Browser extension APIs, made easier.
Write cleaner extension code with typed helpers, promise-based calls, and event listeners that are easy to manage. Spend less time on repetitive browser API plumbing and more time building your extension.
Built for Chrome and Chromium-based browsers, with MV2/MV3 compatibility helpers and selected Firefox support.
- Less boilerplate, clearer intent. Concise, consistent helpers like
getActiveTab()andcreateOrUpdateContextMenu()make everyday extension code easier to write, read, and discover in your editor. - Async code that reads naturally. Promise-based wrappers let you use
async/awaitwith callback-style Chrome APIs. - Events with easy cleanup. Every event helper returns an unsubscribe function
() => void, so you can stop listening as soon as the work is done. - TypeScript at every step. Types based on
@types/chrome, including explicit event parameter types, bring editor guidance to API calls and listeners alike. - Compatibility where it matters. Helpers handle MV2/MV3 and browser differences where applicable, including Action, Tabs MV2 helpers, and Sidebar.
- Import what you use. Named imports, small focused utilities, and a tree-shakable build (
sideEffects: false) let your bundler leave unused helpers out.
npm i @addon-core/browseryarn add @addon-core/browserpnpm add @addon-core/browserA few everyday extension tasks, from toolbar actions to content-script messaging.
import {setActionPopup, setBadgeText} from "@addon-core/browser";
await setActionPopup("popup.html");
await setBadgeText("ON");Use the same helper across manifest versions: setActionPopup() works with chrome.action in Manifest V3 and chrome.browserAction in Manifest V2.
import {getActiveTab, onTabUpdated} from "@addon-core/browser";
const tab = await getActiveTab();
const off = onTabUpdated((tabId, changeInfo) => {
if (tabId === tab.id && changeInfo.status === "complete") {
off();
}
});Listen for the update you need, then call off() to unsubscribe. Every event helper follows the same cleanup pattern.
import {createOrUpdateContextMenu, onContextMenusClicked, sendTabMessage} from "@addon-core/browser";
await createOrUpdateContextMenu("save-selection", {
title: "Save selection",
contexts: ["selection"],
});
const off = onContextMenusClicked(async (info, tab) => {
if (info.menuItemId !== "save-selection" || !tab?.id) {
return;
}
await sendTabMessage(tab.id, {
type: "save-selection",
text: info.selectionText,
});
});Create or update a menu with one call, then pass the selection to a content script. createOrUpdateContextMenu() avoids duplicate-menu errors during extension reloads, and sendTabMessage() keeps the background-to-content-script path promise-based.
Explore the API guides for available helpers, examples, and browser-specific details.
- action — MV2/MV3 compatible; under the hood uses
chrome.action(MV3) orchrome.browserAction(MV2) automatically. - alarms
- audio
- bookmarks — Bookmark trees, native editing and event subscriptions.
- browsingData
- commands
- contextMenus
- cookies
- declarativeNetRequest — Dnr methods for native rules, regex support and debug events.
- documentScan
- downloads
- extension
- history
- i18n
- identity — Chrome full support; Firefox, Edge, and Opera support the portable web auth flow; Safari is not supported.
- idle
- management
- notifications
- offscreen
- permissions
- runtime
- scripting
- search — Default-provider search and Firefox engine selection; Safari limitations and a Tabs API example.
- sidebar — Unified helpers for Chrome Side Panel (MV3) and Firefox/Opera
sidebarAction. - storage — via separate package: @addon-core/storage
- tabCapture
- tabGroups — Read, update and move tab groups, with native event subscriptions.
- tabs
- topSites — Most-visited sites with optional Firefox query settings.
- userScripts
- webNavigation
- webRequest
- windows
- env — Safe background-context detection with
isBackground(). - browserDetection — Best-effort browser detection with
BrowserName,BrowserFamily,guessBrowser(),isBrowser(), andisBrowserFamily().
- Google Chrome (MV2 & MV3)
- Microsoft Edge (Chromium)
- Opera (Chromium) — plus sidebar helpers
- Other Chromium-based browsers (e.g., Brave, Vivaldi, Arc, Yandex, Chromium) — expected to work; behavior aligns with Chrome.
- Firefox — partial support via compatible helpers (e.g.,
sidebarAction,runtime.getBrowserInfo) - Apple Safari — limited WebExtensions support; many Chromium-specific APIs are not available, so some helpers won’t work.
The package depends on @types/chrome@^0.3.5, which owns the global browser alias
(typeof chrome). Our declarations extend that shared API shape with Firefox-only
sidebarAction, runtime.getBrowserInfo, and search engine methods, plus the existing legacy APIs. They do
not redeclare the browser value. The previous type names
browser.runtime.BrowserInfo and browser.sidebarAction.ImageDataType remain available.
These declarations are a cross-browser superset, not a guarantee of runtime availability:
Chrome's browser alias does not provide Firefox-only APIs. Keep feature detection
when calling vendor-specific APIs directly. Applications with an explicit dependency on
older @types/chrome should update it to the same range to avoid mixing global declarations.
Test extension behavior with your preferred runner using @addon-core/browser/testing. It provides deterministic fixtures, configurable browser methods and events, stateful runtime/permissions/tabs/windows/scripting fakes, and reversible browser-global installation. Importing it never changes globalThis, and it has no dependency on Jest or another test runner.
Production API integration tests run in real Chromium and Firefox extensions through npm run test:browser.
See the browser test guide for setup, per-API scenarios and permission profiles.
For finer control, @addon-core/browser/utils exposes the low-level utilities used primarily inside the package for error handling, promise management, and listener safety.
For a complete list of utility functions and examples, see the Utilities Documentation.
The following commonly used WebExtensions/Chrome Extension APIs are not wrapped yet. Chrome OS–only APIs are intentionally omitted.
Want to help expand coverage? See CONTRIBUTING.md to get started, or open an issue to discuss an API you need.
- contentSettings
- declarativeContent
- desktopCapture
- devtools.* (inspectedWindow, network, panels)
- dns
- fontSettings
- omnibox
- pageCapture
- platformKeys
- power
- privacy
- proxy
- sessions
- system.cpu
- system.memory
- system.storage
- tts
- ttsEngine
The 0.x series is a period of shaping the package's public API contracts and working toward comprehensive coverage
of currently available WebExtension and Chrome APIs. Method signatures, TypeScript types, and runtime behavior may
change. Minor releases in 0.x may include breaking changes (for example, 0.9.0 → 0.10.0).
The first stable release will be 1.0.1. It will be released through an explicit maintainer decision when the
public API contracts are ready. From stable 1.x onward, breaking changes require a major release
(for example, 1.4.0 → 2.0.0), while minor releases add backward-compatible functionality.
Patch releases preserve backward compatibility at every version, including public TypeScript types and runtime behavior.
Version 1.0.0 was published with an incorrect version number and does not mark a stable API contract.
Development continues on 0.x; the replacement release is 0.10.0. Consumers of 1.0.0 must explicitly change
their dependency to 0.10.0 (or the range below) and update their lockfile. Existing ^1.0.0 ranges do not accept 0.x.
To allow only patch updates within a chosen minor version, use ~ in your application's package.json:
{
"dependencies": {
"@addon-core/browser": "~0.10.0"
}
}~0.10.0 allows 0.10.1, 0.10.2, and later 0.10.x patches, but excludes 0.11.0 and 1.x.
Use "0.10.0" without a prefix to pin one exact version. For this 0.10.x range, ^0.10.0 also allows only patch updates.
Before upgrading, review the Release Notes for breaking changes and migration instructions. Commit your lockfile for reproducible installs; the version range determines which updates are allowed when you update dependencies. See the versioning policy for details.