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.

Introduction

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:

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.

Goals

Non-goals

Examples

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>
      

Dependencies

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.

Terminology

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.

Web Install model

A web install request is a struct with the following [=struct/items=]:

document
The [=initiating document=].
entry point
The request's [=entry-point kind=].
application source
The request's [=application source=].
manifest URL
The manifest URL for an [=explicit manifest=] request; otherwise null.
manifest ID
The request's optional [=manifest ID assertion=].

A web install candidate is a struct with the following [=struct/items=]:

manifest
A processed manifest.
manifest URL
The URL from which the manifest was obtained.
identity
The processed manifest id.
start URL
The processed start URL.

A web install outcome is one of:

installation succeeded
The user agent completed installation, or completed processing a user-approved action for an already-installed application.
invalid install data
The supplied URL, manifest, identity assertion, or required installation metadata was invalid or unavailable.
installation aborted
The request did not complete for a reason other than [=invalid install data=], including user dismissal, permission or policy denial, an invalid initiating document, an unsupported environment, a concurrent operation, navigation, destruction, or internal failure.

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.

Shared Web Install processing

To finish a web install request given a [=web install request=] request and [=web install outcome=] outcome, run the following steps:

  1. Let traversable be request's [=web install request/document=]'s [=top-level traversable=], if it has one; otherwise null.
  2. If traversable is not null and its [=top-level traversable/active web install request=] is request, set it to null.
  3. Return outcome.

To run a web install request given a [=web install request=] request, run the following steps:

  1. Let document be request's [=web install request/document=].
  2. If document is not an [=eligible initiating document=], return the result of [=finish a web install request=] with request and [=installation aborted=].
  3. Let traversable be document's [=top-level traversable=].
  4. If traversable's [=top-level traversable/active web install request=] is not null, return the result of [=finish a web install request=] with request and [=installation aborted=].
  5. Set traversable's [=top-level traversable/active web install request=] to request.
  6. If request's [=web install request/application source=] is [=current document=], let candidateResult be the result of [=resolve a web install candidate from the current document=] for request. Otherwise, let candidateResult be the result of [=resolve a web install candidate from an explicit manifest=] for request.
  7. If candidateResult is a [=web install outcome=], return the result of [=finish a web install request=] with request and candidateResult.
  8. Let candidate be candidateResult.
  9. If document is no longer an [=eligible initiating document=]:
    1. If traversable's [=top-level traversable/active web install request=] is request, set it to null.
    2. Return the result of [=finish a web install request=] with request and [=installation aborted=].
  10. Let permissionGranted be the result of [=obtain web install permission=] for request.
  11. If permissionGranted is false, return the result of [=finish a web install request=] with request and [=installation aborted=].
  12. Let outcome be the result of [=perform a Web Install action=] with request and candidate.
  13. Return the result of [=finish a web install request=] with request and outcome.

For explicit-manifest requests, manifest retrieval and validation precede installation-permission and unsupported-profile handling. This ensures that invalid manifest data produces the same [=invalid install data=] outcome regardless of permission or profile state. Consequently, the target origin may observe a manifest request before installation permission is granted; the request omits credentials and referrer information.

If the [=initiating document=] navigates, is destroyed, ceases to be fully active, or ceases to be the active document of its top-level traversable before processing completes, the user agent MUST cancel associated user interface and complete the request with [=installation aborted=].

Common request preconditions

To determine whether a {{Document}} document is an eligible initiating document, run the following steps:

  1. If document is not [=Document/fully active=], return false.
  2. If document is not the active document of a [=top-level traversable=], return false.
  3. If the [=navigable/traversable navigable=] of document's [=node navigable=] is a fenced navigable, return false.
  4. If document's active sandboxing flag set is not empty, return false.
  5. If the web-app-installation [=policy-controlled feature=] is disabled in document, return false.
  6. Return true.

Resolving a web install candidate

Resolving from the current document

To resolve a web install candidate from the current document for a [=web install request=] request, run the following steps:

  1. Let document be request's [=web install request/document=].
  2. Let manifest be document's processed manifest.
  3. If manifest is null, return [=invalid install data=].
  4. Let manifestURL be manifest's manifest URL.
  5. Let identity be manifest's manifest id.
  6. If the manifest did not explicitly contain an id member, return [=invalid install data=].
  7. If identity is not [=same origin=] with document's [=Document/URL=], return [=invalid install data=].
  8. Let candidate be a new [=web install candidate=] whose [=web install candidate/manifest=] is manifest, [=web install candidate/manifest URL=] is manifestURL, [=web install candidate/identity=] is identity, and [=web install candidate/start URL=] is manifest's start URL.
  9. Return the result of [=validate a web install candidate=] with request and candidate.

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]].

Resolving from an explicit manifest

