ReaderClient

Constructor, options, methods, and lifecycle for the main Reader API.

ReaderClient is the high-level API you'll use for 99% of Reader workloads. It owns the Playwright pool and the browser instances, exposes scrape() and crawl(), and handles lazy initialization.

Constructor

new ReaderClient(options?: ReaderClientOptions)

The constructor does not touch the browser. It only stores configuration. Initialization happens lazily on the first scrape() or crawl() call.

ReaderClientOptions

interface ReaderClientOptions {
  verbose?: boolean;
  showChrome?: boolean;
  browserPool?: BrowserPoolConfig;
  proxies?: ProxyConfig[];
  proxyPools?: ProxyPoolConfig;
  proxyRotation?: "round-robin" | "random";
  skipTLSVerification?: boolean;
}
OptionTypeDefaultDescription
verbosebooleanfalseEnable Pino logging
showChromebooleanfalseShow the browser window (debugging)
browserPoolBrowserPoolConfig{ size: 2 }Browser pool configuration
proxiesProxyConfig[]-Flat proxy list for round-robin rotation
proxyPoolsProxyPoolConfig-Multi-tier proxy pools (standard/datacenter, premium/residential)
proxyRotation"round-robin" | "random""round-robin"Rotation strategy within a pool
skipTLSVerificationbooleantrueSkip TLS certificate verification

See BrowserPoolConfig and ProxyConfig for the nested types.

Methods

async start(): Promise<void>

Pre-warm the client. Initializes the Playwright pool and browser instances without running a scrape. Optional - scrape() and crawl() will initialize automatically if you haven't called start().

async scrape(options: ScrapeOptions): Promise<ScrapeResult>

Scrape one or more URLs. See ScrapeOptions and ScrapeResult.

async crawl(options: CrawlOptions): Promise<CrawlResult>

Discover and optionally scrape pages on a site. See CrawlOptions and CrawlResult.

isReady(): boolean

Returns true if the client has been initialized (via start() or a prior scrape()/crawl() call).

async close(): Promise<void>

Shut down browsers and release resources. Auto-runs on process exit - call explicitly for fast cleanup.

hasProxyTier(tier: "datacenter" | "residential"): boolean
getProxyForTier(tier: "datacenter" | "residential"): ProxyConfig | undefined

Helpers for checking proxy pool availability. Useful when you want to gate behavior on whether a residential pool is configured.

Lifecycle

ReaderClient is lazy by design:

  1. new ReaderClient() - constructor does nothing expensive
  2. First call to scrape() or crawl() - triggers Playwright pool startup and browser initialization (1-2 seconds)
  3. Subsequent calls - reuse the warm pool
  4. Auto cleanup on SIGTERM/SIGINT/process exit
  5. Explicit close() - tears down browsers immediately

Reuse a single client instance for the lifetime of your process. Don't create-and-close per request.

Server pattern

import { ReaderClient } from "@vakra-dev/reader";
import express from "express";

const reader = new ReaderClient({
  browserPool: { size: 5 },
});

const app = express();
app.use(express.json());

app.post("/scrape", async (req, res) => {
  try {
    const result = await reader.scrape({
      urls: [req.body.url],
      formats: ["markdown"],
    });
    res.json(result);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

process.on("SIGTERM", async () => {
  await reader.close();
  process.exit(0);
});

app.listen(3001);

Where to go next