Progressive web apps and Send-to-me
Abstract
A Progressive Web App (PWA) is a web application packaged with a manifest and a service worker, so that a supported browser can install it to the device's home screen and treat it as if it were a native application. Send-to-me is built as a PWA for a single load-bearing reason: it is the only way to register as a share target in Android's system share sheet from a web codebase. The Web Share Target API requires the app to be an installed PWA.
This document explains what a PWA is, how Send-to-me uses one, what is gained and what is lost compared with native applications, and the platform constraints that shape the MVP scope.
What is a PWA?
A PWA is built from the same primitives as any web page (HTML, CSS, JavaScript) plus two additional pieces:
- A web app manifest (
manifest.json). A small JSON file declaring the app's name, icons, theme colour, display mode, start URL, and (optionally) integration points such as share targets and protocol handlers. The manifest is what makes the browser offer "Install" or "Add to Home Screen". - A service worker (
sw.js). A script the browser registers to run in the background, separately from any open tab. The service worker intercepts network requests for the site (viafetchevents), responds to lifecycle events (install,activate), and is the mechanism that makes installable web apps possible.
Once installed, a PWA launches from the home screen, runs in a window without browser chrome (depending on display mode), and behaves like an application bookmark with extra capabilities. The underlying code is still served from the web origin; nothing is "compiled to native".
The PWA model is open and standards-based. There is no PWA platform vendor; the capabilities are whatever the user's browser implements from the relevant W3C and WHATWG specifications.
How Send-to-me uses a PWA
Send-to-me's PWA exists specifically so Android can include it in the system share sheet. That capability comes from the Web Share Target API, which works only when the app is installed as a PWA.
The app manifest declares the share-target intent:
"share_target": {
"action": "/share",
"method": "POST",
"enctype": "application/x-www-form-urlencoded",
"params": { "title": "title", "text": "text", "url": "url" }
}
When the user shares something to Send-to-me, Android POSTs a form-encoded body to /share. Send-to-me's service worker intercepts that POST, reads the form fields, and redirects to /share?url=...&title=...&text=... so the page can preview the content and let the user confirm (or auto-send, if that setting is enabled).
This is the entire reason Send-to-me is a PWA. The quick-note form would work just as well as a plain web page; the share entry point would not.
Installation
On Chrome for Android, the browser displays an "Install" prompt or "Add to Home Screen" option once it has seen an installable manifest and registered service worker. The user accepts, and the app icon appears on the home screen. Once installed, Send-to-me appears in the system share sheet for compatible content (links, text).
On iOS Safari, "Add to Home Screen" does install the page as a home-screen icon, but it does not register share-target intents. The Web Share Target API specifically remains unsupported on iOS, even after Apple's restoration of broader PWA Home Screen support in the EU under the Digital Markets Act. See "Limitations" below.
Lifecycle and updates
The service worker is the unit of cacheable code on a PWA, and its update model is what governs how quickly changes reach an installed app.
Browsers check for an updated service worker on navigation. By default they will check at most every 24 hours per origin. When a new service worker is found, it installs and waits to activate; activation typically happens on the next page load when no tabs are using the old worker.
To keep updates landing promptly, Send-to-me sets Cache-Control: no-cache on the PWA shell (the root, the service worker, and any HTML page). The browser still keeps a local copy of these but revalidates with the server on every navigation; if the server's copy hasn't changed, a fast 304 is returned, and if it has, the new copy lands on the next reload. Auth-sensitive responses (the API and auth endpoints) are no-store, and other static assets (CSS, JS, images, manifest) use default cacheability.
When the service worker changes meaningfully, its CACHE_NAME constant bumps. The activate event then clears the previous cache, so the asset set stays consistent with the service worker that owns it.
What a PWA gains over a plain web page
- Home-screen presence. The app launches like any other.
- Share-sheet integration on Android. Load-bearing for Send-to-me's share entry point.
- Offline tolerance. A service worker can serve cached assets when the network is gone, surfacing a sensible error rather than a browser failure page.
- Window chrome control.
display: standaloneremoves the URL bar and gives the impression of a native app surface. - Lifecycle hooks. Background events such as fetch interception and push messaging (where the user grants permission) are available without a backing native binary.
What a PWA does not gain (compared to native)
- iOS share sheet integration. The Web Share Target API is not implemented on iOS, irrespective of whether the PWA is installed.
- Long-running background work. Service workers can do bounded work in response to events but are not a substitute for native background services.
- App-store distribution. PWAs are installed from the web origin; they do not appear in Google Play or the App Store unless wrapped in a native shell.
- Access to platform APIs unavailable on the web. A PWA can do what the web platform exposes, and not what it does not. This is sometimes a clean line and sometimes a frustrating one.
Platform constraints for Send-to-me
The MVP is therefore Android-only for the share flow. The quick-note form (typing into a text area and submitting) works on any platform with a browser. The asymmetry is in the share entry point, not the core capability.
If iOS share support becomes worth the operational cost, it would mean shipping a native iOS application that uses a Share Extension and the existing backend API. The API contract is intentionally clean enough to support this without redesign.
Security characteristics
PWAs are served over HTTPS only. Service workers will not register on plain HTTP origins (with the single exception of localhost for development). Send-to-me serves HTTPS exclusively, which is required both for service-worker registration and for the strict Content Security Policy the app applies.
The service worker has the same origin as the page, runs in the browser's sandbox, and has no special privileges beyond those exposed by the web platform. It cannot read other origins' data, access the file system, or persist state without going through standard browser APIs (Cache Storage, IndexedDB, etc.).
Further reading
- Web Share Target API: developer.chrome.com/docs/capabilities/web-apis/web-share-target
- MDN, Progressive web apps: developer.mozilla.org/en-US/docs/Web/Progressive_web_apps
- MDN, Service Worker API: developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
- MDN, Web app manifest: developer.mozilla.org/en-US/docs/Web/Manifest