To resolve a web install candidate from an explicit manifest for a [=web install request=] request, run the following steps:

  1. Let manifestURL be request's [=web install request/manifest URL=].
  2. If manifestURL is not an HTTP(S) URL whose [=url/origin=] is potentially trustworthy, return [=invalid install data=].
  3. Let bodyBytes be the result of [=fetch an install manifest=] from manifestURL.
  4. If bodyBytes is failure, return [=invalid install data=].
  5. Let manifest be the result of [=process install manifest bytes=] with bodyBytes and manifestURL.
  6. If manifest is failure, return [=invalid install data=].
  7. Let identity be manifest's manifest id.
  8. If request's [=web install request/manifest ID=] is not null, and it is not equal to identity, return [=invalid install data=].
  9. If request's [=web install request/manifest ID=] is null, and the fetched manifest did not explicitly contain an id member, return [=invalid install data=].
  10. Let candidate be a new [=web install candidate=] whose [=web install candidate/manifest=] is manifest, [=web install candidate/manifest URL=] is manifestURL, [=web install candidate/identity=] is identity, and [=web install candidate/start URL=] is manifest's start URL.
  11. Return the result of [=validate a web install candidate=] with request and candidate.

Fetching and processing a manifest

Fetching an install manifest

To fetch an install manifest from a URL manifestURL, run the following steps:

  1. Let response be the result of the user agent internally retrieving manifestURL using GET.
  2. The retrieval MUST omit credentials and referrer information.
  3. The retrieval MUST NOT require a CORS check to succeed.
  4. The retrieval MUST comply with the manifest-src directive of the Content Security Policy applicable to the [=initiating document=].
  5. The retrieval MUST NOT be intercepted by a service worker.
  6. The retrieval MUST be subject to Local Network Access checks as if it were initiated by the [=initiating document=].
  7. If the retrieval uses cached data, it MUST use the [=network partition key=] associated with the [=initiating document=]'s [=relevant settings object=].
  8. The information observable by the [=initiating document=] as a result of this retrieval is limited as described in Privacy considerations.
  9. If the retrieval encounters a redirect, return failure.
  10. If response is a [=network error=], return failure.
  11. If response's [=response/status=] is not an [=ok status=], return failure.
  12. If response's Content-Type metadata is not a JSON MIME type, return failure.
  13. Let bodyBytes be the result of fully reading response's [=response/body=].
  14. If fully reading the body failed, return failure.
  15. The user agent MUST NOT expose response or bodyBytes to the [=initiating document=].
  16. Return bodyBytes.

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.

Processing an install manifest

To process install manifest bytes given a byte sequence bodyBytes and URL manifestURL, run the following steps:

  1. Let manifest be the result of running process a manifest with bodyBytes, manifestURL as both the manifest URL and document URL, and null as the client.
  2. If processing the manifest failed, return failure.
  3. Return manifest.

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.

Validating a web install candidate

To validate a web install candidate given a [=web install request=] request and [=web install candidate=] candidate, run the following steps:

  1. Let manifest be candidate's [=web install candidate/manifest=].
  2. If the source manifest did not explicitly contain a valid start_url member, return [=invalid install data=].
  3. If neither name nor short name is a non-empty string, return [=invalid install data=].
  4. If manifest's icons list does not contain at least one valid image resource whose purpose contains any, return [=invalid install data=].
  5. If request's [=web install request/application source=] is [=explicit manifest=], and candidate's [=web install candidate/start URL=] is not [=same origin=] with candidate's [=web install candidate/manifest URL=], return [=invalid install data=].
  6. Return candidate.

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.

Permission and user consent

The 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.

Obtaining install permission

To obtain web install permission for a [=web install request=] request, run the following steps:

  1. If request's [=web install request/entry point=] is [=entry-point kind/declarative=], return true.
  2. If request's [=web install request/application source=] is [=current document=], return true.
  3. Let descriptor be a new {{PermissionDescriptor}} whose {{PermissionDescriptor/name}} is web-app-installation.
  4. Let state be the result of [=request permission to use=] the powerful feature described by descriptor.
  5. If state is not {{PermissionState/"granted"}}, return false.
  6. Return true.

Installation confirmation

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.

Performing installation

To perform a Web Install action given a [=web install request=] request and [=web install candidate=] candidate, run the following steps:

  1. If the user agent determines that an installed web application with candidate's [=web install candidate/identity=] already exists:
    1. Present user-controlled UI that offers a reasonable action for the existing application, such as launching it.
    2. If the user declines or dismisses that UI, return [=installation aborted=].
    3. Perform or initiate the accepted action, then return [=installation succeeded=]. The observable outcome MUST NOT reveal anything about the installation state of the candidate application.
  2. Let accepted be the result of [=confirm web installation=] with request and candidate.
  3. If accepted is false, return [=installation aborted=].
  4. Ask the user agent to install an installed web application whose application manifest is candidate's [=web install candidate/manifest=].
  5. If the user agent cannot complete installation, return [=installation aborted=].
  6. Return [=installation succeeded=].

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.

