TypeScript/JavaScript SDK for the Reader API — content extraction for LLMs. Wraps POST /v1/read, parses the standard envelope, throws typed errors, and auto-polls async jobs to completion.
Version: 0.2.0 · Runtime: Node 18+, Deno, Bun, Cloudflare Workers, modern browsers
npm install @vakra-dev/reader-jsimport { ReaderClient } from "@vakra-dev/reader-js";
const reader = new ReaderClient({ apiKey: process.env.READER_KEY! });
const result = await reader.read({ url: "https://example.com" });
if (result.kind === "scrape") {
console.log(result.data.markdown);
}reader.read(...) returns a discriminated union:
{ kind: "scrape", data: ScrapeResult }— single-URL requests, returned immediately{ kind: "job", data: Job }— batch and crawl requests, auto-polled to completion
- One method for every read operation.
reader.read({ url })for sync scrape,{ urls: [...] }for batch,{ url, maxPages }for crawl. - Typed errors for all 11 Reader error codes.
InsufficientCreditsError,RateLimitedError,UrlBlockedError,ScrapeTimeoutError, and more. Each subclass surfaces the relevant fields (e.g.err.required,err.retryAfterSeconds). - Automatic retries with exponential backoff for transient codes (
rate_limited,upstream_unavailable,scrape_timeout, …). Honors theRetry-Afterheader on 429. - Pagination-aware job collection.
waitForJob()returns the full job with every page result collected across pagination boundaries. - SSE streaming.
for await (const event of reader.stream(jobId))yields real-timeprogress/page/error/doneevents. - Request ID tracing. Every error carries the
x-request-idheader value onerr.requestIdfor support tickets.
Launch a stealthed Chrome and connect Playwright or Puppeteer:
import { chromium } from "playwright-core";
const session = await reader.sessions.create();
const browser = await chromium.connectOverCDP(session.wsEndpoint);
const page = await (await browser.newContext()).newPage();
await page.goto("https://example.com");
console.log(await page.title());
await browser.close();
await reader.sessions.stop(session.sessionId);Methods: reader.sessions.create(), .get(id), .stop(id), .list()
The SDK works in modern browsers via native fetch, but do not ship your API key in browser code — anyone can read and reuse it. Proxy requests through your own backend.
import {
ReaderApiError,
InsufficientCreditsError,
RateLimitedError,
UrlBlockedError,
} from "@vakra-dev/reader-js";
try {
await reader.read({ url });
} catch (err) {
if (err instanceof InsufficientCreditsError) {
console.error(`Need ${err.required}, have ${err.available}`);
} else if (err instanceof RateLimitedError) {
console.error(`Retry after ${err.retryAfterSeconds}s`);
} else if (err instanceof UrlBlockedError) {
console.error(`Blocked: ${err.reason}`);
} else if (err instanceof ReaderApiError) {
console.error(`[${err.code}] ${err.message} — see ${err.docsUrl}`);
} else {
throw err;
}
}Full catalog of error codes: https://reader.dev/docs/home/concepts/errors
- Docs: https://reader.dev/docs
- SDK reference: https://reader.dev/docs/sdk/javascript
- API reference: https://reader.dev/docs/api-reference/read
- Discord: https://discord.gg/6tjkq7J5WV
npm install
npm run typecheck
npm run build # builds to dist/
npm test # vitest