Skip to content

Installation · Concept

App shortcuts after install

Published

App shortcuts are the entries of the manifest shortcuts member that the operating system lists when the user right-clicks or long-presses an installed web app’s icon; because the menu belongs to the icon, no shortcut exists until the app is installed. Chrome 85 on Android, Chrome and Edge 96 on desktop, Samsung Internet 14, and Safari 17.4 on macOS read the member; Safari on iOS and Firefox ignore it (BCD html.manifest.shortcuts).

At install time the browser copies shortcuts into the platform’s own shortcut mechanism: a Windows jump list (right-click the taskbar or Start icon), the macOS Dock icon’s context menu, the ChromeOS shelf menu, or Android’s launcher shortcuts (long-press the home-screen or drawer icon). The entries are static copies, so a changed manifest reaches the menu only after the browser’s next manifest update check, not on the next page load.

Each shortcut object carries name (required), url (required), and optional short_name, description, and icons. The url is resolved against the manifest’s own URL, not against the page or start_url: a manifest at /dashboard/manifest.json with "url": "../projects" opens /projects. The resolved URL must lie within the manifest scope; an out-of-scope entry is dropped by the browser rather than reported. The specification caps nothing, but Windows jump lists and Android launchers show only the first few entries, so the most used actions belong at the top of the array.

Nothing about a shortcut is special once it opens: the app receives an ordinary navigation to the shortcut’s URL in its standalone window. A shortcut therefore costs nothing where the member is unsupported (the same URLs still work as links inside the app), and gains a launcher-level entry point where it is.

The manifest excerpt declares two shortcuts; the script shows how the app learns which one launched it and what happens where the member is unsupported.

Declaring shortcuts that resolve inside the app’s scope

Section titled “Declaring shortcuts that resolve inside the app’s scope”

The manifest lives at /app/manifest.webmanifest, so the relative URLs resolve under /app/. Each entry carries a ?source=shortcut query so the app can attribute the launch.

{
"name": "Calendar",
"start_url": "/app/",
"scope": "/app/",
"display": "standalone",
"shortcuts": [
{
"name": "New event",
"short_name": "New",
"description": "Create an event starting now",
"url": "new-event?source=shortcut",
"icons": [{ "src": "icons/new-event-96.png", "sizes": "96x96", "type": "image/png" }]
},
{
"name": "Today",
"url": "today?source=shortcut",
"icons": [{ "src": "icons/today-96.png", "sizes": "96x96", "type": "image/png" }]
}
]
}

Writing "url": "/new-event" instead would resolve outside /app/ and the browser would silently drop that shortcut; keeping the icons at 96×96 px matches the size Chrome documents for shortcut icons on Android.

Telling which shortcut launched the app, with a fallback for browsers without shortcuts

Section titled “Telling which shortcut launched the app, with a fallback for browsers without shortcuts”

The app reads location.pathname and the source query on startup. Where shortcuts is unsupported (Safari on iOS, Firefox), the same URLs are still reachable as in-app links, so the app exposes them in its own menu instead.

const url = new URL(location.href);
const fromShortcut = url.searchParams.get('source') === 'shortcut';
if (fromShortcut && url.pathname.endsWith('/new-event')) {
openEventEditor({ startsAt: Date.now() });
analytics.track('launch_shortcut', { shortcut: 'new-event' });
}
// Fallback: no launcher menu exists on iOS Safari or Firefox, so surface the same
// actions inside the app. `display-mode` tells whether the app runs installed at all.
const installed = matchMedia('(display-mode: standalone)').matches || navigator.standalone === true;
if (!installed || /iPhone|iPad|Firefox/.test(navigator.userAgent)) {
renderQuickActions([
{ label: 'New event', href: '/app/new-event?source=menu' },
{ label: 'Today', href: '/app/today?source=menu' },
]);
}

The source query is the only reliable attribution: the referrer is empty for a launcher-initiated navigation, and document.referrer cannot distinguish a shortcut from a typed URL.

Specifications

SpecificationStatus
None.