Extensions
The manifest
Every connect.json field — identity, background, and the ui surfaces.
Every extension has a connect.json at its root, validated at load time (unknown keys are
rejected). It declares the extension's identity, the surfaces it presents, and the
capabilities it requests.
Fields
| Field | Required | Type | Notes |
|---|---|---|---|
manifestVersion | ✅ | 1 | Only 1 today. |
id | ✅ | string | Reverse-DNS-ish, e.g. com.example.hello. Immutable identity; also the on-disk dir name and the connect-extension://<id> origin. |
name | ✅ | string | Display name. |
version | ✅ | string | Dotted-numeric (1.2.10). Updates compare these numerically. |
apiVersion | ✅ | string | The connect.* API generation you target ("1"). |
description | string | Shown in the manager and store. | |
icons | { [size]: path } | Toolbar / manager icon; the shell picks the size nearest a toolbar slot. | |
background | object | A headless script — see below. | |
contentScripts | array | Static content scripts — see connect.scripting. | |
ui | object | Surfaces: action, sidePanel, options, newTab, historyPage, bookmarksPage, panels — see below. | |
capabilities | array | The capabilities you request — see Capabilities & consent. | |
commands | object | Keyboard shortcuts — see connect.commands. | |
default_locale | string | Fallback locale for connect.i18n (needs _locales/<default_locale>/messages.json). | |
key | string | Pinned signing key (base64 SPKI/DER) — the update trust anchor. See Packaging & trust. | |
updateUrl | string (http/https) | Where to check for updates. See Packaging & trust. |
background
"background": {
"entry": "background.js", // required: your background script
"lifecycle": "suspendable", // persistent | suspendable | ephemeral
"substrate": "renderer" // renderer (default) | worker (first-party only)
}| Lifecycle | Behaviour |
|---|---|
persistent | Stays resident for the profile's lifetime. |
suspendable | Starts at boot; after ~30s idle it's told runtime.onSuspend and torn down, then woken by a subscribed event (told runtime.onResume). There is no event replay — re-establish state on resume/boot. |
ephemeral | Not started at boot; spun up on a wake event, torn down on idle. |
substrate: "worker" runs the background in a worker_threads compute host —
far lighter than a renderer, faster to wake, no DOM/window. First-party
(root-signed) extensions only: a worker cannot be sandboxed like a renderer, so any
other trust level is refused and gets the sandboxed renderer. The worker's connect
surface is call/onEvent plus runtime/storage/alarms sugar (no Ports).
ui
"ui": {
"action": { "entry": "popup.html", "defaultTitle": "…", "width": 360, "height": 520 },
"options": { "entry": "options.html" },
"sidePanel": { "entry": "panel.html" },
"panels": [{ "id": "…", "entry": "…", "title": "…" }]
}action.entryis optional: omit it for a popup-less button that firesaction.onClickedinstead.action.width/heightseed the popup (bounded 150–800 × 100–600); resize it live withui.setPopupSize.
Next
- Capabilities & consent — declare what your extension can do.
- Surfaces & calling the API — wire the pieces together.