Reader: A Playwright-Based Scraping Engine That Hands Agents Clean Markdown
Open source web infrastructure for AI. Scrape, crawl, and automate the web, clean markdown, browser sessions, ready for your agents.
At a glance
- What is it?
- vakra-dev/reader packages browser pooling, proxy tiers and anti-detection behind three TypeScript primitives: scrape, crawl and browser. It is Apache-2.0 and self-hostable, but the README leaves operational details thin.
- Who is it for?
- Adopt Reader if you already run Node.js 18 or later and want scraping, crawling and a CDP-controlled browser behind one client instead of assembling Puppeteer with stealth plugins yourself. Do not adopt it if you need documented, stable configuration for proxy rotation and browser recycling, because the README does not expose those knobs.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 27 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The Gap Reader Claims to Fill Between Puppeteer and Production
The README opens with a complaint rather than a feature list: building agents that need web access means piecing together Puppeteer, adding stealth plugins, fighting Cloudflare and managing proxies, and it still breaks in production. The project's own framing is that rendering a page and converting HTML to markdown is the easy part. What sits underneath is browser architecture at scale, anti-bot bypass for Cloudflare, Turnstile and JS challenges, TLS fingerprinting, proxy rotation with sticky sessions, browser pooling with memory limits, and rate limiting, retries and caching. Reader is aimed at engineers who would otherwise write that layer themselves. It is a Node.js and TypeScript library, published as @vakra-dev/reader on npm, with a separate cloud client at @vakra-dev/reader-js for people who would rather use a hosted API key from console.reader.dev than run the engine. The self-hosted path is the one worth examining, because that is where the operational cost lands on you.
Three Primitives: scrape, crawl and browser
The README reduces the surface to three calls. scrape takes a urls array and returns results whose first entry exposes markdown and html fields. crawl takes a single url plus depth, maxPages and a scrape boolean, and returns discovered urls along with a scraped object. browser returns a session object with a wsEndpoint, which you pass to chromium.connectOverCDP from playwright-core, then reach into browser.contexts()[0].pages()[0] to drive the page directly. The claim that makes browser interesting is that the launched Chrome already has stealth active: webdriver set to false, navigator spoofing and WebRTC masking. If that holds, an existing Playwright script needs one changed line, from launching a local browser to connecting over CDP to the session endpoint. The README does not describe how the session is torn down beyond calling session.close(), nor whether the underlying browser instance returns to a pool or is destroyed. That distinction matters for long-running agents and it is not answered in the material provided.
Getting It Running: Install, Chromium and the First Scrape
Installation is two commands. npm install @vakra-dev/reader pulls the library, and the README states the requirement as Node.js >= 18. The first run needs a browser binary, and the README instructs npx playwright install chromium, noting that Playwright bundles Chromium for all platforms. That step is the one most likely to fail in a container: it downloads a browser build, so a slim image without the system libraries Chromium expects will install successfully and then fail at launch. The README does not list those dependencies. From there, the basic scrape example constructs new ReaderClient() with no arguments, calls scrape with urls and formats set to ["markdown", "html"], reads result.data[0].markdown and result.data[0].html, and closes with await reader.close(). Batch work adds batchConcurrency, shown as 3, plus an onProgress callback that receives completed, total and currentUrl, and the result carries batchMetadata.successfulUrls. Crawling uses depth, maxPages and scrape, and reports result.urls.length and result.scraped?.batchMetadata.successfulUrls. Note the optional chaining on scraped: the README does not say when that field is absent, so treat it as possibly undefined.
Where the Documentation Stops and You Start Guessing
The feature list promises tiered proxies with standard and premium pools, health tracking, browser auto-recycling and memory limits. The code examples never show a single configuration key for any of it. ReaderClient is constructed with no options in every self-hosted snippet, and no config file, environment variable or option name for proxy credentials, pool size or recycling thresholds appears anywhere in the README. The same gap applies to retries, timeouts, caching and rate limiting, all named as concerns in the problem table but absent from the API surface shown. This is a real limitation, not a nitpick: if proxy rotation is configured somewhere, you cannot learn how from the material provided, and you will be reading the source or the docs site at docs.reader.dev to find out. The README also promises smart content cleaning that removes nav, headers, footers, popups and cookie banners, with no way to inspect or override what was stripped. For a pipeline where the extracted text feeds an LLM prompt, silent removal of a section you needed is hard to detect.
Cloud Client Versus Self-Hosted Engine
The two packages are not interchangeable. @vakra-dev/reader-js is the cloud client, constructed with an apiKey from process.env.READER_API_KEY, and it calls read rather than scrape. Its return value is a discriminated union: the example checks if (result.kind === "scrape") before reading result.data.markdown, which implies other kinds exist for other operations. The self-hosted @vakra-dev/reader calls scrape, crawl and browser directly and returns plain result objects with no kind tag. So code written against one package will not compile against the other, even though both are exported as ReaderClient. The trade-off is straightforward. The cloud route gets you an API key and no browser to install, at the cost of sending every URL you scrape to someone else's infrastructure. The self-hosted route keeps the traffic on your machines but makes you responsible for Chromium, memory and the proxy pool. The README does not state whether the cloud client is a thin wrapper over the same engine or a different implementation.
The Honest Alternative: Writing the Playwright Layer Yourself
The direct alternative is Playwright plus a stealth plugin plus your own proxy rotation, which is exactly the stack the README describes as the problem. The difference in approach is where the abstraction sits. A hand-rolled setup gives you a page object and total control: you decide when the browser launches, which context options apply, how cookies persist, and what gets logged when a challenge page appears. Reader instead gives you a client that owns the browser lifecycle and returns markdown, with the browser() escape hatch when you need the page. That is a better fit when many URLs need the same treatment and you do not want to maintain pooling logic. It is a worse fit when your scraping is a handful of known pages with custom interaction, because you will spend more time learning Reader's option surface than writing the Playwright calls. There is also a category of tool the README positions against via repository topics, including firecrawl-alternative and tavily-alternative, but the material provided does not describe how Reader differs from either, so no comparison can be made here.
Licence, Release Cadence and What Upgrades Cost
Reader is Apache-2.0, which permits commercial use, modification and redistribution provided you keep the licence and notice files and state significant changes. It also includes an explicit patent grant, unlike MIT. That is the licence text, not legal advice; if you are embedding Reader in a product, have counsel read the NOTICE requirements rather than relying on a summary. On maintenance, the release history shows v0.3.0 on 2026-06-27, v0.3.1 two days later, and v0.3.2 on 2026-07-01. Three patches inside a week suggests active work but also churn. The version is still 0.x, so the maintainers have not declared the API stable, and the README examples are the only contract you have. Pin the exact version in package.json and read the diff before bumping, because a rename of scrape, crawl or the result shape would break every call site. The repository was last pushed on 2026-08-19 and is not archived, so the project is live, but nothing in the material states a support policy or a deprecation window.
Editorial conclusion
Adopt Reader if you already run Node.js 18 or later and want scraping, crawling and a CDP-controlled browser behind one client instead of assembling Puppeteer with stealth plugins yourself. Do not adopt it if you need documented, stable configuration for proxy rotation and browser recycling, because the README does not expose those knobs. Before committing, verify three things: that npx playwright install chromium succeeds in your deployment image, that the browser() session survives the Cloudflare and Turnstile challenges your target sites actually serve, and that the scrape and crawl option objects in your installed version match the README examples, since the project is still on 0.x releases.
Community notes