In-process Chromium rendering pool · Node.js

Screenpool

A lightweight in-process rendering pool for Node.js. Runs Chromium once, maintains a fixed set of isolated worker tabs, queues render jobs, and returns screenshots, PDFs, or parsed structured data.

Full reference (mirrors README) — open this file locally or from the repo. Requires Node.js 20+.

Why?

Spawning and killing Chromium processes on every render job creates high CPU overhead and memory leaks. Screenpool launches Chromium once and allocates concurrent jobs to a fixed pool of isolated context tabs, recycling contexts on crash/timeout and blanking pages after runs to guarantee bounded resource usage.

Ideal when…

  • You need bounded memory and CPU resource limits
  • Rendering hundreds of screenshots or PDFs concurrently
  • Scraping and extracting structured data with full JS execution
  • Integrating with AI coding tools via stdio MCP protocol

Core mechanics

  • Fixed-size BrowserContext and tab workers
  • Navigation blanking and cookie clearance
  • Memory pressure checks with auto-recycling
  • Built-in local network SSRF security checks

Features

Installation

Requires Node.js 20+.

npm install screenpool

Note: Screenpool automatically discovers installed Chrome/Chromium on macOS, Linux, Windows, or PATH. If no browser is found, it automatically downloads chrome@stable into ~/.screenpool/browser on first run.

Quick start

import { ScreenPool } from 'screenpool';

// Create a pool
const pool = new ScreenPool({
  browser: 'chrome@stable',
  poolSize: 4,
  memory: { limitMb: 512 }
});

await pool.start();

// Take a screenshot
const result = await pool.screenshot({
  url: 'https://example.com',
  viewport: { width: 1200, height: 630 },
  format: 'webp',
  quality: 80
});

// Do something with the buffer
console.log(result.buffer); // => 
console.log(result.contentType); // => 'image/webp'

// Stop the pool gracefully
await pool.stop();

Browser Connection Options

Screenpool supports several ways to resolve or connect to a browser. Define these in the top-level configuration options:

MethodDescriptionExample Config
executablePath System file path to a Chromium/Chrome binary. { executablePath: '/usr/bin/chromium' }
browser Browser shorthand string or configuration resolved via @puppeteer/browsers cache. { browser: 'chrome@stable' }
browserWSEndpoint Connects to an already running browser using its WebSocket debugging endpoint URL. { browserWSEndpoint: 'ws://127.0.0.1:9222/devtools/browser/...' }
browserURL Connects to an already running browser using its local debugging port URL. { browserURL: 'http://localhost:9222' }
browserInstance Directly pass an existing Puppeteer Browser instance. Lifecycle is managed by user. { browserInstance: existingBrowser }

API Reference

new ScreenPool(config)

