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

effect-playwright

v0.4.0

Published

An Effect-based Playwright library.

Readme

effect-playwright

NPM Version GitHub License Effect: yes Documentation

A Playwright wrapper for the Effect ecosystem. This library provides a set of services and layers to interact with Playwright in a type-safe way using Effect.

[!NOTE] This library is currently focused on using Playwright for automation and scraping. It does not provide a wrapper for @playwright/test (the test runner).

Installation

pnpm add effect-playwright playwright-core

or

npm install effect-playwright playwright-core

You can also install playwright instead of playwright-core if you want the post-build auto install of the browsers.

Quick Start

import { Playwright } from "effect-playwright";
import { Effect } from "effect";
import { chromium } from "playwright-core";

const program = Effect.gen(function* () {
  const playwright = yield* Playwright;
  const browser = yield* playwright.launchScoped(chromium);
  const page = yield* browser.newPage();

  yield* page.goto("https://example.com");
  console.log(`Page title: ${page.title()}`);
}).pipe(Effect.scoped, Effect.provide(Playwright.layer));

await Effect.runPromise(program);

Managing Lifecycle

Using launchScoped is the recommended way to manage the browser lifecycle. It ensures that the browser is closed automatically when the effect's scope ends, preventing resource leaks.

const program = Effect.gen(function* () {
  const playwright = yield* Playwright;
  const browser = yield* playwright.launchScoped(chromium);
  // Browser will be closed automatically after this block
}).pipe(Effect.scoped);

Connecting via CDP

You can connect to an existing browser instance using the Chrome DevTools Protocol (CDP).

const program = Effect.gen(function* () {
  const playwright = yield* Playwright;

  // Use connectCDPScoped to automatically close the CONNECTION when the scope ends
  // Note: This does NOT close the browser process itself, only the CDP connection.
  const browser = yield* playwright.connectCDPScoped("http://localhost:9222");

  const page = yield* browser.newPage();
  // ...
}).pipe(Effect.scoped);

If you need to manage the connection lifecycle manually, use connectCDP:

const program = Effect.gen(function* () {
  const playwright = yield* Playwright;
  const browser = yield* playwright.connectCDP("http://localhost:9222");

  // ... use browser ...

  yield* browser.close;
});

PlaywrightEnvironment (Experimental)

The PlaywrightEnvironment simplifies setup by allowing you to configure the browser type and launch options once and reuse them across your application.

Usage

import { PlaywrightBrowser } from "effect-playwright";
import { PlaywrightEnvironment } from "effect-playwright/experimental";
import { Effect } from "effect";
import { chromium } from "playwright-core";

const liveLayer = PlaywrightEnvironment.layer(chromium, {
  headless: false /** any other launch options */,
});

const program = Effect.gen(function* () {
  const browser = yield* PlaywrightBrowser;
  const page = yield* browser.newPage();

  yield* page.goto("https://example.com");
}).pipe(PlaywrightEnvironment.withBrowser);

await Effect.runPromise(program.pipe(Effect.provide(liveLayer)));

PlaywrightEnvironment.withBrowser

The withBrowser utility provides the PlaywrightBrowser service to your effect. It internally manages a Scope, which means the browser will be launched when the effect starts and closed automatically when the effect finishes (including on failure or interruption).

const program = Effect.gen(function* () {
  const browser = yield* PlaywrightBrowser; // Now available in context
  const page = yield* browser.newPage();

  // ...
  // Browser close is ensured
}).pipe(PlaywrightEnvironment.withBrowser);

Event Handling

You can listen to Playwright events using the eventStream method. This returns an Effect Stream that emits events as they occur.

[!NOTE] eventStream emits "Effectified" wrappers (e.g., PlaywrightRequest, PlaywrightResponse, PlaywrightPage) for most events. This allows you to continue using the Effect ecosystem seamlessly within your event handlers.

The stream is automatically managed and will close when the underlying resource (like the Page or Browser) is closed.

Example: Monitoring Network Requests

Since event streams run indefinitely until the resource closes, you often need to fork the resulting effect so it runs in the background without blocking your main program flow.

const program = Effect.gen(function* () {
  const browser = yield* PlaywrightBrowser;
  const page = yield* browser.newPage();

  // Create a stream of request events
  yield* page.eventStream("request").pipe(
    Stream.runForEach((request) =>
      Effect.gen(function* () {
        yield* Effect.log(`Request: ${request.url()}`);
      }),
    ),

    // Fork to run it in the background
    Effect.fork,
  );

  yield* page.goto("https://example.com");
}).pipe(PlaywrightEnvironment.withBrowser);

Accessing Native Playwright

If you need to access functionality from the underlying Playwright objects that isn't directly exposed, you can use the use method available on most services/objects (browsers, pages, locators).

import { Playwright } from "effect-playwright";
import { Effect } from "effect";
import { chromium } from "playwright-core";

const program = Effect.gen(function* () {
  const playwright = yield* Playwright;
  const browser = yield* playwright.launchScoped(chromium);
  const page = yield* browser.newPage();

  // Use the native Playwright Page object
  const screenshot = yield* page.use((p) => p.screenshot());
});

Error Handling

All methods return effects that can fail with a PlaywrightError. This error wraps the original error from Playwright. Note that Playwright does not support interruption, so Effect.timeout or similar code does not behave like you might expect. Playwright provides its own timeout option for almost every method.