Skip to content

Extension APIs

WXT is built on top of webextension-polyfill, which uses the standard browser global.

If you're used to Chrome's chrome global, its a simple switch:

  1. Replace chrome with browser
  2. Replace callbacks with async/await

And that's it! Your extension now supports Chrome, Firefox, Safari, Edge, and other Chromium browsers.

Basic Usage

The browser variable is available globally via auto-imports, or it can be imported manually.

import { browser } from 'wxt/browser';

The wxt/browser module exports a customized version of webextension-polyfill's browser with improved typing.


Let's save the date the extension was installed. Just like chrome, some APIs require the permission is added to your manifest before the API is defined. Here, we need to add the storage permission to your manifest.

// wxt.config.ts
import { defineConfig } from 'wxt';

export default defineConfig({
  manifest: {
    permissions: ['storage'],

Then we can use to save the install date to local storage.

// background.ts
export default defineBackground(() => {
  browser.runtime.onInstall.addEventListener(({ reason }) => {
    if (reason === 'install') {{ installDate: });


Follow Chrome's message passing guide to understand how message passing works in web extensions. In Google's examples, just replace chrome with browser, and it will work in WXT.

Here's a basic request/response example:

// popup/main.ts
const res = await browser.runtime.sendMessage('ping');

console.log(res); // "pong"
// background.ts
export default defineBackground(() => {
  browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
    console.log(message); // "ping"

    // Wait 1 second and respond with "pong"
    setTimeout(() => sendResponse('pong'), 1000);
    return true;

There are a number of message passing libraries you can use to improve the message passing experience.

Here are some that are compatible with WXT (because they are based off webextension-polyfill as well):

Browser Differences

Some APIs are only available on certain browsers or manifest versions. You will have to check if an API exists at runtime if it is not in the browser standard.

if ('session' in {
  // Do something with the non-standard session storage API

If you're using TypeScript, knowing what is non-standard is easy! APIs that are not typed are non-standard.