![Dibyajyoti Pal](https://web.dev/images/authors/dibyajyotipal.jpg) Dibyajyoti Pal [LinkedIn](https://www.linkedin.com/in/dpal1996) ![Dan Murphy](https://web.dev/images/authors/danmurphy.jpg) Dan Murphy [X](https://twitter.com/danity_project) [LinkedIn](https://www.linkedin.com/in/daniel-murphy-09961314) ![Marijn Kruisselbrink](https://web.dev/images/authors/mek.jpg) Marijn Kruisselbrink [LinkedIn](https://www.linkedin.com/in/marijnkruisselbrink)

<br />


Published: June 3, 2026

<br />

Progressive Web Apps (PWAs) have revolutionized the web by offering app-like
experiences. However, one of their greatest strengths has also been a persistent
challenge: app identity is tightly coupled to the web origin.

To rebrand or restructure your architecture (for example, moving from
`www.example.com/social` to `social.example.com`), you faced a painful dilemma.
There was no way to "move" an installed PWA. Users were forced to manually
uninstall the old app and find the install button for the new one.

The PWA team is excited to introduce **PWA Origin Migration** in Chrome 150.
This new platform
feature lets you seamlessly transition installed PWAs to a new, same-site
origin with minimal user interruption, while still keeping the user sufficiently
informed.

## What origin migration enables

You can modify your site architecture without breaking user experience:

- **Technical architecture freedom:** Change the subdomain or path of your application.
- **Fix *split app* states:** Resolve the issue where changing a `start_url` without a stable ID accidentally created [duplicate app
  installations](https://github.com/WICG/manifest-incubations/blob/gh-pages/pwa-migration-explainer.md#duplicate-app-identity-split-apps).

Users can migrate their apps with a simple update dialog. They are informed of
the migration in a similar way to a
[standard app update](https://developer.chrome.com/blog/improvements-to-web-app-updates.md.txt). With
a single click the old app is uninstalled and the new app is installed and
launched.

## How to migrate a PWA

To migrate a PWA, follow these steps. The rest of the post goes into more
detail:

1. **Deploy the handshake:**
   - Add `migrate_from` to the new app.
   - Add the `allow_migration` field to the `/.well-known/web-app-origin-association` file on the old origin.
2. **Choose behavior:** `suggest` (or empty) avoids interrupting the user, likely helpful during an initial rollout. `force` blocks the user and requires the migration, if the user can't continue using the old URLs.
3. **Keep the old app up-to-date:** If the old site redirects to the new site, use the `install_url` property in the `migrate_from` block to ensure the browser can still find the old manifest for potential updates.
4. **Implement `id` in the destination manifest:** Chrome requires the destination app manifest to include an `id` field. This ensures the app cannot hit the common mistake of [creating *split apps*](https://github.com/WICG/manifest-incubations/blob/gh-pages/pwa-migration-explainer.md#duplicate-app-identity-split-apps) by changing the `start_url` without having an `id` set.

## The two-way handshake: How it works

To ensure security and prevent hostile takeovers, the migration requires a
secure handshake between the old and new origins. This handshake ensures that
both sites are controlled by the same entity.

> [!IMPORTANT]
> **Important:** This feature is currently limited to *same-site* migrations (sharing the same [eTLD+1](https://web.dev/articles/same-site-same-origin#public-suffix-list-etld)). This restriction reduces the risk that an app could be migrated completely away from one organization to another.

### Step 1: The new app declares the predecessor (required)

Add a `migrate_from` field to the web app manifest of the *new* application.

```json
// Manifest at https://fileman.google.com/manifest.json
{
  "name": "File Manager",
  "id": "/files/",
  "start_url": "/files/index.html",
  ....
  "migrate_from": [
    "https://drive.google.com/"
  ]
}
```

### Step 2: The old origin confirms the migration (required)

To prevent a new site from unilaterally hijacking an old app, the old origin
must explicitly authorize the migration. It does this with a `.well-known`
configuration file.

```json
// File at https://drive.google.com/.well-known/web-app-origin-association
{
  "https://fileman.google.com/files/": {
    "allow_migration": true
  }
}
```

### Step 3: Proactive signaling (optional)

To trigger the update without waiting for the user to visit the new site, update
the *old* app's manifest to point to the new one.

```json
// Manifest at https://drive.google.com/manifest.json
{
  "name": "Drive",
  "start_url": "/",
  "migrate_to": {
    "id": "https://fileman.google.com/files/",
    "install_url": "https://fileman.google.com/drive/installwebapp?usp=migrate"
  }
}
```

### Step 4: Handle redirects (optional)

As an alternative to using the `migrate_to` field, you can signal the migration
by redirecting the old app URLs to new app, and relying on the
[`scope_extensions`](https://developer.chrome.com/docs/capabilities/scope-extensions.md.txt)
to have the
[out of scope banner not display in the old app](https://developer.chrome.com/docs/capabilities/scope-extensions.md.txt#cross-origin_in-scope_navigation).
This means the old app's manifest will never be seen, and thus it can never be
updated. To allow the old app to continue to update before the app migration
occurs, set the `install_url` inside `migrate_from` to inform the browser of a
URL to fetch that still has the old manifest attached without redirection.

```json
// Manifest at https://fileman.google.com/manifest.json
{
  "name": "File Manager",
  "id": "/files/",
  "start_url": "/files/index.html",
  ....
  "migrate_from": [
    {
      "id": "https://drive.google.com/",
      "install_url": "https://drive.google.com/drive/installwebapp?usp=migrate"
    }
  ]
}
```

That's it! The UX is similar to the one used for
[app updating](https://developer.chrome.com/blog/improvements-to-web-app-updates.md.txt#name_and_icon_updates_are_now_optional),
where the user is notified on the top right corner of the app window:

![The app window shows that an App update is available. The dropdown includes a link to Review app update.](https://developer.chrome.com/static/blog/seamless-pwa-origin-migration/image/fig1.png)

Clicking **Review app update** shows the following UX (depending on what has
changed in the manifest):

![The dialog asks the user to review the logo, name, and URL updates.](https://developer.chrome.com/static/blog/seamless-pwa-origin-migration/image/fig2.png)

## Control the user experience

You can choose how aggressive the migration should be using the `behavior` flag:

1. **Suggest (default):** The user receives a passive notification (for example, in the app menu). They can choose to update, uninstall their app or ignore the migration by launching the dialog.
2. **Force:** On the next app launch, the user is presented with a blocking dialog. They must either update to the new origin or uninstall the app (please see the following screenshot).

The following example shows how to set this choice,

```json
"migrate_from": [
  { 
    "id": "https://example.com/social/",
    "behavior": "force" // or suggest
  }
]
```

> [!NOTE]
> **Note:** Forced migrations don't let developers change the app's name and icons at the same time. Instead, any name and icon updates will be presented to the user with a [standard app update](https://developer.chrome.com/blog/improvements-to-web-app-updates.md.txt) process after migration completes.

![The dialog tells the user that a new version of the app is required.](https://developer.chrome.com/static/blog/seamless-pwa-origin-migration/image/fig3.png)

## Conclusion

The PWA Migration feature empowers developers to keep building modern, flexible
web architectures without leaving users behind.