v150 · sub apps
Manifest-id round trip
A sub app is identified by a stable ManifestId. That single string threads through the whole lifecycle: add() returns it, list() is a record keyed by it (mapping to { appName }), and remove() consumes it. This demo runs the real list() and remove() calls and shows the identity moving between them.
Real API requirement:
window.subApps.list() and remove() only exist inside a secure Isolated Web App with the sub-apps permission policy — currently ChromeOS-only for end users, with the developer-trial flags (#enable-isolated-web-apps, #enable-isolated-web-app-dev-mode, #enable-sub-apps) and an install via chrome://web-app-internals. ChromeStatus (API, updated 2026-07-24) targets default-on at Chrome 152 (status text “Proposed”). On this origin the binding is absent, so the demo reports that and falls back to a clearly-labelled illustrative inventory so the round trip is still legible.
Inventory and remove by manifest id
| Select for removal | ManifestId | appName |
|---|
how identity flows
add(install_paths)resolves toinstalledApps: { [installPath]: ManifestId }— the install path is your input, the ManifestId is the durable handle you keep.list()resolves torecord<ManifestId, { appName }>— the ManifestId is the record key, so it is the join column between calls.remove(manifest_ids)takes those same ManifestIds and resolves to{ removedApps: ManifestId[], failedApps: { [ManifestId]: DOMException } }. A ManifestId that belongs to a different parent IWA fails withNotFoundError.
code path
const installed = await window.subApps.list(); // record<ManifestId, {appName}>
const ids = Object.keys(installed); // ["/mail/", "/calendar/", ...]
const { removedApps, failedApps } = await window.subApps.remove(selectedIds);
// removedApps: ManifestId[] failedApps: record<ManifestId, DOMException>
see also
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