OptionDefaultDescription
poolSize4Number of concurrent worker pages/tabs to maintain.
maxQueueSize100Maximum number of pending render jobs to queue before failing with QueueOverflow.
jobTimeout15000Timeout in ms for single render jobs.
workerRestartAfterJobs500Recycle worker tab/context after this many completed jobs (0 disables).
allowLocalhostfalseWhether to allow renders from localhost URLs.
allowPrivateNetworksfalseWhether to allow rendering URLs resolving to private subnets.
allowFileProtocolfalseWhether to allow local file paths (file://).
defaultViewport{ width: 1280, height: 720 }Default viewport settings applied to worker pages on start/recycle.
memory.limitMbUpper limit on browser RSS usage in MB. Blocks jobs if exceeded.
memory.v8HeapMbLimits Chromium V8 engine heap size via launch arguments.

Methods

Browser Action Architecture & Record API

Screenpool provides a strict, observation-based browser action engine and session recorder for interactive multi-step flows, popup windows, OAuth logins, and web recording.

Session API Example

import { ScreenPool } from 'screenpool';

const pool = new ScreenPool({ poolSize: 2 });
await pool.start();

// 1. Create an isolated session
const session = await pool.sessions.create({
  pages: { maxPages: 5, onPopup: 'register', onActivePageClosed: 'activate-opener' },
});

// 2. Start recording
const recording = await session.record.start({ preset: 'debug', screenshots: 'each-action' });

// 3. Navigate and Observe
await session.goto('https://example.com');
const obs = await session.observe({ screenshot: true, elements: true });

// 4. Execute Action Sequence
const actResult = await session.act({
  observationId: obs.id,
  actions: [
    {
      type: 'click',
      target: { by: 'role', role: 'button', name: 'Open Auth' },
      expect: { page: { event: 'popup', alias: 'oauth-login', activate: true } }
    }
  ]
});

// 5. Stop Recording & Close
const manifest = await recording.stop();
await session.close();
await pool.stop();

Security (SSRF Protection)

Chromium renders page links on your server. To prevent users from requesting internal resources, Screenpool includes built-in SSRF checks blocking loopback interfaces (localhost, 127.0.0.1), private IPs (10.0.0.0/8, 192.168.0.0/16), link-local subnets, and AWS/cloud metadata services (169.254.169.254).

To allow local testing or developer instances, enable access explicitly during initialization:

const pool = new ScreenPool({
  allowLocalhost: true,        // Allow localhost and loopback resolving
  allowPrivateNetworks: true,  // Allow access to standard private ranges (192.168.X.X, etc.)
  allowFileProtocol: true      // Allow opening file:// paths on the host system
});

HTTP Server

Screenpool packages a Hono-based HTTP server to daemonize screenshotting and rendering services.

import { ScreenPool } from 'screenpool';
import { createScreenPoolServer } from 'screenpool/http';

const pool = new ScreenPool({ browser: 'chrome@stable' });
await pool.start();

const server = createScreenPoolServer(pool, { port: 3000, host: '0.0.0.0' });
await server.listen();

API Endpoints

EndpointMethodDescription
/screenshotPOSTRender a screenshot of URL or raw html. Returns image payload.
/pdfPOSTRender a PDF. Returns application/pdf payload.
/html-to-imagePOSTRender raw html payload. Requires html in request body.
/html-to-pdfPOSTRender raw html to PDF. Requires html in request body.
/extractPOSTExtract structured JSON using Pipsel rules.
/statsGETReturns current server pool statistics JSON.
/healthGETChecks browser connection state and system memory status.

Model Context Protocol (MCP) Server

Screenpool includes built-in Model Context Protocol (MCP) server capabilities over stdio. This enables AI coding assistants (Claude Code, Cursor, VS Code MCP clients, Antigravity, etc.) to perform web rendering, screenshot capture, PDF generation, HTML extraction, and health monitoring.

Quick Run

# Run MCP server via npx
npx screenpool mcp

# Run using installed binary
screenpool mcp

# Standalone binary
screenpool-mcp

MCP Tools

Tool NameDescription
screenpool_screenshotCapture web page screenshot (png, jpeg, webp, fullPage, viewport, selector).
screenpool_pdfRender web page as PDF (A4, Letter, landscape, margins).
screenpool_htmlExtract client-side rendered HTML after JS execution (with truncation support).
screenpool_metadataExtract page title, meta description, and canonical URL.
screenpool_session_createCreate an isolated browser session with multi-page tracking.
screenpool_session_pagesList managed pages in session and active/main status.
screenpool_session_closeClose active browser session and release isolated context.
screenpool_observeCapture page observation state including interactive element IDs and compact DOM.
screenpool_actExecute strict, verifiable browser actions (click, fill, press, select, scroll, wait, page actions).
screenpool_runStateless browser action run in a temporary session.
screenpool_record_startStart session recording (events jsonl, action screenshots, and video).
screenpool_record_stopStop session recording and return recording manifest.
screenpool_record_getGet active session recording status.
screenpool_healthView worker pool health status, active jobs, uptime, and queue length.
screenpool_capabilitiesInspect supported formats, tool list, and version information.
screenpool_helpStructured documentation, parameter guides, diagnostics presets, and examples.

Client Configuration Example

{
  "mcpServers": {
    "screenpool": {
      "command": "npx",
      "args": [
        "-y",
        "screenpool",
        "mcp",
        "--pool-size",
        "3",
        "--timeout",
        "30000"
      ]
    }
  }
}

CLI Reference

Command line interface tools for quick scripts, daemons, and MCP server:

# Start MCP Server for AI tools over stdio
screenpool mcp --pool-size 3 --timeout 30000

# Take a screenshot and write to out.png
screenpool screenshot https://example.com --out out.png --width 1280 --height 720

# Connect to an existing browser via remote debugging and take a screenshot
screenpool screenshot https://example.com --browser-url http://localhost:9222 --out out.png

# Render a PDF using a custom Chromium binary path
screenpool pdf https://example.com --executable-path /usr/bin/chromium --out page.pdf

# Start HTTP Server daemon on port 3000
screenpool server --port 3000 --pool-size 4

# Start server daemon with interactive web UI panel
screenpool ui --port 3000

Architecture

┌────────────────────────────────────────────────────────────────┐
│                          ScreenPool                            │
├────────────────────┬────────────────────┬──────────────────────┤
│    JobQueue        │   HealthMonitor    │    WorkerPool        │
│                    │                    │  ┌────────────────┐  │
│  [Job1, Job2...]   │  (Memory / RSS)    │  │ ScreenWorker 0 │  │
│                    │                    │  │ ScreenWorker 1 │  │
│                    │                    │  │ ScreenWorker 2 │  │
│                    │                    │  │ ScreenWorker 3 │  │
│                    │                    │  └────────────────┘  │
├────────────────────┴────────────────────┴──────────────────────┤
│                        BrowserManager                          │
├────────────────────────────────────────────────────────────────┤
│            Puppeteer (Connect/Launch Contexts)                 │
├────────────────────────────────────────────────────────────────┤
│                    Chromium Browser Process                    │
└────────────────────────────────────────────────────────────────┘

Development & testing

The codebase uses Vitest for integration and unit testing.

npm run test
npm run test:watch

Build output files using tsup before distributing: npm run build.