This specification defines Web Install, a user-mediated capability that
lets a website ask the user agent to install a web application. It
defines two entry points: the {{Navigator/install()}} method and the
HTML <install>
element. Both entry points resolve a target
application manifest,
validate the target application, obtain
user consent, and invoke the same installation processing model.
This document is an incubation draft. It intentionally records open interoperability, privacy, and specification-ownership questions inline. Those issues are part of the draft and do not indicate implementer consensus.
User agents can install web applications, but websites do not have a consistent way to offer that action. Existing installation affordances vary by user agent and platform, and script-driven installation mechanisms are generally limited to the application associated with the current document.
Web Install provides a common operation with two complementary entry points:
<install> is a
declarative, user-agent-rendered control that gives
the user agent a stronger signal of the user's intent.
Either entry point can target the web application associated with the current document, or a web application identified by the URL of its manifest. A user agent always remains responsible for presenting trustworthy confirmation UI and for deciding how installation maps to the host platform.
A site can offer installation of the web application associated with its current document:
await navigator.install();
<install>
<a href="/install-help">How to install this app</a>
</install>
A catalog can offer installation of an application identified by its manifest URL:
await navigator.install({
manifest: "https://music.example/manifest.webmanifest",
manifestId: "https://music.example/app"
});
<install
manifest="https://music.example/manifest.webmanifest"
manifestid="https://music.example/app">
<a href="https://music.example/">Open Music Example</a>
</install>
This specification extends [[!HTML]] with {{Navigator/install()}} and
the <install>
element. It reuses manifest concepts and processing from
[[!appmanifest]], permission concepts from [[!permissions]], policy
control from [[!permissions-policy]], content restrictions from
[[!CSP3]], and request processing from [[!FETCH]]. Explicit-manifest
retrieval is also subject to [[!LOCAL-NETWORK-ACCESS]].
The <install>
element provisionally reuses
activation blockers and their rendering protections from
[[!CAPABILITY-ELEMENTS]].
Activation-blocker processing ownership is unsettled.
This specification defines the {{HTMLInstallElement}} members directly
but reuses the internal state and processing currently defined for
ActivationBlockersMixin in the
Geolocation Element draft.
PEPC's Permission Elements draft separately defines InPagePermissionMixin
which exposes the same activation-blocker-facing members. Reconciling these
overlapping abstractions should be done at the PEPC level.
[[MANIFEST-INCUBATIONS]] is an informative dependency at present. If this specification later reuses an incubating manifest member or algorithm, that dependency must be made normative at the exact point of use.
A user agent that does not support web application installation on a particular platform or profile is not required to expose these entry points. Platform support is implementation status, not a desktop-specific conformance requirement. If an entry point is exposed, its observable behavior MUST conform to this specification.
An initiating document is the {{Document}}
whose {{Navigator}} or
<install> element
initiated a Web Install request.
An entry-point kind is either
imperative,
for a request initiated by {{Navigator/install()}}, or
declarative,
for a request initiated by the
<install> element's
[=EventTarget/activation behavior=].
A application source is either current document or explicit manifest.
A manifest ID assertion is an optional URL supplied by the caller representing the expected processed manifest id.
A web install request is a struct with the following [=struct/items=]:
A web install candidate is a struct with the following [=struct/items=]:
A web install outcome is one of:
The outcome vocabulary is shared by both entry points. Each entry point maps an outcome to its corresponding public result.
Every [=top-level traversable=] has an active web install request, which is null or a [=web install request=] and is initially null.
The public outcome taxonomy remains unresolved. Current proposal text and Chromium expose success, invalid data, and a broad aborted result. Developer feedback asks for user cancellation to be distinguishable from internal failure, while privacy review prefers exposing less cross-origin information. The algorithms below provisionally retain the coarse current behavior and mark the entry-point mappings explicitly.
To determine whether a {{Document}} document is an eligible initiating document, run the following steps:
web-app-installation [=policy-controlled feature=]
is disabled in document, return false.
To resolve a web install candidate from the current document for a [=web install request=] request, run the following steps:
id member, return [=invalid install data=].
Manifest readiness is underspecified. The no-argument API can be activated before the document's linked manifest finishes loading. Chromium reads the current document's processed manifest without waiting for a service worker. The final algorithm must define whether it waits for an in-flight manifest, fails immediately, or reuses the installation-prompt discovery processing currently incubated in [[MANIFEST-INCUBATIONS]].
To resolve a web install candidate from an explicit manifest for a [=web install request=] request, run the following steps:
id member, return [=invalid install data=].
To fetch an install manifest from a URL manifestURL, run the following steps:
GET.
manifest-src directive of the Content Security
Policy applicable to the [=initiating document=].
Content-Type metadata is not a
JSON MIME type, return
failure.
Exact Fetch integration remains unresolved. The steps above describe the intended network and exposure behavior directly. Chromium implements them using an internal browser-process request. This draft does not yet define the request destination, or response tainting model. These details require coordination with Fetch before advancement.
A user agent MAY impose implementation-defined response-size, retry, cache, and resource limits. Such limits MUST NOT expose installed state or private-browsing state.
If the user agent fetches icons or other target resources before the user accepts installation, those requests MUST omit credentials and caller-specific authentication state. Their referrer, cache behavior, and cross-origin requirements need the same integration review as the manifest retrieval.
To process install manifest bytes given a byte sequence bodyBytes and URL manifestURL, run the following steps:
This is an explicit Web App Manifest integration. Chromium passes the manifest URL as both the document URL and manifest URL so relative members resolve against the manifest. Web App Manifest permits processing without a client but recommends evidence that a document was historically associated with the manifest. Direct installation deliberately has no loaded target document. WebApps WG should decide whether this call is a supported parameterization or a monkeypatch requiring a new processing entry point.
Source-member presence must survive processing.
Both application sources need to distinguish an explicitly declared
id or start_url from Web App Manifest's
computed defaults. The current processed-manifest model does not
clearly export those presence bits. This specification needs either
an enriched processing result or an explicit pre-processing step that
records them.
To validate a web install candidate given a [=web install request=] request and [=web install candidate=] candidate, run the following steps:
start_url member, return [=invalid install data=].
any, return [=invalid install data=].
Installation eligibility differs between current paths.
Chromium's current-document path requires a suitable
any icon and ignores display mode, while its explicit
manifest path initially checks only for a non-empty icon list before
downloading icons. The common requirements above are provisional and
need alignment with Web App Manifest's deliberately broad definition
of an installable web application.
Related-application support is deferred.
This specification currently targets the requested web application
and does not define an installation handoff based on
related_applications. Such handling is a desired future
enhancement, outside the initial shipping scope. Its design should
be coordinated with Web App Manifest and assess compatibility for
existing manifests, particularly if it would replace or prevent the
requested web-app installation.
This specification does not require a service worker, offline capability, or a particular display mode. A user agent MAY use those signals when deciding how to present or integrate an application, but it MUST NOT report their absence as [=invalid install data=] unless a future version of this specification makes them requirements.
web-app-installation powerful feature
This specification defines a [=powerful feature=] identified by the
permission name
web-app-installation permission.
Its [=permission state=] is associated with the [=initiating
document=]'s [=origin=].
This specification also defines a [=policy-controlled feature=] named
web-app-installation
policy-controlled feature with a default allowlist of
self.
To obtain web install permission for a [=web install request=] request, run the following steps:
web-app-installation.
To confirm web installation given a [=web install request=] request and [=web install candidate=] candidate, the user agent MUST present user-controlled UI that:
The exact layout, wording, platform integration, and number of UI surfaces are user-agent-defined.
Return true if the user accepts the operation. Otherwise, return false.
To perform a Web Install action given a [=web install request=] request and [=web install candidate=] candidate, run the following steps:
A user agent MAY launch the application after installation and MAY integrate it with host-platform surfaces. Such behavior does not change the target application's origin, permissions, or storage partition.
<install> element
The HTML
<install> element
represents a user-agent-rendered control that lets the user initiate a
Web Install request.
manifest.
manifestid.
oninstallresult.onvalidationstatuschange.
[Exposed=Window]
interface HTMLInstallElement : HTMLElement {
[HTMLConstructor] constructor();
[CEReactions, ReflectURL] attribute USVString manifest;
[CEReactions, ReflectURL] attribute USVString manifestId;
readonly attribute boolean isValid;
readonly attribute DOMString invalidReason;
attribute EventHandler onvalidationstatuschange;
};
partial interface mixin GlobalEventHandlers {
attribute EventHandler oninstallresult;
};
enum InstallResult {
"success",
"aborted",
"invalid-data"
};
[Exposed=Window]
interface InstallResultEvent : Event {
constructor(DOMString type,
optional InstallResultEventInit eventInitDict = {});
readonly attribute InstallResult result;
};
dictionary InstallResultEventInit : EventInit {
InstallResult result = "aborted";
};
The child nodes of an
<install> element are
fallback content.
While the native control is rendered, those nodes are not rendered,
focusable, or exposed in the accessibility tree. A user agent that does
not support the element renders the children according to ordinary HTML
rules.
The <install>
element is not form-associated. It does not define a
disabled content attribute; activation blockers represent
whether the native control can currently be activated.
The {{HTMLInstallElement/isValid}}, {{HTMLInstallElement/invalidReason}}, and {{HTMLInstallElement/onvalidationstatuschange}} members use the activation-blocker processing defined by [[CAPABILITY-ELEMENTS]]. Their direct WebIDL declarations above do not redefine that processing.
To determine an
<install>
element's context blocker reason, run the following steps:
illegal_subframe.
web-app-installation
[=policy-controlled feature=] is disabled in
document, return illegal_subframe.
illegal_sandbox.
illegal_subframe.
If the element's [=context blocker reason=] is not the empty string, the element is blocked, {{HTMLInstallElement/isValid}} is false, and {{HTMLInstallElement/invalidReason}} is that reason.
The shared blocker reason set does not yet include
illegal_sandbox.
[[CAPABILITY-ELEMENTS]] defines illegal_subframe, but
does not include illegal_sandbox in
ActivationBlockersMixinBlockerReason or its blocker
reason table. This specification provisionally defines
illegal_sandbox and the context ordering above for
<install>. This
does not otherwise redefine the mixin's blocker processing or the
ordering among blocker reasons defined by [[CAPABILITY-ELEMENTS]].
{{HTMLInstallElement}} uses the internal state defined by
ActivationBlockersMixin. It does not store a persistent
installation result; each result belongs to one
{{InstallResultEvent}}.
The {{HTMLInstallElement/constructor()}} steps are:
The {{HTMLInstallElement}} insertion steps are:
The {{HTMLInstallElement}} removing steps are:
The default value of the
tabindex content attribute for
<install> is 0.
The manifest
content attribute gives the URL of the target application manifest.
The {{HTMLInstallElement/manifest}} IDL attribute
reflects the
manifest content attribute as a
URL.
The manifestid
content attribute gives an optional [=manifest ID
assertion=]. Relative values are resolved against the element's
[=Node/node document=]'s
document base URL. The {{HTMLInstallElement/manifestId}} IDL
attribute
reflects the
manifestid content attribute as
a URL.
Omitting both attributes selects [=current document=] as the
[=application source=]. Supplying
manifestid without
manifest is invalid install data.
The <install>
element uses
ActivationBlockersMixin's initialization, insertion,
removing, visibility, occlusion, and style-validation processing.
A supporting user agent MUST render a user-agent-controlled control whose accessible purpose is installation. The user agent controls the control's text and iconography and MUST ensure the control remains distinguishable, legible, focusable, and activatable using keyboard and platform accessibility input.
The user agent controls the native control's appearance, subject to the requirements in Privacy considerations that prevent the initiating document from detecting the target application's installed state.
A user agent MAY apply anti-clickjacking and anti-spam limits in addition to the capability-element requirements. Numeric cooldowns, per-page control limits, and reputation checks are user-agent policy and are not interoperable state exposed by this specification.
The <install>
element's [=EventTarget/activation behavior=] given an {{Event}}
event is:
manifestid attribute but no
manifest attribute,
[=queue an install result=] of invalid-data at
[=this=] and return.
manifest attribute:
manifest attribute's value.
invalid-data at
[=this=] and return.
invalid-data at
[=this=] and return.
manifestid attribute:
manifestid attribute's
value.
invalid-data at [=this=] and return.
invalid-data at [=this=] and return.
success at
[=this=] and abort these substeps.
invalid-data at
[=this=] and abort these substeps.
aborted at
[=this=].
Returning before a [=web install request=] is created because the
activation is untrusted, the element is blocked, or the document is
ineligible does not queue an installresult event.
Blocker state is exposed through
{{HTMLInstallElement/isValid}},
{{HTMLInstallElement/invalidReason}}, and
{{HTMLInstallElement/onvalidationstatuschange}}.
The values used by an in-flight request are snapshotted during
activation. Later mutations to
manifest or
manifestid affect only later
activations.
installresult event| Value | Meaning |
|---|---|
success |
Installation completed, or processing of a user-approved action for an existing application completed. |
invalid-data |
The manifest URL, manifest contents, identity assertion, or required installation metadata was invalid or unavailable. |
aborted |
The operation did not complete for a non-data reason. |
An {{InstallResultEvent}} has a [[\result]] internal slot. Its constructor initializes {{InstallResultEvent/[[result]]}} to the value of {{InstallResultEventInit/result}} in eventInitDict.
To queue an install result of {{InstallResult}} result at an {{HTMLInstallElement}} element, [=queue an element task=] on the [=user interaction task source=] with element to run these steps:
installresult,
{{InstallResultEvent/result}} is result,
{{Event/bubbles}} is true, {{Event/cancelable}} is false, and
{{Event/composed}} is false.
The following are the event handlers and their corresponding event handler event types that user agents MUST support:
| Event handler | Event handler event type |
|---|---|
oninstallresult |
installresult |
result attributeThe {{InstallResultEvent/result}} getter returns [=this=].{{InstallResultEvent/[[result]]}}.
This specification supplies the manifest URL as both manifest URL and document URL, and null as client, when it invokes process a manifest for an [=explicit manifest=] [=application source=].
This specification additionally requires an explicitly declared
id when the caller did not supply a
[=manifest ID assertion=], even though Web App Manifest normally
computes a fallback identity.
This specification adds {{Navigator/install()}},
{{HTMLInstallElement}}, the
<install> element,
and the installresult event to HTML.
{{HTMLInstallElement}} reuses the internal state and initialization,
insertion, removal, and activation-validation processing defined for
ActivationBlockersMixin. It does not include the mixin's
WebIDL or observe or expose a capability permission state through
that processing.
This specification registers the
web-app-installation powerful feature and the
same-named policy-controlled feature. The Permissions API descriptor
requires no members beyond {{PermissionDescriptor/name}}.
If an accepted action for an already-installed application launches it, the user agent SHOULD apply the application's launch handling behavior as defined by [[LAUNCH-HANDLER]].
Web Install creates potential cross-origin information channels because an installing origin can name another application's manifest. User agents MUST NOT expose the target application's installed state directly through this API.
The user agent MUST ensure that the initiating document cannot distinguish whether the candidate application was newly installed or was already installed through:
<install>
element's dimensions, label, style, or state;
User agents SHOULD minimize distinguishable timing, focus, visibility, user-interface, and application-launch behavior between those cases.
Manifest and icon requests for explicit targets MUST omit credentials and MUST NOT disclose cookies or other caller-specific authentication state to the target origin.
Explicit-manifest retrieval does not require the target origin to opt in through CORS. The [=initiating document=] MUST NOT receive the response, manifest contents, or individual results of retrieval, parsing, identity, or metadata validation. It may observe only that processing produced [=invalid install data=], or that the candidate passed validation and processing continued to a user-mediated step.
[=Invalid install data=] MUST NOT distinguish among a network failure, an unsuccessful HTTP response, a redirect, a body-read failure, a manifest-processing failure, an identity failure, or a required-metadata validation failure. If processing continues, the [=initiating document=] may infer that the manifest was processed as a valid [=web install candidate=] and that any supplied [=manifest ID assertion=] matched.
Success means that installation completed, or that the user accepted an action for an existing application and the user agent completed processing that action. It does not reveal which case occurred. A later uninstall is not observable through this API.
User agents that do not support installation in private, guest, managed, or other profile types MUST process invalid installation data consistently with supported profiles. After installation data has been validated, they MUST return [=installation aborted=]. They SHOULD avoid reliable timing differences that distinguish an unsupported profile from other reasons for [=installation aborted=].
The user agent is the authority that validates installation input, attributes the request, obtains user consent, and performs privileged platform integration. Renderer- or script-side checks do not replace authoritative validation before installation.
The confirmation UI MUST clearly distinguish the installing origin from the target application's origin. Target names and icons MUST be treated as untrusted presentation data and displayed so that they cannot obscure or impersonate origin information.
The <install>
element's trusted rendering, visibility, occlusion, style validation,
focus behavior, and activation cooldown protect its click as a signal
of user intent. A user agent MAY apply stricter clickjacking,
reputation, rate-limit, or prompt-abuse defenses.
Direct manifest installation does not execute script from the target application before consent. Manifest and resource parsing MUST be bounded and MUST treat every URL and metadata field as untrusted.
For an [=explicit manifest=] request, the same-origin requirement between the candidate's [=web install candidate/manifest URL=] and [=web install candidate/start URL=] prevents a manifest hosted on one origin from claiming authority over an application on another origin. Supporting cross-origin manifest hosting would require a mechanism through which the application origin authorizes that association.
A supporting
<install> element
maps to the accessibility semantics of a button. Its accessible name
comes from user-agent-controlled localized content, not from untrusted
author fallback content.
The element MUST be reachable and activatable using sequential focus, keyboard activation, and platform accessibility input. Visual validation and anti-clickjacking checks MUST work with forced colors, high contrast, zoom, text scaling, and other user preferences.
How shared activation-blocker states map to platform accessibility states remains unspecified in the HTML Permission Element specification; see its accessibility considerations issue.
Authors SHOULD provide accessible status feedback when reacting to
installresult; dispatching the event does not itself create
an assistive-technology announcement.
The user agent uses the
lang and
dir attributes
applicable to
<install> to
localize and order the native control's own label. It uses Web App
Manifest's localization processing when displaying target application
metadata.
User agents MUST isolate bidirectional app names, URLs, and origins from surrounding UI and MUST safely elide or wrap long localized strings without hiding security-relevant origin information.
These mechanisms intentionally can select different languages. The native control follows the language inherited by the element, while target metadata can follow user-agent language preferences through Web App Manifest localization processing. A mixed-language interface is therefore conforming.
Interoperable tests should cover both entry points against the same target and outcome matrix. In addition to WebIDL and feature-detection tests, the suite should cover:
Content-Type metadata, referrers, cookies, and
service-worker interception;
Existing Chromium tests cover many product behaviors, but they do not by themselves establish interoperability requirements. Every normative requirement in this draft should map to a Web Platform Test or to a documented reason that cross-browser automation is not possible.
Open issues are recorded inline beside the affected definitions and algorithms. Before advancement, editors should ensure each inline issue is linked to a public repository issue and that its resolution updates the associated Web Platform Tests.
The editors thank Mike West, Diego González, Daniel Murphy, Alex Russell, Arthur Sonzogni, and participants in WICG, WebApps WG, TAG, browser standards-position discussions, and early developer trials for feedback that informed this draft.