Skip to content

Instantly share code, notes, and snippets.

Last active September 22, 2017 01:39
Show Gist options
  • Save kenchris/0acec2790cd38dfdff0a7197ff00d1de to your computer and use it in GitHub Desktop.
Save kenchris/0acec2790cd38dfdff0a7197ff00d1de to your computer and use it in GitHub Desktop.

Shortcuts API Specification

This explainer is for the Shortcut API


Some platforms like Windows and Android have ways to add menu items to the app launcher icon itself, here after called shortcuts. These can perform certain app actions. On Android in addition, you can drag these shortcuts to the homescreen.

The shortcut list (aka menu) contains a mixture of static and dynamic shortcuts and has a limit which may be different per platform or per launcher used. The amount of shortcuts on the homescreen is not limited so though the shortcut list may change overtime, existing shortcuts on the homescreen can still be updated (say change icon) though not removed.


The shortcuts are quite useful as /shortcuts/ to common actions, like starting a chat with the person you chat with the most, or say launch the web app to a specific place inside the app (deep link).

These are becoming quite popular, like for instance in GMaps you can add a shortcut to your contributions page.

API proposal

The ShortcutInfo dictionary is reusing name, short_name and icons from the manifest specification and can itself be embedded in the manifest.json inside the shortcuts member which takes an array of ShortcutInfo.

dictionary ShortcutInfo {
  DOMString id;
  DOMString name;
  DOMString short_name;
  sequence icons;
  dictionary data;

partial interface Navigator {
    readonly attribute int maxVisibleShortcuts;
    sequence<ShortcutInfo> getManifestShortcuts();
    sequence<ShortcutInfo> getDynamicShortcuts();
    Promise addShortcut(ShortcutInfo);
    Promise removeShortcut(ShortcutInfo);
    Promise setShortcut(ShortcutInfo); 
    Promise requestPinShortcut(ShortcutInfo);

[Constructor(DOMString type, optional ShortcutEventInit eventInitDict), Exposed=ServiceWorker]
Interface ShortcutEvent : ExtendableEvent {
  readonly attribute DOMString id;
  readonly attribute any data;


Static shortcuts inside a link manifest file

  "name": "Cool Email",
  "start_url": "",


  "shortcuts": [{
     "name": "Email Mom",
     "id": "send-email",
     "data": { "email": "" },
     "icons": [{
        "src": "icon/hd_hi.svg",
        "sizes": "any"

Responding to a shortcut activation

Similarly to the Push API, when shortcuts are clicked, the shortcutclick event is fired in the Service Worker.

At that point you have access to the id and data of the shortcut and can easily access any existing open window for the PWA or open the app using openWindow. postMessage can be used to talk to the open instance.

This is quite flexible. Using a Service Worker, the app can load URLs, execute JavaScript and communicate with a running instance of the PWA, even without giving it focus.

self.addEventListener('shortcutclick', function(event) {
  console.log('[Service Worker] Shortcut click Received.');

  if ( != "send-email) {

  async function getWindow() {
    const client = await clients.matchAll(options).then(function(clientList) {
      if (clients.length > 0) {
        return clients[0];
      return clients.openWindow(''); 

    client.postMessage({ action:, data: });
    await client.focus();


Manually add a /dynamic/ shortcut

  name: "Email Mom",
  id: "send-email",
  data: { email: "" },
  icons: [{
    src: "icon/hd_hi.svg",
    sizes: "any"
}).then(info => {
  console.log(`Added ${info.title} shortcut`); 


As it is quite a common case to just load different URLs (deep links into the app), it makes sense to add start_url to the ShortcutInfo. Questions is how to handle that. Without Service Worker it could just load the URL direclty.

  • Should shortcutclick be dispatched when a start_url is available as the URL might already be part of fetch event if in scope?

Relevant links

Copy link

kenchris commented Aug 9, 2017

@mgiuca Static are the ones that are described in the manifest and only gets updated when the manifest is updated. That is how it works for Android apps as well - these can not be tampered with at runtime.


  1. I added a few more links to how something similar works on iOS - I will have to look at that more.

  2. Static will only work when added to the home screen (and we might make that a requirement for dynamic as well) as there needs to be an icon to long press on to show the list (which can then be dragged to the homescreen for a regular shortcut). I do think it makes sense to always require the app to be added to the homescreen so that links can lunch /within/ the app, respecting the display-mode etc.

  3. On Android you can remove shortcuts from the long press menu (only dynamic ones, static ones needs an app update) - shortcuts on the homescreen itself cannot be removed, but you can intercept their urls and show an error page, like for -> "This hangout chat group no longer exists"

You are probably right, these can probably be just URLs, but we need the id as part of the payload so that we can update the long press menu list etc.

Copy link

mgiuca commented Sep 22, 2017

I've written up a counter-proposal here. The major points are:

  1. URL-based, not event based, as discussed above.
  2. Focus on static first (much less complexity), and punt dynamic shortcuts to later.

The second point means it can be entirely done in the manifest spec, not introducing any new JavaScript APIs (which at least the two of us are most comfortable working with, spec-wise).

If anyone else wants to comment on that, please do so, then I think the next steps are perhaps just drafting a CL for the Manifest spec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment