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

playwright-crx-open

v0.15.29

Published

Playwright Chrome Extension with exposed internals for advanced state management and precise control. A fork of playwright-crx with all internal state accessible for library consumers who need full control over the lifecycle.

Readme

Playwright CRX Open

A fork of playwright-crx with exposed internals for advanced state management and precise control.

This package contains the Chrome Extensions flavor of the Playwright library, with all internal state accessible for library consumers who need full control over the lifecycle.

Why This Fork?

The original playwright-crx heavily encapsulates its internal state, making it difficult to:

  • Clean up stale state when used as a library
  • Recover from errors without reloading the extension
  • Reattach to tabs without creating new ones
  • Precisely control the debugger lifecycle

This fork exposes all internal state and provides utility methods for:

  • State inspection: Access internal maps, caches, and singleton references
  • State manipulation: Clear cached state, reset connections, force reattachment
  • Lifecycle control: Precise control over when resources are created and destroyed

Installation

npm install playwright-crx-open

Key Differences from playwright-crx

Exposed Internal State

All internal state is now accessible via public properties:

import { crx } from 'playwright-crx-open';

const crxApp = await crx.start();

// Access internal state directly
console.log(crx._transport);           // CrxTransport instance
console.log(crx._browserPromise);      // Browser promise
console.log(crx._crxApplicationPromise); // Regular mode app promise

// Access transport internals
const transport = crxApp.getTransport();
console.log(transport._tabToTarget);   // Map<tabId, targetInfo>
console.log(transport._targetToTab);   // Map<targetId, tabId>
console.log(transport._sessions);      // Map<sessionId, tabId>

New Utility Methods

On Crx class:

// Check if started without throwing
if (crx.isStarted()) {
  // ...
}

// Clear cached promise without closing (use with caution)
crx.clearApplicationPromise();

// Full reset - closes everything and clears all state
await crx.reset();

On CrxApplication class:

// Force attach - clears cached state first
const page = await crxApp.forceAttach(tabId);

// Check if closed
if (crxApp.isClosed()) {
  // ...
}

// Reset closed state (use with caution)
crxApp.resetClosedState();

// Clear recorder app reference
crxApp.clearRecorderApp();

// Get parent instances
const crx = crxApp.getCrx();
const transport = crxApp.getTransport();

On CrxTransport class:

const transport = crxApp.getTransport();

// Clear all cached mappings
transport.clearMappings();

// Clear specific tab
transport.clearTab(tabId);

// Get all attached tabs
const tabIds = transport.getAttachedTabIds();

// Get all targets
const targets = transport.getAllTargets();

// Check if attached
if (transport.isAttached(tabId)) {
  // ...
}

// Force detach with cache clearing
await transport.forceDetach(tabId);
await transport.forceDetachAll();

Common Use Cases

Reattaching to a Tab

When you need to reattach to a tab that was previously attached (e.g., after navigation or error):

// Instead of this (may return stale cached data):
const page = await crxApp.attach(tabId);

// Use this (clears cache first):
const page = await crxApp.forceAttach(tabId);

Recovering from Errors

try {
  await crxApp.recorder.run(code);
} catch (error) {
  // Clear transport state
  crxApp.getTransport().clearMappings();

  // Or do a full reset
  await crx.reset();

  // Start fresh
  const newApp = await crx.start();
}

Cleanup on Extension Reload

// In your background script startup:
const cleanupOrphanedDebuggers = async () => {
  const targets = await chrome.debugger.getTargets();
  const attached = targets.filter(t => t.attached && t.tabId);
  for (const target of attached) {
    await chrome.debugger.detach({ tabId: target.tabId }).catch(() => {});
  }
};

await cleanupOrphanedDebuggers();

Original API

This fork maintains full compatibility with the original playwright-crx API:

import { crx, expect } from 'playwright-crx-open/test';

chrome.action.onClicked.addListener(async ({ id: tabId }) => {
  const crxApp = await crx.start({ slowMo: 500 });

  try {
    const page = await crxApp.attach(tabId!).catch(() => crxApp.newPage());

    await page.goto('https://demo.playwright.dev/todomvc/#/');
    await page.getByPlaceholder('What needs to be done?').click();
    await page.getByPlaceholder('What needs to be done?').fill('Hello World!');
    await page.getByPlaceholder('What needs to be done?').press('Enter');

    await expect(page.getByTestId('todo-title')).toHaveText('Hello World!');
  } finally {
    await crxApp.detach(page);
    await crxApp.close();
  }
});

Tracing

Playwright CRX also supports tracing, compatible with Playwright Trace Viewer.

await page.context().tracing.start({ screenshots: true, snapshots: true });

await page.goto('https://demo.playwright.dev/todomvc');
// ... perform actions ...

await page.context().tracing.stop({ path: '/tmp/trace.zip' });
const data = crx.fs.readFileSync('/tmp/trace.zip');

Build

To build playwright-crx-open:

npm ci
npm run build

Credits

This is a fork of playwright-crx by Rui Figueira.

License

Apache-2.0