Manifest protocol_handlers
Published Updated
Per MDN, the protocol_handlers member “specifies an array of objects that are protocols
which this web app can register and handle,” and “protocol handlers register the
application in an OS’s application preferences; the registration associates a specific
application with the given protocol scheme.” MDN’s own illustration: “when using the
protocol handler mailto:// on a web page, registered email applications open.”
Where it is supported
Section titled “Where it is supported”- Legend
- Yes
- Partial
- Flag
- No
- Unknown
| Browser / Platform | Support | Versions | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Android) | No | — | medium | source | 1 |
| Chrome (Desktop) | Yes | 96 | medium | source | — |
| Edge (Desktop) | Yes | 96 | medium | source | — |
| Safari (iOS) | No | — | medium | source | 2 |
| Safari (macOS) | No | — | medium | source | 3 |
| Firefox (Desktop) | No | — | medium | source | 4 |
| Samsung Internet | No | — | medium | source | 5 |
- Desktop-only registration.
- Safari does not implement the `protocol_handlers` manifest member (MDN compatibility table, checked 2026-10-03).
- Safari does not implement the `protocol_handlers` manifest member (MDN compatibility table, checked 2026-10-03).
- Desktop Firefox does not install web apps from the manifest and does not implement `protocol_handlers` (MDN compatibility table, checked 2026-10-03).
- Chromium ships manifest protocol handlers for desktop installs only; Samsung Internet lists no support (MDN compatibility table, checked 2026-10-03).
MDN marks the member experimental. Its browser-compat-data entry for
manifests.webapp.protocol_handlers records support in Chrome 96, with Edge and Opera
listed as mirroring Chrome’s data. Firefox and Safari are recorded with no support, as is
Chrome on Android; the remaining mobile entries (Firefox for Android, Opera Android,
Safari on iOS, Samsung Internet, and the Android and iOS WebViews) are recorded as
mirrors of those same engines.
How to use it
Section titled “How to use it”Each entry pairs a protocol with a url. Per MDN, protocol is “a required string
containing the protocol to be handled; e.g.: mailto, ms-word, web+jngl,” and url
is a “required HTTPS URL within the application scope that will handle the protocol,”
where “the %s token will be replaced by the URL starting with the protocol handler’s
scheme.” MDN adds that “if url is a relative URL, the base URL will be the URL of the
manifest.”
MDN’s example declares that the app “should be registered to handle the protocols
web+jngl and web+jnglstore”:
{ "protocol_handlers": [ { "protocol": "web+jngl", "url": "/lookup?type=%s" }, { "protocol": "web+jnglstore", "url": "/shop?for=%s" } ]}MDN describes what happens next: “after registering a web app as a protocol handler, when
a user clicks on a hyperlink with a specific scheme such as mailto:// or web+music://
from a browser or native app, the registered PWA would open and receive the URL.”
The Manifest Incubations specification splits that into two actors. On installation, “a user agent SHOULD register protocol handlers with the Operating System,” and from then on “clicking on a registered protocol will launch the registered application. If this is the web app, then execute the [invoke a protocol handler] steps defined in [HTML], where the user agent SHOULD navigate to url and the appropriate browsing context is set to a new top level browsing context.” Where several apps claim the same protocol, the spec expects that “the OS allows the user to select which app should open it, and also allows the user to set a default app.”
The spec’s own worked example makes the substitution concrete: for a manifest at
https://example.com/manifest.webmanifest, a web+music handler with
"url": "/play?songId=%s" activated on web+music://#1234 means “the user agent would
instantiate a new top-level browsing context and navigate to
https://example.com/play?songId=web+music://%231234.”
How to detect the substituted URL and fall back
Section titled “How to detect the substituted URL and fall back”Per MDN, %s is replaced with “the URL starting with the protocol handler’s scheme.”
The cited sources do not define the unsubstituted template as a fallback URL, so the route
should accept only the documented substituted shape and use its fallback branch for an
absent or invalid value:
// The route the manifest points at: /lookup?type=%s//// Note the parser. MDN: "The URLSearchParams constructor interprets plus signs// (+) as spaces, which might cause problems." In the spec's worked example the// "+" of "web+music" is literal in the query string, so read the raw value.const encoded = location.search.match(/[?&]type=([^&]*)/)?.[1];let value = null;
try { value = encoded ? decodeURIComponent(encoded) : null;} catch { // An unsubstituted or malformed value is not a handled protocol URL.}
if (value?.startsWith('web+jngl:')) { // The value has the shape MDN documents for a substituted %s. showLookupFor(value.slice('web+jngl:'.length));} else { // Absent, or not a web+jngl URL. Render the normal lookup page with its own // search field instead of parsing a value that isn't there. showLookupForm();}Practical checklist
Section titled “Practical checklist”- Keep the handler
urlinside the app’sscopeand on HTTPS, per MDN. The spec’s processing steps skip any entry whose normalized URL “is not within scope of” the manifest, and also skip entries whereprotocolorurlis undefined. - Do not expect an arbitrary scheme to be accepted. In the spec’s example, the second
handler “would be ignored, as the protocol provided does not start with
web+and is not part of the safelisted schemes.” - Do not register the same URL twice: per the spec’s processing steps, if the processed list already contains the normalized URL, the entry is skipped.
- A permission prompt is not guaranteed, and the presented list may be shortened. Per
the spec, “a user agent SHOULD ask users for permission before registering a protocol
handler description
protocol_handlersas the default handler for a protocol with the host operating system,” and it “MAY truncate the list … in order to remain consistent with the conventions or limitations of the host operating system.” - Treat registration as operating-system dependent, and not only an install-time act. Per MDN, “registering applications to handle URL schemes is operating-system dependent. This association is usually done during application install but it can also be done afterwards from an app that has already been installed.”
- Parse the whole URL, not a payload.
%sis replaced “by the URL starting with the protocol handler’s scheme” (MDN) — in the spec’s example the query value is the entireweb+music://#1234, with the fragment marker written as%23. - Be aware the registration can become a default silently. The spec’s privacy note warns that “depending on the operating system capabilities, the protocol handler could become a ‘default’ handler … of a given protocol without the explicit knowledge of the user,” and lists the protections a user agent may employ, including removing the registration.
Where to go next
Section titled “Where to go next”- Manifest protocol_handlers: registering a PWA for custom URL schemes — the capability-side entry, including the older imperative registration API.
- Manifest Protocol Handlers support — the compatibility dataset for this member.
- Manifest scope — the member that bounds which handler URLs the spec will accept.