Build my web app

App shortcuts and share targets: two manifest features that make a web app feel installed

Long-press shortcuts that jump straight to "New order" or "My bookings", and a share target that puts your web app in Android's share sheet, including the service worker code that receives shared files.

Once your web app is installed, two small additions to the manifest change how it feels. Shortcuts appear when someone long-presses your icon and take them straight to a task. A share target puts your app in the system share sheet, so a photo, a link or a piece of text can be sent to it from any other app. Neither needs a framework, and both degrade to nothing where they are not supported.

Where they work

ShortcutsShare target
Chrome and Edge on Android (installed app)Yes, long-press the iconYes, in the share sheet
Chrome and Edge on Windows, ChromeOSYes, right-click the taskbar or shelf iconChromeOS yes; Windows no
Safari on iPhone and iPadNoNo
Not installed (a browser tab)NoNo

Both only exist for an installed app, and both are read from the manifest at install time and when the browser refreshes it (Chrome checks for manifest changes about once a day when the app is opened). After editing, reinstall to see the change straight away.

Shortcuts

{
  "shortcuts": [
    {
      "name": "New order",
      "short_name": "Order",
      "description": "Start a new order",
      "url": "/order/new?source=shortcut",
      "icons": [{ "src": "/icons/order-96.png", "sizes": "96x96", "type": "image/png" }]
    },
    {
      "name": "My bookings",
      "url": "/bookings?source=shortcut",
      "icons": [{ "src": "/icons/bookings-96.png", "sizes": "96x96", "type": "image/png" }]
    }
  ]
}

A share target for text and links

The simplest share target receives a title, text and URL as query parameters on a page you already have:

{
  "share_target": {
    "action": "/share",
    "method": "GET",
    "params": { "title": "title", "text": "text", "url": "url" }
  }
}

Sharing a link from another app now opens /share?title=…&text=…&url=… in your installed app. Read the values with new URLSearchParams(location.search). Note that many Android apps put the link in text rather than url, so check both.

A share target for files

Files need POST and multipart/form-data:

{
  "share_target": {
    "action": "/share-file",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "title": "title",
      "text": "text",
      "files": [{ "name": "media", "accept": ["image/*", "application/pdf"] }]
    }
  }
}

A static site cannot receive a POST, and it does not need to: the service worker intercepts it before it reaches the network.

// sw.js
self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url);
  if (event.request.method !== 'POST' || url.pathname !== '/share-file') return;

  event.respondWith((async () => {
    const form = await event.request.formData();
    const files = form.getAll('media');
    const cache = await caches.open('shared-files');
    await Promise.all(files.map((file, i) =>
      cache.put('/shared/' + i, new Response(file, { headers: { 'Content-Type': file.type } }))));
    // 303: the browser follows with a GET, so a reload does not re-send the share
    return Response.redirect('/received?count=' + files.length, 303);
  })());
});

The /received page then reads /shared/0, /shared/1… from the cache, shows them, and deletes them when done. Keep the accept list honest: if you accept image/*, your page must cope with a 20 MB camera photo and a HEIC file.

Testing

  1. In Chrome DevTools open Application → Manifest. It lists your shortcuts and share target and flags errors (a URL outside the scope, a missing icon).
  2. Install the app on an Android phone, long-press the icon, and try each shortcut.
  3. Share a link and an image from the Photos app. If your app is missing from the share sheet, the app is not installed or the manifest has not been refreshed yet: uninstall and install again.
  4. For the file target, open chrome://inspect on a desktop with the phone connected by USB to watch the service worker receive the POST.

When you need more than the manifest offers

Shortcuts are fixed at install time, and share targets do not exist on iPhone. If you need shortcuts that change per user, or sharing that also works when the app is wrapped for Google Play, the Android packaging route covers both: a packaged app can register dynamic shortcuts and appear in the share sheet for chosen file types.