> [!NOTE]
> **Note:** The initial release of Isolated Web Apps, and any high-trust APIs that require them, will only be available to [Chrome
> Enterprise](https://chromeenterprise.google/) administered ChromeOS devices and select development partners. We are looking to expand this to additional partners and unmanaged and cross-platform devices in the future.

The web is a truly unique application platform. Apps built on it are instantly
accessible on any operating system without any code changes or compiling needed.
Whenever a user comes to your app, they always have the most up-to-date version.
They're [installable](https://web.dev/learn/pwa/) and can work offline, are
[highly capable](https://developer.chrome.com/capabilities), and super shareable with just a link. Build a
web application, and it just works, everywhere.

Because the web aims to be [safe and secure by
default](https://web.dev/secure/), its security model needs to be very
conservative. Any new capabilities added need to be safe for a casual user to
accidentally come across through a URL. We call this security model the *drive
by web* . While this is great for many applications, and can be made more secure
using
[Content Security Policies](https://developer.mozilla.org/docs/Web/HTTP/CSP) and
[cross-origin isolation](https://web.dev/why-coop-coep/), it doesn't work for
every use-case. A number of really important, and very powerful APIs, like
[Direct Sockets](https://developer.chrome.com/docs/iwa/direct-sockets) and
[Controlled Frame](https://developer.chrome.com/docs/iwa/controlled-frame), that developers need can't be made safe enough for the drive
by web.

For these applications, they don't currently have an option for building on the
web. For others, the web's security model may not be conservative enough; they
may not share the assumption that the server is trustworthy, and instead prefer
discretely versioned and signed stand-alone applications. A new, high-trust
security model is needed. Isolated Web Apps (IWAs) provide an isolated, bundled,
versioned, signed, and trusted application model built on top of the existing
web platform to enable these developers.

## A spectrum of trust on the web

You can think of security and capabilities on the web in terms of a spectrum.

![An illustration demonstrating the spectrum of trust on the web. On the left, a
globe representing the drive-by web. In the middle, Progressive Web Apps. On the
right, a fish bowl with a goldfish inside, representing Isolated Web Apps. A
solid black line connects all three icons horizontally, and a dashed red line
separates Progressive Web Apps from Isolated Web
Apps](https://developer.chrome.com/docs/iwa/introduction/image/isolated-web-apps-1.avif)

The *drive-by web*, on the left, has the lowest trust security model because
it needs to be most accessible, and therefore has the least access to a user's
system. Browser-installed web apps, in the middle get a little more trust, and
can integrate a little deeper into a user's system. Users can generally switch
between drive-by web versions of apps and browser-installed versions without
problem.

Then there's high-trust, Isolated Web Applications.

They act and feel more like native apps and can get access to deep system
integrations and powerful capabilities. Users can't jump between them and the
drive-by-web. If you need this level of security, or these capabilities, there's
no going back.

When trying to decide where on this spectrum you should aim for, default to the
lowest-trust security model that you can, like a [Progressive Web
App](http://web.dev/learn/pwa). This will give you the greatest reach, require
you to manage the least amount of security concerns yourself, and will be the
most flexible for your developers and users.

## Secure by design

Isolated Web Apps provide a high-trusted security model for web applications. To
enable that, though, some of the assumptions that the drive by web makes about
trust need to be rethought. Core web building blocks, like servers and DNS, can
no longer be explicitly trusted. Attack vectors that may seem more relevant for
native apps suddenly become important. So, to gain access to the new high-trust
security model provided by IWAs, web apps need to be packaged, isolated, and
locked down.

### Packaged

Pages and assets for Isolated Web Apps can't be served from live servers or
fetched over the network like normal web applications. Instead, to gain access
to the new high-trust security model, web apps need to package all of the
resources they need to run into a
[Signed WebBundle](https://developer.chrome.com/docs/web-platform/web-bundles). Signed
web bundles take all of the resources required to run a site and package them
together into a `.swbn` file, concatenating them with an [integrity
block](https://github.com/WICG/webpackage/blob/main/explainers/integrity-signature.md).
This allows the web app to be securely downloaded in its entirety, and even
shared or installed while offline.

This, however, poses a problem for verifying the authenticity of a site's code:
TLS keys require an internet connection to work. Instead of TLS keys, IWAs are
signed with a key that can be kept securely offline. The good news is that, if
you can gather all of your production files into a folder, you can turn it into
an IWA without much modification.

> [!WARNING]
> **Warning:** IWAs, by design, exclude some site architectures. A site must be able to serve each of its pages while offline. That means server-rendered pages cannot be included. You should consider static generated sites or client-rendered sites as your primary architectures.

#### Generate signing keys

Signing keys are Ed25519 or ECDSA P-256 key pairs, with the private key being
used to sign the bundle and the public key used to verify the bundle. You can
use [OpenSSL](https://www.openssl.org/) to generate and encrypt an Ed25519 or
ECDSA P-256 key:

    # Generate an unencrypted Ed25519 key
    openssl genpkey -algorithm Ed25519 -out private_key.pem

    # or generate an unencrypted ECDSA P-256 key
    openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem

    # Encrypt the generated key. This will ask for a passphrase, make sure to use a strong one
    openssl pkcs8 -in private_key.pem -topk8 -out encrypted_key.pem

    # Delete the unencrypted key
    rm private_key.pem

> [!TIP]
> **Tip:** If you're on a Mac, run `openssl version`. If it says LibreSSL, you'll need to switch to OpenSSL. Install it using [Homebrew](https://brew.sh/) by running `brew install openssl` and linking it to override the default using [these instructions](https://stackoverflow.com/questions/62195898/openssl-still-pointing-to-libressl-2-8-3/72274633#72274633)

Signing keys have a secondary purpose, too. Because a domain may be vulnerable
to loss of control like a server, it can't be used to identify the installed
IWA. Instead, an IWA is identified by the bundle's public key, which is part of
its signature and tied to the private key, instead. This is a significant change
to how the drive-by web works, so instead of using HTTPS, IWAs use a new
[scheme](https://github.com/WICG/isolated-web-apps/blob/main/Scheme.md), too:
`isolated-app://`.

> [!WARNING]
> **Warning:** Because your IWA's identity is tied to the private key used to sign it, you'll need a different signing key for each IWA you create. This also means that, if you sign the same app with different signing keys, they'll be considered different apps, which will affect your ability to provide a seamless update experience.

#### Bundle your app

With your signing key available, it's time to bundle your web app. To do so, you
can use the official [NodeJS](https://nodejs.org/en) packages to bundle then
sign your IWAs ([Go](https://go.dev/) command-line tools are [also
available](https://github.com/WICG/webpackage/tree/main/go/bundle)). First, use
the, [wbn](https://www.npmjs.com/package/wbn) package, pointing to the folder
containing all of your IWA's production files (here dist) to wrap them up into
an unsigned bundle:

    npx wbn --dir dist

> [!NOTE]
> **Note:** [`npx`](https://docs.npmjs.com/cli/v7/commands/npx) is an [NPM](https://www.npmjs.com/) command (as of NPM 7) and is used here as a convenient way to run a package without installing it globally or as a dependency of your project. It will always try and use the latest version of the package. If you need consistency in your builds, you should instead install these packages as development dependencies in your project and run them from [npm scripts](https://docs.npmjs.com/cli/v9/using-npm/scripts).

This will generate an unsigned web bundle of that directory to `out.wbn.` Once
generated, use the encrypted Ed25519 or ECDSA P-256 key you previously created
to sign it using [wbn-sign](https://www.npmjs.com/package/wbn-sign):

    npx wbn-sign -i out.wbn -k encrypted_key.pem -o signed.swbn

> [!TIP]
> **Tip:** This will prompt you for the password used to encrypt your key. You can set the `WEB_BUNDLE_SIGNING_PASSPHRASE` environment variable to automatically pass in the password.

This will generate a signed web bundle from the unsigned web bundle called
`signed.swbn`. Once signed, the tool will also output the Web Bundle ID and its
Isolated Web App origin. The Isolated Web App origin is how your IWA is
identified in the browser.

    Web Bundle ID: ggx2sheak3vpmm7vmjqnjwuzx3xwot3vdayrlgnvbkq2mp5lg4daaaic
    Isolated Web App Origin: isolated-app://ggx2sheak3vpmm7vmjqnjwuzx3xwot3vdayrlgnvbkq2mp5lg4daaaic/

> [!NOTE]
> **Note:** Even though your IWA is identified by this origin, IWAs open in their own window without an address bar, like a PWA, and users are unlikely to ever see this.

If you are using [Webpack](https://webpack.js.org/),
[Rollup](https://rollupjs.org/), or a tool that supports their plugins (like
[Vite](https://vitejs.dev/)), you can use one of the bundler plugins
([Webpack](https://www.npmjs.com/package/webbundle-webpack-plugin),
[Rollup](https://www.npmjs.com/package/rollup-plugin-webbundle)) that wraps
these packages instead of calling them directly. Doing so will generate a signed
bundle as the output of your build.

> [!TIP]
> **Tip:** You only need to include these plugins as part of your production build pipeline, not your development pipeline.

#### Test your app

You can test your IWA in one of two ways: either by running your development
server through Chrome's built-in IWA developer proxy, or by installing your
bundled IWA. To do so, you'll need to be on Chrome or ChromeOS 120 or later,
enable the IWA flags, and install your app through Chrome's Web App Internals:

1. Enable the `chrome://flags/#enable-isolated-web-app-dev-mode` flag
2. Test your IWA by going to Chrome's Web App Internals page at `chrome://web-app-internals`

Once on the Web App Internals page, you have two choices: `Install IWA with Dev
Mode Proxy` or `Install IWA from Signed Web Bundle`.

If you install through a Dev Mode Proxy, you can install any URL, including
sites running from a local development server, as an IWA, without bundling them,
presuming they meet the other IWA installation requirements. Once installed, an
IWA for that URL will be added to your system with the correct security policies
and restrictions in place and access to IWA-only APIs. It will be assigned a
random identifier. Chrome Dev Tools is also available in this mode to help you
debug your application. If you install from a Signed Web Bundle, you'll upload
your signed, bundled IWA and it will install as if it had been downloaded by an
end-user.

On the Web App Internals page, you can also force update checks for any
applications installed through Dev Mode Proxy or from a Signed Web Bundle to
test the update process, too.

### Isolated

Trust is key to Isolated Web Apps. This starts with how they run. Users have
different mental models for what an app can, and should be able to, do depending
on whether it's running in a browser or in a stand-alone window, generally
believing that stand-alone apps have more access and are more powerful. Because
IWAs can gain access to high-trust APIs, they're required to run in a
stand-alone window to align with this mental model. This visually separates them
from the browser. But it goes further than visual separation.

Isolated Web Apps run on a separate protocol than in-browser websites
(`isolated-app` versus `http` or `https`). This means each IWA is entirely separated
from websites running in-browser, even if they're built by the same company,
thanks to the
[same-origin policy](https://developer.mozilla.org/docs/Web/Security/Same-origin_policy).
IWA storage is also separated from each other. This together ensures that
cross-origin content can't leak between different IWAs or between
IWAs and a user's normal browsing context.

But neither isolation nor bundling and signing a site's code are useful for
establishing trust if an IWA can download and run arbitrary code after
installation. To ensure this while still allowing IWAs to connect to other sites
for content, IWAs enforce a rigorous set of
[Content Security Policies](https://developer.mozilla.org/docs/Web/HTTP/CSP):

- Only allows JavaScript from the bundle; however, it does allow Wasm to be run no matter its source. ([`script-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/script-src))
- Allows JavaScript to fetch from secure, non-localhost cross-origin domains, connect [WebSocket](https://developer.mozilla.org/docs/Web/API/WebSockets_API) and [WebTransport](https://developer.mozilla.org/docs/Web/API/WebTransport) endpoints, and [blob](https://developer.mozilla.org/docs/Web/API/Blob) and [data](https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) URLs ([`connect-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src))
- Guards against DOM cross-site script injection (XSS) attacks by regulating how DOM manipulation functions can be used ([`require-trusted-types-for`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/require-trusted-types-for))
- Allows frames, images, audio, and video from any HTTPS domain ([`frame-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src), [`img-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/img-src), [`media-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/media-src))
- Allows fonts from the bundle and blobs ([`font-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/font-src))
- Allow inline CSS or CSS from the bundle ([`style-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/style-src))
- [`<object>`](https://developer.mozilla.org/docs/Web/HTML/Element/object), [`<embed>`](https://developer.mozilla.org/docs/Web/HTML/Element/embed), and [`<base>`](https://developer.mozilla.org/docs/Web/HTML/Element/base) elements cannot be used ([`object-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/object-src) and [`base-uri`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/base-uri))
- Only allows resources from the bundle for any other CSP-covered requests ([`default-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/default-src))

> [!NOTE]
> **Note:** For IWAs, `self` refers to resources loaded from the bundle. It excludes `blob:`, `filesystem:`, and other local schemes, as well as inline scripts.

    Content-Security-Policy: script-src 'self' 'wasm-unsafe-eval';
      connect-src 'self' https: wss: blob: data:;
      require-trusted-types-for 'script';
      frame-src 'self' https: blob: data:;
      img-src 'self' https: blob: data:;
      media-src 'self' https: blob: data:;
      font-src 'self' blob: data:;
      style-src 'self' 'unsafe-inline';
      object-src 'none';
      base-uri 'none';
      default-src 'self';

These CSPs aren't enough to fully protect against potentially malicious
third-party code. IWAs are also [cross-origin
isolated](https://web.dev/why-coop-coep/), setting headers to reduce the ability
of third-party resources to affect them:

- Only allow resources from the bundle or cross-origin resources explicitly marked as supporting [CORS](https://developer.mozilla.org/docs/Web/HTTP/CORS) with either a cross-origin resource policy (CORP) header set or the `crossorigin` attribute. ([`Cross-Origin-Embedder-Policy`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy))
- Disallow no-CORS cross-origin requests ([`Cross-Origin-Resource-Policy`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy))
- Process-isolate the browsing context from cross-origin documents, preventing window.opener references and global object access ([`Cross-Origin-Opener-Policy`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy))
- Prevent the site from being embedded within a frame or iframe (CSP, [`frame-ancestors`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors))

    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: require-corp
    Cross-Origin-Resource-Policy: same-origin
    Content-Security-Policy: frame-ancestors 'self'

Even with these restrictions in place, there's one more potential attack that
IWAs guard against: sequence breaking attacks. A sequence breaking attack
happens when malicious third-party content attempts to create a confusing and
potentially exploitable user experience by navigating to a page in an unexpected
way, like navigating directly to an internal settings page. IWAs prevent this by
disallowing arbitrary deep linking from external sites, only allowing
applications to be opened by navigating to well-defined entry points, like a
[`start_url`](https://developer.mozilla.org/docs/Web/Manifest/start_url),
a [protocol
handler](https://developer.chrome.com/articles/url-protocol-handler), a [share
target](https://web.dev/web-share/), or through a [launch
handler](https://developer.chrome.com/docs/web-platform/launch-handler).

### Locked down

Packaging and isolation provide a set of guarantees around what is allowed to
run and where it came from, but the dynamic nature of permissions on the web
means they alone can't ensure that a web application is only using the
capabilities it needs. Because different capabilities have different security
considerations, a user or administrator will want to audit what permissions an
IWA may use, just like they can do with other native apps like Android and iOS
before they install or update an app.

To facilitate this, Isolated Web Apps block all permission requests by default.
Developers can then opt-in to the permission they need by adding a
`permissions_policy` field to their Web App Manifest. This field contains
key/value pairs of [permission policy
directives](https://developer.mozilla.org/docs/Web/HTTP/Headers/Permissions-Policy#directives)
and [permission policy
allowlists](https://developer.mozilla.org/docs/Web/HTTP/Permissions_Policy#allowlists)
for each permission the IWA, *or any child frame* like a [Controlled Frame](https://developer.chrome.com/docs/iwa/controlled-frame) or an
iframe, may request. Adding a permission here does not automatically grant it;
instead it makes it available to be requested when a request for that capability
is made.

Consider you're building a fleet tracking IWA as an example. You may need your
IWA to be able to request the user's location, and for an embedded map to
request location, too. You may also want any embedded site to be able to go
fullscreen to give an immersive view for the user. To do so, you'd set up the
following permission policy in your Web App Manifest:

    "permissions_policy": {
       "geolocation": [ "self", "https://map.example.com" ],
       "fullscreen": [ "*" ]
    }

Because WebBundles can specify [Permissions
Policy](https://developer.mozilla.org/docs/Web/HTTP/Permissions_Policy)
headers, too, only permissions declared in both will be allowed, and then only
origins in the allowlists that are in both will be allowed.

## Named and versioned

Normal web apps rely on their [domain
name](https://developer.mozilla.org/docs/Learn/Common_questions/Web_mechanics/What_is_a_domain_name)
to identify themselves to users and can be updated by changing code that's
served at that domain. But because of the security constraints around Isolated
Web Apps, identity and updates need to be handled differently. Much like
Progressive Web Apps, Isolated Web Apps need a [Web App
Manifest](https://developer.mozilla.org/docs/Web/Manifest) file to
identify them to your users.

> [!TIP]
> **Tip:** An Isolated Web App's Web App Manifest isn't linked in the HTML because it needs to be discoverable at install time. It **must** be located at `/.well-known/manifest.webmanifest` and included in your IWA package.

### Web app manifest

Isolated Web Apps share the same [key manifest
properties](https://web.dev/articles/add-manifest#manifest-properties) for their
Web App Manifest as PWAs, with some slight variations. For example, `display`
works a little differently; both `browser` and `minimal-ui` are forced into a
`minimal-ui` display, and `fullscreen` and `standalone` are both forced into a
`standalone` display (additional `display_override` options work as expected).
In addition, there are two more fields that should be included, `version` and
`update_manifest_url`:

- `version`: **Required** for Isolated Web Apps. A string consisting of one or more integers separated by a dot (`.`). Your version can be something simple like `1`, `2`, `3`, etc..., or something complex like [SemVer](https://semver.org/) (`1.2.3`). The version number should match the regular expression `^(\d+.?)*\d$`.
- `update_manifest_url`: **Optional** , but recommended field that points to an HTTPS URL (or `localhost` for testing) where a Web Application Update Manifest can be retrieved.

A minimal Web App Manifest for an Isolated Web App may look something like this:

    {
      "name": "IWA Kitchen Sink",
      "version": "0.1.0",
      "update_manifest_url": "https://example.com/updates.json",
      "start_url": "/",
      "icons": [
        {
          "src": "/images/icon.png",
          "type": "image/png",
          "sizes": "512x512",
          "purpose": "any"
        },
        {
          "src": "/images/icon-mask.png",
          "type": "image/png",
          "sizes": "512x512",
          "purpose": "maskable"
        }
      ]
    }

### Web application update manifest

A Web Application Update Manifest is a JSON file that describes each version of
a given web application. The JSON object contains one required field, `version`,
which is a list of objects containing `version`, `src`, and `channels`:

- `version` - The version number of the application, same as the Web App Manifest's `version` field
- `src` - The HTTPS URL (or `localhost` for testing) pointing to the hosted bundle for that version (the `.swbn` file). Relative URLs are relative to the Web Application Update Manifest file.
- `channels` - A list of strings to identify the update channel this version is part of. A special `default` channel is used to describe the primary channel that will be used if no other channel is selected.

You can also include a `channels` field, an object of your channel IDs with an
optional `name` property for each ID to provide a human-readable name (including
for the `default` channel. A channel that doesn't include the `name` property,
or isn't included in the `channels` object, uses its ID as its name.

A minimal update manifest may look something like this:

    {
      "versions": [
        {
          "version": "5.2.17",
          "src": "https://cdn.example.com/app-package-5.2.17.swbn",
          "channels": ["next", "5-lts", "default"]
        },
        {
          "version": "5.3.0",
          "src": "v5.3.0/package.swbn",
          "channels": ["next", "default"]
        },
        {
          "version": "5.3.1",
          "src": "v5.3.1/package.swbn",
          "channels": ["next"]
        },
      ],
      "channels": {
        "default": {
          "name": "Stable"
        },
        "5-lts": {
          "name": "5.x Long-term Stable"
        }
      }
    }

In this example, there are three channels: `default` that will be labeled
`Stable`, `5-lts` that will be labeled `5.x Long-term Stable`, and `next` that
will be labeled `next`. If a user is on channel `5-lts`, they'll get version
`5.2.17`, if they're on channel `default` they'll get version `5.3.0`, and if
they're on channel `next` they'll get version `5.3.1`.

Web Application Update Manifests can be hosted on any server. Updates are
checked for every 4-6 hours.

## Admin managed

For their initial launch, Isolated Web Apps will only be able to be installed on
[Chrome Enterprise](https://chromeenterprise.google/) managed Chromebooks by an
administrator through the [Admin
panel](https://workspace.google.com/products/admin/).

To get started, from your Admin panel, go to **Devices \> Chrome \> Apps \&
extensions \> Users \& browsers** . This tab lets you add apps and extensions
from the Chrome Web Store, Google Play, and the web for users across your
organization. Adding items is done by opening the yellow floating add (`+`)
button on the bottom right corner of the screen and selecting the type of item
to add.

> [!TIP]
> **Tip:** You can only add items at the Organizational Unit (OU) level; if you haven't selected an OU in the sidebar panel on the **Apps \& extensions** page, or you aren't in the **Users \& browsers** tab, the add button won't show up.

When opened, there will be an icon of a square inside a square, labeled **Add an
Isolated Web App**. Clicking on it will open a modal to add an IWA to you OU. To
do so, you'll need two pieces of information: the IWA's Web Bundle ID (generated
from your app's public key and displayed after the app is bundled and signed)
and the URL to the Web App Update Manifest for the IWA. Once installed, you'll
have the Admin panel's standard set of options for managing it:

- **Installation policy**: How you want the IWA installed, either force installed, force installed and pinned to the ChromeOS shelf, or prevent installation.
- **Launch on login**: How you want the IWA launched, either allow a user to launch manually, force the IWA to launch when the user logs in, but let them close it, or force launch when the user logs in and prevent it from closing.

Once saved, the app will be installed the next time a policy update is applied
to Chromebooks in that OU. Once installed, a user's device will check for
updates from the Web App Update Manifest every 4-6 hours.

In addition to force-installing IWAs, you can also auto-grant some permissions
for them in a similar way you can for other web applications. To do so, go
**Devices \> Chrome \> Web capabilities** and click the **Add origin** button. In
the `Origin / site pattern field`, paste in the IWA's Web Bundle ID
(`isolated-app://` will automatically be added onto it as its protocol). From
there, you can set access levels to different APIs (allowed/blocked/unset),
including window management, local font management, and the [screen
monitoring](https://github.com/screen-share/capture-all-screens) API. For APIs
that may require additionyal opt-in from an administrator to enable, like the
mandatory screen monitoring API, an additional dialog will pop up to confirm
your selection. Once you're done, save your changes and your users will be ready
to start using your IWA!

## Work with extensions

While Isolated Web Apps don't work with extensions out of the box, you can
connect extensions you own to them. To do so, you'll need to edit the
extension's manifest file. The `externally_connectable` section of the manifest
defines which external web pages or other Chrome Extensions your extension can
interact with. Add your IWA's origin under the `matches` field within
`externally_connectable` (be sure to include the `isolated-app://` scheme):

    {
      "externally_connectable": {
        "matches": ["isolated-app://79990854-bc9f-4319-a6f3-47686e54ed29/*"]
      }
    }

While this will allow your extension to run in the Isolated Web App, it won't
allow it to inject content into it; you're limited to
[passing messages](https://developer.chrome.com/docs/extensions/develop/concepts/messaging#external-webpage)
between the extension and your IWA.