From Chrome 122 you can subscribe to the origin trial for the `scope_extensions`
app manifest member which allows sites that control multiple subdomains and top
level domains to be presented as a single web app. This document explains why
the Chrome team are introducing this feature, and when you might want to use it.


![Demián Renzulli](https://web.dev/images/authors/demianrenzulli.jpg) Demián Renzulli [X](https://twitter.com/drenzulli) [GitHub](https://github.com/demianrenzulli) ![Thomas Steiner](https://web.dev/images/authors/thomassteiner.jpg) Thomas Steiner [GitHub](https://github.com/tomayac) [LinkedIn](https://www.linkedin.com/in/thomassteinerlinkedin) [Mastodon](https://toot.cafe/@tomayac) [Bluesky](https://bsky.app/profile/tomayac.com) [Homepage](https://blog.tomayac.com/)

<br />

## Overview

Some web applications have multiple
[origins](https://developer.mozilla.org/docs/Glossary/Origin), for
example, `example.com` as the main app, and then `space_1.example.com`, ...,
`space_n.example.com`, sometimes combined with `special-example.com`, as
sub-experiences, all under the roof of the main app. This type of site
architecture has implications in the context of Progressive Web Apps.
Limitations include not being able to share service workers, any type of device,
local storage, and permissions across origins. Also, cross-origin navigation in
a standalone PWA shows a window UI ("out of scope" bar) indicating that the user
has moved out of the PWA experience. You can learn how to work around some of
these problems in the articles
[Progressive Web Apps in multi-origin sites](https://web.dev/multi-origin-pwas/)
and
[Building multiple Progressive Web Apps on the same domain](https://web.dev/building-multiple-pwas-on-the-same-domain/).

The Scope Extensions API allows web apps to overcome some of the challenges that
the
[same-origin policy](https://developer.mozilla.org/docs/Web/Security/Same-origin_policy)
imposes on this type of site architecture. It lets web apps extend their
[scope](https://www.w3.org/TR/appmanifest/#understanding-scope) to other origins
to help achieve a unified experience, given agreement between the web app's
primary origin and the associated origins.

> [!NOTE]
> **Note:** At the time of this writing, only ChromeOS supports both of the Scope Extensions features covered in this document (cross-origin in-scope navigation and cross-origin link capturing). Cross-origin in-scope navigation is also supported in Chrome on Windows, macOS, and Linux, but the integration with link capturing is not available yet on these platforms. Scope Extensions is not yet available on mobile devices.

## Goals

The main goal of the Scope Extensions API is to allow sites that control
multiple subdomains and top level domains to behave as one contiguous web app
when it comes to web app UI and link capturing. For example, letting the site
`example.com` that spans `example.com.co.uk` and `support.example.com` behave as
much as possible as a single web application.

![Diagram showing a main PWA and associated subexperiences.](https://developer.chrome.com/static/docs/capabilities/scope-extensions/webappscopeext--a7gn51inf67.png)

Scope Extensions allows multi-origin PWAs to behave as a contiguous web app when
it comes to web app UI.

In practice, this translates to two more specific goals:

- **Cross-origin navigation:** Allow users to navigate across associated origins without disrupting the user experience by invoking window UI informing the user that they are moving away from the PWA.
- **Cross-origin link capturing:** Allow web apps to capture user navigations to sites they are affiliated with.

### Cross-origin in-scope navigation

By default, when users navigate across origins in a standalone PWA, they are
shown a window UI indicating that they are moving outside of the PWA experience.
In Chrome, this UI consists of an "out of scope" bar that contains the URL of
the new origin. This is disruptive to the user experience, as users expect to
continue navigating inside the same application context, but they might perceive
they are being taken out of it.

![Out of scope bar at the top of a standalone PWA.](https://developer.chrome.com/static/docs/capabilities/scope-extensions/webappscopeext--8v1hi4zrb.png)

"Out of scope" bar shown in Chrome when users navigate across different origins
in a standalone PWA.

With Scope Extensions, the window UI won't be shown when users navigate to any
of the associated origins so the PWA is presented as a unified experience.

### Cross-origin link capturing

Link Capturing refers to the ability of an app to capture links within its
scope. The way that this is implemented varies among browsers and operating
systems. In Chrome on ChromeOS for example, links in the scope of an installed
PWA by default open a browser tab with an indication in the address bar that
there is an app that's capable of handling these links, allowing the user to
opt-in for automatic link capturing from that point.

![Omnibar prompt for an installed PWA.](https://developer.chrome.com/static/docs/capabilities/scope-extensions/webappscopeext--szcq8svsqd.png)

Fragment of Chrome address bar for a tab in ChromeOS showing a visual indication
that the link can be handled by a PWA and the option to remember that decision.

If a user clicks on a link that is outside of the scope of the PWA (including
links to subdomains or top-level domains), they won't be recognized as belonging
to it. For example, links will be opened in a browser tab without any indication
to the user that there is an app that's capable of handling the link. The Scope
Extensions API allows extending the scope of the PWA so that the associated
origins are treated as in-scope links.

## Implementation

Implementing scope extensions requires establishing the relationship between the
main origin and the associated origins.

### Declare the list of associated origins

Add a `scope_extensions` web app manifest member to the main PWA origin to
enable the web app to extend their scope to other origins.

#### Web App Manifest (https://example.com)

    {
      "name": "Example",
      "display": "standalone",
      "start_url": "/index.html",
      "scope_extensions": [
        { "origin": "https://*.example.com" },
        { "origin": "https://example.co.uk" },
        { "origin": "https://*.example.co.uk" }
      ]
    }

### Confirm associations

Each of the listed origins confirms the association with the web app using a
`/.well-known/web-app-origin-association` configuration file. This file needs to
be named `web-app-origin-association` and be served at this exact location, as
it is a [Well-Known URI](https://en.wikipedia.org/wiki/Well-known_URI).

#### /.well-known/web-app-origin-association (associated origin)

    {
      "web_apps": [{ "web_app_identity": "https://example.com" }]
    }

## Demo

The demo consists of two sites:

- [Main PWA](https://googlechrome.github.io/samples/pwa-testing/main-pwa-origin-2/): The actual PWA that declares the list of associated origins through the `scope_extensions` member in its [web app manifest](https://googlechrome.github.io/samples/pwa-testing/main-pwa-origin-2/manifest.json).
- [Origin in extended scope](https://mkruisselbrink.github.io/scope-extensions-test-site/): An origin outside the main PWA's scope but associated with it after being listed by the main PWA as an associated origin and confirming the relationship through its [`web-app-origin-association` file](https://mkruisselbrink.github.io/.well-known/web-app-origin-association).

To perform the following tests, you have to enable the
`about://flags/#enable-desktop-pwas-scope-extensions` flag (available from
Chrome v115 onwards).

### Test cross-origin navigation

As a precondition for these tests, open the
[main PWA](https://googlechrome.github.io/samples/pwa-testing/main-pwa-origin-2/) in a browser, install it as a PWA
and open it to run it in standalone mode. The PWA contains links to an
[origin in extended scope](https://mkruisselbrink.github.io/scope-extensions-test-site/) and to an
[origin not in extended scope](https://www.example.com/).

![Main PWA window with in scope and extended scope links.](https://developer.chrome.com/static/docs/capabilities/scope-extensions/webappscopeext--e4jpob14w8.png)

Demo PWA with links to origin in extended scope and origin not in extended
scope.

#### Default cross-origin navigation (not in extended scope)

1. Click the link to the [origin not in extended scope](https://example.com) inside the full screen PWA.
2. As a result, the navigation happens and the out of scope bar is shown.

![Main PWA window with out of scope bar after clicking the out of scope link.](https://developer.chrome.com/static/docs/capabilities/scope-extensions/webappscopeext--3dio5zza69i.png)

"Out of scope" bar shown by default for a cross-origin navigation for a PWA in
standalone mode.

#### Cross-origin navigation with Scope Extensions (in extended scope)

1. Navigate back to the home page of the PWA.
2. Click the link to the[origin not in extended scope](https://googlechrome.github.io/samples/pwa-testing/main-pwa-origin-2/).
3. By default, an "out of scope" bar should be shown, but because of the Scope Extensions association, it is not.

![Main PWA window without out of scope bar after clicking the extended scope link.](https://developer.chrome.com/static/docs/capabilities/scope-extensions/webappscopeext--nbh41z9x80e.png)

"Out of scope" bar not shown in cross-origin navigation after origin association
has been made with Scope Extensions.

### Test cross-origin link capturing

1. Open and install the [main PWA](https://googlechrome.github.io/samples/pwa-testing/main-pwa-origin-2/) in a ChromeOS device.
2. Click the following link: [associated origin](https://mkruisselbrink.github.io/scope-extensions-test-site/).
3. The link is opened in a new browser tab and a prompt is shown to open it in the installed PWA.

![Omnibar prompt for an installed PWA with extended scope.](https://developer.chrome.com/static/docs/capabilities/scope-extensions/webappscopeext--q7ar1vs9ccl.png)

Clicking on a link to a PWA's associated origin opens the link in a new tab and
shows an "Open in App" icon allowing the user to opt-in for automatic link
capturing.

## Origin trial

If you'd like to test this API in your application out in the field with real
users, you can do so with an
[origin trial](https://github.com/GoogleChrome/OriginTrials/blob/gh-pages/developer-guide.md).
Origin trials let you try out experimental features with your users by obtaining
a testing token that's tied to your domain. You can then deploy your app and
expect it to work in a browser that supports the feature you're testing (in this
case, it is available in Chrome from 121 to 126). To obtain your own token to
run an origin trial, fill out the
[application form](https://developer.chrome.com/origintrials#/view_trial/3889984178141265921).

## Feedback

The Chrome team are looking for feedback about the usefulness of this API. To
help the team make this API evolve with feedback about the usefulness of it and
new use cases not covered in the current version, open an
[Issue on GitHub](https://github.com/WICG/manifest-incubations/issues).

## Additional resources

- [Scope Extensions API - Origin Trial](https://goo.gle/scope-extensions-ot)
- [Chrome Status - Web App Scope Extensions](https://chromestatus.com/feature/5746537956114432)
- [Scope Extensions for Web Applications explainer](https://github.com/WICG/manifest-incubations/blob/gh-pages/scope_extensions-explainer.md)
- [Intent to Experiment](https://groups.google.com/a/chromium.org/d/msgid/blink-dev/37136c0f-1f17-4da1-9398-b8ba890d2ee2n%40chromium.org)
- [Mozilla Standards Position](https://github.com/mozilla/standards-positions/issues/904)
- [Apple Standards Position](https://github.com/WebKit/standards-positions/issues/265)
- [Chromium bug](https://crbug.com/1250011)
- [Progressive Web Apps in multi origin sites](https://web.dev/articles/multi-origin-pwas)
- [Building multiple Progressive Web Apps on the same domain](https://web.dev/articles/building-multiple-pwas-on-the-same-domain)

## Acknowledgements

Special thanks to the team behind the development of this API. Scope Extensions
was specified by [Alan Cutter](https://github.com/alancutter) and
[Lu Huang](https://github.com/LuHuangMSFT), with input from
[Matt Giuca](https://twitter.com/mgiuca). The API was implemented by
[Alan Cutter](https://github.com/alancutter) from Google Chrome and
[Hassan Talat](https://github.com/htalat),
[Kristin Lee](https://github.com/Kbhlee2121), and
[Lu Huang](https://github.com/LuHuangMSFT) from Microsoft Edge.