Skip to content

Progressive web app

Citizen generates a web app manifest for your wiki, so readers can install it and open it like any other app on their device — its own window, its own icon, no browser chrome around it.

If progressive web apps are new to you, web.dev and MDN both have a good overview. This page only covers what Citizen does.

How it works

When the manifest is enabled, Citizen adds <link rel="manifest"> to every page, pointing at api.php?action=appmanifest. That endpoint builds the manifest from your wiki's settings:

Manifest memberWhere it comes from
name$wgSitename
short_name, descriptionManifest options — left out when unset
iconsManifest options, or $wgLogos when you set none
screenshotsManifest options — left out when unset
shortcutsManifest options, or Citizen's defaults
theme_color, background_colorManifest options
start_urlYour wiki's main page
scopeYour whole server, so index.php URLs stay inside the app
lang, dirYour wiki's content language
display, orientationAlways standalone and natural

Citizen also sets a <meta name="theme-color"> tag from $wgCitizenThemeColor. That one tints browser UI during an ordinary visit, and is separate from the manifest's theme_color, which applies to the installed app.

Private wikis get no manifest

The manifest link is only added when anonymous users can read your wiki. If $wgGroupPermissions['*']['read'] is off, nothing is linked and nothing is installable, no matter how the options below are set.

Changes take a while to appear

The manifest is served with a one-week cache, so a browser that has already fetched it keeps its copy for up to a week. When testing a change, use a fresh private window, or reload the manifest from your browser's developer tools (in Chrome: Application ▸ Manifest).

Making your wiki installable

Browsers decide for themselves when to offer an install — web.dev's install criteria covers what they look for.

The part worth setting up here is icons. Left alone, the manifest carries whatever your $wgLogos happen to be; giving it PNGs of its own is more predictable:

LocalSettings.php
php
$wgCitizenManifestOptions['icons'] = [
    [ 'src' => '/images/icon-192.png', 'sizes' => '192x192', 'type' => 'image/png' ],
    [ 'src' => '/images/icon-512.png', 'sizes' => '512x512', 'type' => 'image/png' ],
];

A 192×192 and a 512×512 PNG is the usual pair to start from. Adding 'purpose' => 'maskable' on a version with padding around the artwork gives platforms that crop icons to their own shape something safe to crop.

The richer install dialog

Instead of a bare "Install?" prompt, browsers can show a fuller dialog with your wiki's name, its description, and a carousel of screenshots. Citizen supports this — it needs screenshots, and a description is worth setting alongside them.

Configuration

$wgCitizenEnableManifest

Whether to generate the manifest at all. On by default.

LocalSettings.php
php
$wgCitizenEnableManifest = true;

Manifest options

Everything else lives in $wgCitizenManifestOptions.

View default configuration
php
$wgCitizenManifestOptions = [
    'background_color' => '#0d0e12',
    'description' => '',
    'short_name' => '',
    'theme_color' => '#0d0e12',
    'icons' => [],
];

description

The sentence browsers show under your wiki's name in the install dialog. Keep it to a couple of lines — a long one gets truncated.

LocalSettings.php
php
$wgCitizenManifestOptions['description'] = 'The community encyclopedia of everything.';

short_name

The name used where the full one does not fit, such as under a home screen icon. Falls back to $wgSitename.

LocalSettings.php
php
$wgCitizenManifestOptions['short_name'] = 'My wiki';

Both are empty by default, and an empty value is left out of the manifest entirely rather than shipped blank.

icons

The icons the installed app is represented by, as defined by the manifest icons member. Each entry may set src, sizes, type, and purpose; any other key is dropped.

LocalSettings.php
php
$wgCitizenManifestOptions['icons'] = [
    [ 'src' => '/images/icon-192.png', 'sizes' => '192x192', 'type' => 'image/png' ],
    [ 'src' => '/images/icon.svg', 'sizes' => 'any', 'type' => 'image/svg+xml', 'purpose' => 'any maskable' ],
];

Leave the list empty to derive the icons from $wgLogos instead — Citizen reads each logo's dimensions and MIME type off the file itself, and skips any it cannot measure. Setting the list yourself is the more predictable route, since your logos were chosen for the wiki's header rather than for an app icon.

shortcuts

The shortcuts a long press or right click on the installed app offers, as defined by the manifest shortcuts member. Each entry may set name, short_name, description, url, and icons; any other key is dropped. name and url are both required — the spec says so, and Citizen drops entries missing either rather than shipping them incomplete.

LocalSettings.php
php
$wgCitizenManifestOptions['shortcuts'] = [
    [ 'name' => 'Search', 'url' => '/wiki/Special:Search' ],
    [
        'name' => 'Guides',
        'short_name' => 'Guides',
        'description' => 'Community guides',
        'url' => '/wiki/Project:Guides',
        'icons' => [
            [ 'src' => '/images/guides.png', 'sizes' => '96x96' ],
        ],
    ],
];

Leave the option unset to get Citizen's defaults — Search, Random, and Recent changes, each resolved against your wiki's own article path. Set it to [] to ship no shortcuts at all.

screenshots

Pictures of your wiki that browsers show in the install dialog, as defined by the manifest screenshots member. Each entry may set src, sizes, type, form_factor, label, and platform; any other key is dropped. src is required — entries without one are dropped.

LocalSettings.php
php
$wgCitizenManifestOptions['screenshots'] = [
    [
        'src' => '/images/screenshot-desktop.png',
        'sizes' => '1920x1080',
        'type' => 'image/png',
        'form_factor' => 'wide',
        'label' => 'An article on desktop',
    ],
    [
        'src' => '/images/screenshot-mobile.png',
        'sizes' => '750x1334',
        'type' => 'image/png',
        'form_factor' => 'narrow',
        'label' => 'An article on mobile',
    ],
];

Citizen ships no screenshots by default, because they have to be pictures of your wiki. Leave the option unset and the manifest leaves the member out.

Set form_factor on every entry, and supply at least one of each value — an entry that leaves it out can end up shown in one place and never the other.

Service worker

When your wiki is served from the root of its domain rather than a subdirectory, Citizen registers a service worker on every page load — this has nothing to do with whether a reader has installed the app. It is a placeholder: it does no caching and adds no offline support, so it is safe to ignore if you spot it in your browser's developer tools. Wikis served from a subdirectory skip it entirely.