Connect+Documentation
Extensions

Surfaces & calling the API

Backgrounds, popups, options, side panels, content scripts — and how to call the API and handle errors.

An extension can present several surfaces, all served over the privileged connect-extension://<id>/ origin, each in the extension's own per-profile session.

Surfaces

SurfaceManifestWhat it is
Backgroundbackground.entryA headless page with window.connect — the long-lived logic. Honors its lifecycle.
Action popupui.action.entryThe panel under the toolbar button. Tab-scoped: closes on tab switch.
Optionsui.options.entryA modal settings surface.
Side panelui.sidePanel.entryA docked panel; every extension with one gets a tab on the right-edge panel rail so users can open it. Also open/close from code via ui.sidePanel.
New-tab pageui.newTabReplaces the profile's new-tab page (needs newTab).
History viewui.historyPageReplaces the History popup's content (needs historyPage).
Favorites viewui.bookmarksPageReplaces the Favorites popup's content (needs bookmarksPage).
Content scriptscontentScriptsCode injected into pages you're granted host access to — see connect.scripting.

All extension-page surfaces get the full window.connect. Content scripts get a restricted subset (runtime + storage) — see connect.scripting.

Calling the API

Every method returns a Promise. A denied capability rejects with a clean error whose .code you can branch on:

try {
  await connect.history.list();
} catch (err) {
  if (err.code === 'CAPABILITY_DENIED') {
    const { granted } = await connect.capabilities.request(['history.read']);
    if (granted.includes('history.read')) return connect.history.list();
  }
  throw err;
}

Prefer capabilities.contains to branch before calling, so the expected "not granted" path doesn't throw.

Escape hatches

For anything not yet wrapped (or a new action you're entitled to), two primitives back the whole API:

connect.call(ns, action, payload?, opts?);   // dispatch any connect.<ns>.<action>
connect.onEvent(ns, action, cb);              // subscribe to any connect.<ns>.on<Event>

Everything in the API reference is sugar over these two.

Recipes

A few end-to-end patterns:

  • Ad/content blockernet.block + declarative rules; a popup with the master toggle and per-site tier.
  • Page theming / dark mode — a documentStart content script reading a per-host pref from the origin's localStorage (zero flash), plus a popup that pushes changes with tabs.sendMessage. Per-host truth in storage.
  • Tab session managertabs.query + storage to save/restore sets; live-refresh the popup on tabs.onActivated / onUpdated; bookmark all tabs with bookmarks.*.
  • Cross-extension coordination — two extensions share a { channel } grant and exchange state with channel.publish / subscribe.
  • Background that reacts to browsing — a suspendable background subscribing to tabs.onUpdated / webNavigation, re-arming from runtime.onGrantsChanged, using alarms for periodic work so it survives suspension.

On this page