The <install> element

The HTML <install> element represents a user-agent-rendered control that lets the user initiate a Web Install request.

Categories:
[=Flow content=].
[=Phrasing content=].
[=Interactive content=].
[=Palpable content=].
Contexts in which this element can be used:
Where [=phrasing content=] is expected.
Content model:
[=Phrasing content=].
Content attributes:
Global attributes.
manifest.
manifestid.
oninstallresult.
onvalidationstatuschange.
Accessibility considerations:
For authors: none.
For implementers: see [[HTML-AAM]] and Accessibility considerations.
DOM interface:
{{HTMLInstallElement}}.
[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.

Context blocker reasons

To determine an <install> element's context blocker reason, run the following steps:

  1. Let document be the element's [=Node/node document=].
  2. If the [=navigable/traversable navigable=] of document's [=node navigable=] is a fenced navigable, return illegal_subframe.
  3. If the web-app-installation [=policy-controlled feature=] is disabled in document, return illegal_subframe.
  4. If document's active sandboxing flag set is not empty, return illegal_sandbox.
  5. If document is not the active document of a [=top-level traversable=], return illegal_subframe.
  6. Return the empty string.

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]].

Internal state and lifecycle

{{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:

  1. Run ActivationBlockersMixin's initialization steps.

The {{HTMLInstallElement}} insertion steps are:

  1. Run ActivationBlockersMixin's insertion steps.

The {{HTMLInstallElement}} removing steps are:

  1. Run ActivationBlockersMixin's removing steps.

The default value of the tabindex content attribute for <install> is 0.

Attributes

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.

Lifecycle and rendering

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.

Activation behavior

The <install> element's [=EventTarget/activation behavior=] given an {{Event}} event is:

  1. If event.{{Event/isTrusted}} is false, return.
  2. If [=this=].{{HTMLInstallElement/isValid}} is false, return.
  3. Let document be [=this=]'s node document.
  4. If document is not an [=eligible initiating document=], return.
  5. Let manifestURL be null.
  6. Let manifestID be null.
  7. If [=this=] has a manifestid attribute but no manifest attribute, [=queue an install result=] of invalid-data at [=this=] and return.
  8. If [=this=] has a manifest attribute:
    1. Let manifestValue be the result of stripping leading and trailing ASCII whitespace from the manifest attribute's value.
    2. If manifestValue is the empty string, [=queue an install result=] of invalid-data at [=this=] and return.
    3. Set manifestURL to the result of the [=URL parser=] on manifestValue with document's document base URL as base.
    4. If manifestURL is failure, [=queue an install result=] of invalid-data at [=this=] and return.
    5. If [=this=] has a manifestid attribute:
      1. Let manifestIDValue be the result of stripping leading and trailing ASCII whitespace from the manifestid attribute's value.
      2. If manifestIDValue is the empty string, [=queue an install result=] of invalid-data at [=this=] and return.
      3. Set manifestID to the result of the [=URL parser=] on manifestIDValue with document's document base URL as base.
      4. If manifestID is failure, [=queue an install result=] of invalid-data at [=this=] and return.
  9. Let request be a new [=web install request=] whose [=web install request/document=] is document, [=web install request/entry point=] is [=entry-point kind/declarative=], [=web install request/application source=] is [=current document=] if manifestURL is null and [=explicit manifest=] otherwise, [=web install request/manifest URL=] is manifestURL, [=web install request/manifest ID=] is manifestID.
  10. Run the following steps [=in parallel=]:
    1. Let outcome be the result of [=run a web install request=] with request.
    2. If outcome is [=installation succeeded=], [=queue an install result=] of success at [=this=] and abort these substeps.
    3. If outcome is [=invalid install data=], [=queue an install result=] of invalid-data at [=this=] and abort these substeps.
    4. [=Queue an install result=] of 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.

The 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:

  1. Let event be a new {{InstallResultEvent}} whose {{Event/type}} is installresult, {{InstallResultEvent/result}} is result, {{Event/bubbles}} is true, {{Event/cancelable}} is false, and {{Event/composed}} is false.
  2. [=Dispatch=] event at element.

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 attribute

The {{InstallResultEvent/result}} getter returns [=this=].{{InstallResultEvent/[[result]]}}.

Host-specification integrations

Web App Manifest

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.

WHATWG HTML

This specification adds {{Navigator/install()}}, {{HTMLInstallElement}}, the <install> element, and the installresult event to HTML.

Capability Elements

{{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.

Permissions and Permissions Policy

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}}.

Launch Handler

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]].

Privacy considerations

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:

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=].

Security considerations

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.

Accessibility considerations

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.

Internationalization considerations

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.

Testing considerations

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:

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 index

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.

Acknowledgements

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.