npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wxt-dev/runner

v0.1.2

Published

Launch Chrome and Firefox with a web extension installed

Readme

@wxt-dev/runner

Programmatically open a browser and install a web extension from a local directory.

Usage

With WXT

[!WARNING] This package is intended to replace web-ext in the future, but it is not ready at the moment. Once it's ready for testing in WXT, more details will be added here.

// ~/wxt.runner.config.ts OR <project>/wxt.runner.config.ts
import { defineRunnerConfig } from 'wxt';

export default defineRunnerConfig({
  // Options go here
});

JS API

import { run } from '@wxt-dev/runner';

await run({
  extensionDir: '/path/to/extension',
  // Other options...
});

Features

  • Supports all Chromium and Firefox based browsers
  • Zero dependencies
  • One-line config for persisting data between launches

Requirements

@wxt-dev/runner requires a JS runtime that implements the WebSocket standard:

| JS Runtime | Version | | ---------- | ----------- | | NodeJS | ≥ 22.4.0 | | Bun | ≥ 1.2.0 |

You also need to have a specific version of the browser installed that supports the latest features so extensions can be loaded:

| Browser | Version | | -------- | -------- | | Chromium | Unknown | | Firefox | ≥ 139 |

TODO

  • [x] Provide install functions to allow hooking into already running instances of Chrome/Firefox
    • [ ] Try to setup E2E tests on Firefox with Puppeteer using this approach
    • [ ] Try to setup E2E tests on Chrome with Puppeteer using this approach

Options

Target

To open a specific browser, use the target option:

import { run } from '@wxt-dev/runner';

await run({
  extensionDir: 'path/to/extension',
  target: 'firefox',
});

Defaults to opening chrome. You may see type-hints for a list of popular browsers, but you can enter any string you want here.

Data Persistence

Browsers block you from using your normal browser profiles when using the BiDi and CDP protocols for security reasons.

To change how the new profile's data is saved between sessions, use the dataPersistence option:

import { run } from '@wxt-dev/runner';

await run({
  dataPersistence: 'user',
});
  • "none" (default): Use a brand new browser profile every time the browser is opened (stored in the system's tmp directory)
  • "project": Create a new profile that is re-used for your current directory (by default stored in .wxt-runner or .wxt/runner for WXT projects)
  • "user": Create a new profile that is re-used for all projects using @wxt-dev/runner (by default stored in $HOME/.wxt-runner)

These presets configure different flags for different operating systems when spawning the browser process.

If you want to customize your data persistence beyond what these presets define, you can override the browser flags yourself to configure persistence.

Browser Binaries

@wxt-dev/runner will look for browser binaries/executables in a hard-coded list of paths. It does not and will not explore your filesystem/$PATH to find where the browser is installed. That means there are times you will need to specify the path to a browser's binary on your system:

  • Your browser's path is non-standard or missing from the hard-coded list.
  • You want to use a specific version/release of the browser.
  • You're using a less popular browser and @wxt-dev/runner doesn't have hard-coded paths for it.

To do this, use the browserBinaries option and set the path to the browser's binary:

import { run } from '@wxt-dev/runner';

await run({
  extensionDir: 'path/to/extension',
  browserBinaries: {
    chrome: '/path/to/chrome',
    firefox: '/path/to/firefox',
  },
});

Arguments

To pass custom arguments to the browser on startup, use the chromiumArgs or firefoxArgs options:

import { run } from '@wxt-dev/runner';

await run({
  extensionDir: 'path/to/extension',
  chromiumArgs: ['--window-size=1920,1080'],
  firefoxArgs: ['--window-size', '1920,1080'],
});

Start URLs

To open specific URLs in tabs by default, you also use the chromiumArgs or firefoxArgs options.

Any URLs passed as a CLI argument will be opened in the browser when it starts.

import { run } from '@wxt-dev/runner';

await run({
  extensionDir: 'path/to/extension',
  chromiumArgs: ['https://example.com'],
  firefoxArgs: ['https://example.com'],
});

Debugging

To see debug logs, set the DEBUG env var to "@wxt-dev/runner". This will print the resolved config, commands used to spawn the browser, any messages sent on the browser's communication protocol, and more for you to debug.

@wxt-dev/runner:options User options: { extensionDir: 'demo-extension', target: undefined }
@wxt-dev/runner:options Resolved options: {
  browserBinary: '/usr/bin/chromium',
  chromiumArgs: [
    '--disable-features=Translate,OptimizationHints,MediaRouter,DialMediaRouteProvider,CalculateNativeWinOcclusion,InterestFeedContentSuggestions,CertificateTransparencyComponentUpdater,AutofillServerCommunication,PrivacySandboxSettings4',
    '--disable-component-extensions-with-background-pages',
    '--disable-background-networking',
    '--disable-component-update',
    '--disable-client-side-phishing-detection',
    '--disable-sync',
    '--metrics-recording-only',
    '--disable-default-apps',
    '--no-default-browser-check',
    '--no-first-run',
    '--disable-background-timer-throttling',
    '--disable-ipc-flooding-protection',
    '--password-store=basic',
    '--use-mock-keychain',
    '--force-fieldtrials=*BackgroundTracing/default/',
    '--disable-hang-monitor',
    '--disable-prompt-on-repost',
    '--disable-domain-reliability',
    '--propagate-iph-for-testing',
    '--remote-debugging-port=0',
    '--remote-debugging-pipe',
    '--user-data-dir=/tmp/wxt-runner-pWXLO1',
    '--enable-unsafe-extension-debugging'
  ],
  dataDir: '/tmp/wxt-runner-pWXLO1',
  dataPersistence: 'none',
  chromiumRemoteDebuggingPort: 0,
  extensionDir: '/home/aklinker1/Development/github.com/wxt-dev/wxt/packages/runner/demo-extension',
  firefoxArgs: [
    '--new-instance',
    '--no-remote',
    '--profile',
    '/tmp/wxt-runner-pWXLO1',
    '--remote-debugging-port=0',
    'about:debugging#/runtime/this-firefox'
  ],
  firefoxRemoteDebuggingPort: 0,
  target: 'chrome'
}
@wxt-dev/runner:chrome:stderr DevTools listening on ws://127.0.0.1:38397/devtools/browser/93dc4de5-64cb-4e0b-a9d3-7549527015f0
@wxt-dev/runner:cdp Sending command: {
  id: 1,
  method: 'Extensions.loadUnpacked',
  params: {
    path: '/home/aklinker1/Development/github.com/wxt-dev/wxt/packages/runner/demo-extension'
  }
}
@wxt-dev/runner:cdp Received response: { id: 1, result: { id: 'hckhakegfgenefhikdcfkaaonnclljmf' } }

Implementation Details

All this package does is spawn a child process to open the browser with some default flags before using remote protocols to install the extension.

Firefox

We use the new WebDriver BiDi protocol to install the extension. This just involves connecting to a web socket and sending a few messages.

Chrome

We use the CDP with --remote-debugging-pipe and --enable-unsafe-extension-debugging to install the extension by sending a message via IO pipes 3 and 4.

We don't use Webdriver Bidi because it's not built into Chrome yet. It requires us instantiating a separate child process for chromedriver. This is slower and more difficult than just using the CDP built into Chrome.