OCR 模型在首次使用时才下载,需提前联网或预置;JavaScript 页面要另装浏览器,可用 pagesift doctor 检查;Docker 服务默认监听 3002 端口,且需设置 PAGESIFT_API_KEYS 才能带鉴权调用。
pagesift
YOLOW92AGPL-3.0活跃维护自托管的网页抓取与文档解析服务,把 URL、带 OCR 的 PDF 和 Office 文件转成干净的 Markdown/JSON 供 AI Agent 使用,兼容 Firecrawl 和 Jina 接口,单个 Rust 二进制即可部署。
Self-hosted web scraper, crawler and document parser for AI agents: URLs, PDFs with OCR and Office files to clean Markdown/JSON. Firecrawl- and Jina-compatible API, MCP server, agent endpoint, Python/Node SDKs. Single Rust binary.
cargo install pagesift --locked
pagesift scrape https://example.comHTTP、PDF、Office 解析无需额外安装;JavaScript 页面需可选浏览器,OCR 可用 NVIDIA GPU,带公式模型的 OCR 约需 1.7 GB 内存;无浏览器时单 worker 峰值 18–377 MB。支持 Linux x86_64/aarch64、macOS arm64、Windows x86_64。
自托管 Rust 单二进制,把网页、PDF、Office 转成干净 Markdown/JSON 喂给 AI Agent
自托管的网页抓取与文档解析服务,把 URL、带 OCR 的 PDF 和 Office 文件转成干净的 Markdown/JSON 供 AI Agent 使用,兼容 Firecrawl 和 Jina 接口,单个 Rust 二进制即可部署。
核心能力
- 用自研 Rust 解析器读取 PDF、Office、电子书、邮件和压缩包
- 用 PP-OCRv6 在 CPU 或 NVIDIA GPU 上识别扫描件与公式
- 兼容 Firecrawl v1/v2 与 Jina Reader 的 HTTP 接口
- 提供 MCP 服务与 Python/Node 等多语言 SDK
- 按 CSS 选择器或模型生成的 schema 抽取结构化 JSON
容易踩的坑
- v1.2.4最新正式版2026-11-09 · 2026-11-09 10:10 UTC
PageSift 1.2.4 Release Notes
Release Version:
v1.2.4License: AGPL-3.0-only (Commercial licensing available)Changes since 1.2.3.
Attachment authorization
- Problem:
GET /v2/attachments/{id}checked only the API key and not resource ownership. A valid key for one account could download an attachment produced for another account when the ID was known. IDs are content-derived SHA-256 prefixes and also appear inrewriteMarkdown (asset://<id>), JSON results and logs, so they are not a secret. - Fix: the download endpoint now requires an
(account, attachment)authorization record before reading bytes. A missing or expired record returns the same404response as a missing attachment, with the messageattachment {id} not found or expired, so the response does not reveal whether the attachment exists. Content addressing and cross-account deduplication are unchanged: every account that receives an attachment in a scrape, batch, crawl or parse result gets its own authorization record. - Migration: on startup, missing authorizations are backfilled from saved job results, using the job owner and the attachment IDs in each page. Backfill runs in the background; failures are logged as warnings and do not block startup. Attachments referenced by persisted batch and crawl results keep working for their owning account for the remainder of the 24-hour retention period. Attachments that were only produced by a synchronous scrape are not part of a saved job result and cannot be attributed to an account, so such a link is not backfilled after an upgrade.
- Scope: multi-key deployments are affected. For new results, single-key and no-authentication deployments behave as before: when no API keys are configured, the anonymous identity is used for both writing and checking authorization. MCP attachments remain memory-only and are unaffected.
- Problem:
- v1.2.32026-11-09 · 2026-11-09 08:04 UTC
查看更新说明
PageSift 1.2.3 Release Notes
Version:
v1.2.3· Date: 2026-11-09 · License: AGPL-3.0-only; commercial licensing availableChanges since 1.2.2. Also available in 简体中文, 日本語, and Español.
Image assets
imageAssetsis opt-in on scrape and batch requests, or insidescrapeOptionsfor crawl. Omit it to retain the previous link-only output.attachkeeps Markdown links and returns Base64 attachment bytes;embedwrites data URLs into Markdown;rewriteusesasset://<id>references and returns attachments. The CLI supports--image-assets attach|embed|rewriteon scrape and crawl.- Assets report an ID derived from the SHA-256 of exported bytes, the complete hash, detected MIME type, byte count and source. The separate
imageAssetsoutcomes includeok,skipped-limitandfailed, with a reason when relevant. Image recognition uses content, not just filename extensions or HTTP Content-Type. attachandrewritepublish identical bytes once per batch/crawl task. Later pages keep the same asset ID without another Base64 payload. With persistent jobs the asset bytes are stored in the content-addressed attachment store; the first page's inline payload is reconstructed when that page is read. Pagination clients should retain assets from earlier pages or use the attachment endpoint while available.embedinstead keeps each page self-contained, so data URLs may repeat across pages.- Web images use the existing robots, rate-limit, redirect and SSRF policy. Each page has a byte budget, up to 64 image requests, a 10-second image deadline and at most four concurrent image fetches. Fetch failures and limit skips retain the original links. A bounded task-local cache shares up to 32 URLs with images up to 512 KiB; persistent job recovery repopulates it from saved successful sources. Larger images, additional URLs or different URLs with identical bytes can still require repeated downloads.
- SVG is allowed as an attachment or
asset://reference, not as a newembeddata URL. Identifying SVG does not sanitize it. Source-page data URLs are governed separately byremoveBase64Images. - PDF XObject images use the asset pipeline independently of OCR. IDs hash the actual exported bytes, including images converted to PNG/TIFF, and PDF Markdown references follow the exported ID. PDF inline images are not included. DOCX, PPTX and XLSX ZIP media preserve their original bytes; email image attachments are not included in this pipeline.
- HTTP scrape, batch and crawl return the asset data. With
--out, CLI output writesimages/<id>and includes outcomes inindex.jsonl. MCP scrape returns image assets as native image content. In MCPembedmode, Markdown with data URLs is kept in the text block but omitted from structured content to avoid a further copy; native image blocks still duplicate the bytes present in the text.
Streaming and compatibility
POST /v2/scrape/streamcan send provisional extracted Markdown before image downloads complete, followed by the final scrape result. With?previews=true, batch/crawl streams also emit provisional Markdown before their final page events. Previews are limited to 1 MiB, may be dropped, and are not replayed; final page sequence IDs and resume behavior are unchanged. Normal JSON results still wait for asset processing.removeBase64Images: falseis now accepted and preserves source-page data URL images in Markdown; the defaulttruecontinues to remove them. Cache keys distinguish the two options.- Existing
exportImagesremains available. New-mode attachment JSON contains MIME, Base64datafor the first published copy and aninlineDatamarker. HTTP, CLI, MCP and stream details are in the [image asset guide](https://g
- v1.2.22026-11-08 · 2026-11-08 07:29 UTC
查看更新说明
PageSift 1.2.2 Release Notes
Release Version:
v1.2.2License: AGPL-3.0-only (Commercial licensing available)Changes since 1.2.1.
Security and fixes
- Crawl and batch job listing, status, errors, streams and cancellation are scoped to the account that created the job. Extract job results are likewise restricted to their owner.
- Search with page scraping and extract use the daily page quota. Each page attempt consumes a unit before it is fetched; when the quota is exhausted, further pages are not fetched.
- A cached page is checked against robots.txt when the current request respects robots, including recorded redirect URLs.
- Expired extract and agent jobs can no longer be retrieved or cancelled.
- MCP placeholder outputs match their published output schemas. Nullable fields in the document schema match the serialized result.
- Finishing an unreserved itna attempt no longer panics. The session-pool test fixture carries the
Retry-Afterflag into outcome classification.
Compatibility
storeSnapshot: trueandremoveBase64Images: falsenow return an unsupported-option error instead of being silently ignored. Change tracking is available through thechangeTrackingformat.- With multiple API keys, an account can no longer access another account's crawl, batch or extract jobs by id.
- Engines implementing the
Enginetrait must implement the budgeted search and extract methods to support those operations for accounts with a daily page quota; the default implementation rejects them.
- v1.2.12026-11-08 · 2026-11-08 04:48 UTC
查看更新说明
PageSift 1.2.1 Release Notes
Release Version:
v1.2.1License: AGPL-3.0-only (Commercial licensing available)Changes since 1.2.0.
Security
- Identity-scoped API requests (
ownerset by an authenticated API caller) no longer read from or write to the shared result cache. Previously the cache key had no caller, egress or fingerprint dimension, so a page fetched with one API key's session cookies could be returned to another key. Anonymous requests keep the existing cache behavior. - The result cache is unchanged for requests without a caller identity. Per-owner session isolation in the identity pool is not affected.
Fixed
- A 503 response with
Retry-Afteris now classified asthrottledin the itna attempt trace and in egress-pool outcomes. The header was present in the response but never reachedclassify, so the trace saidotherwhile the classifier's contract saidthrottled. The status of the returned page does not change. - A 503 response without
Retry-Afteris still classified asother.
MCP
pagesift_crawl_statusis renamed topagesift_poll_job. The tool polls both crawl and batch scrape jobs, and the new name pairs withpagesift_cancel_job. There is no old-name alias. Migration: change the tool name in the client; arguments are unchanged.- New
pagesift_cancel_jobstops a running crawl or batch scrape job. Pages collected before the cancel stay available throughpagesift_poll_job; work that finishes after the cancel is discarded. Cancelling an already finished job returns its current status, and an unknown or expired id is an error. - Every MCP tool now publishes an
outputSchemawith field descriptions for its structured result. - Input schemas now describe every parameter, including nested action, viewport, location, chunking and scrape-option fields, and document defaults, limits and sitemap enum values.
- Tool descriptions state cache lifetime,
keepSessionlifetime, prompt-versus-actions usage, partial-failure behavior, polling and cancellation rules. - Read-only tools set
idempotentHint: true;pagesift_cancel_jobis idempotent and non-destructive.
Compatibility
- No configuration or data migration is required.
- The MCP rename is a breaking change for clients that hard-code
pagesift_crawl_status. No alias is kept because a duplicate tool would enter the tool set under two names. - HTTP APIs, the CLI, Python, Node and other language bindings are unchanged.
Verification
- Added engine tests for owner-scoped cache isolation (anonymous hit, owner bypass, no owner write-back) and for 503 with and without
Retry-After. - Added MCP tests that every definition has an output schema and every input parameter has a description.
cargo fmt --check,git diff --check, the release identity check and the README checks pass.
- Identity-scoped API requests (
- v1.2.02026-11-07 · 2026-11-07 01:15 UTC
查看更新说明
PageSift 1.2.0 Release Notes
Release Version:
v1.2.0License: AGPL-3.0-only (Commercial licensing available)Changes since 1.1.3. Speed and quality figures in the README were measured on 1.1.0 and were not measured again for this release.
Access-barrier recovery (opt-in)
[itna] enabled = trueadds a bounded recovery path for normal HTTP requests. It is off by default; with it off, the existing request path and configuration behave as before.- HTTP results are classified by status, response headers and the existing barrier rules.
- A blocked or challenge HTTP result may get one browser retry on the same egress. Rate limits (429 and
Retry-After), login walls and an explicitengine = "http"do not escalate. - Redirects and browser sub-requests draw from one network budget. When the budget is exhausted the request fails closed instead of continuing unbudgeted.
- The attempt trace is reported in
metadata.pagesift.itnaor in the error details.
Sessions and identities
- Sessions are leased per owner, origin, egress and fingerprint. API requests with a stable caller identity can reuse a session across requests; anonymous requests receive a per-request session. Different owners never share a session.
- 429 and 5xx responses, and cancellation, no longer count as identity failures. 401 and 403 still count.
- Retired sessions are removed from the pool. A lease is released on cancellation as well as on success or failure.
Fingerprint transport through proxies
browser_fingerprintcan now be combined with an HTTP proxy (HTTP CONNECT), an HTTPS proxy, SOCKS5 or SOCKS5H.- Targets are resolved and SSRF-checked locally; the proxy receives an IP address, while TLS SNI and the HTTP authority keep the original hostname.
- TLS and HTTP/2 still use the existing fingerprint-shaped transport. Proxy TLS certificates are verified.
- A failed proxy or target tunnel is reported as an error. It is not silently downgraded to a plain reqwest request or a direct connection.
socks5hresolves targets locally, likesocks5, because the target must pass the SSRF check before the tunnel opens.
HTTP to browser handoff
- Cookies from the HTTP session are imported into an isolated browser context only for the exact origin.
- Imported cookies are host-only. Browsers do not isolate cookies by port, so same-host requests on another scheme or port are blocked, except the standard
http:80tohttps:443upgrade. HTTPS to HTTP is blocked. - Path,
Secure,HttpOnlyand expiry are preserved. Imported cookies useSameSite=Strictbecause the session store does not keep SameSite. - The handoff is refused when the HTTP fingerprint's Chrome major version differs from the running browser's major version.
Browser automation markers and challenges
- When itna is enabled, the default launch arguments omit the Blink automation marker, and a document-start script clears
navigator.webdriverfor local and remote browsers. It does not fabricate hardware or identity. - Non-interactive JavaScript challenges get a bounded settle wait: at most 8 seconds and never beyond the request timeout.
- Pages with interactive CAPTCHA widgets are not waited for. They return
ACCESS_BARRIERwithneedsHuman: true. No CAPTCHA solver is included.
Verification
- Covered by local controlled fixtures in the release test suites for
pagesift-itna,pagesift-net,pagesift-cdp,pagesift-policy,pagesift-engineandpagesift-api. - Local fixtures cover classification, attempt and network budgets, cancellation, proxy failure, certificate rejection, session isolation, cookie scope, automation-marker removal, non-interactive challenge settling and interactive-CAPTCHA reporting.
cargo fmt --check,git diff --checkandcargo deny --config .github/deny.toml checkpass.- No production-site or WAF pass-rate claims were measured for this release.
Compatibility
- No configuration or data migration is required. The `[itn
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
pagesift 1.2.2
The web and document layer for AI agents: any URL, document, email, archive or source file in, clean Markdown or JSON out.
One self-hosted Rust binary with a CLI, Firecrawl and Jina Reader APIs, an MCP server, and packages for Python, Node.js, Go, Java, C#, Ruby, PHP and more.
Measured: PDF to Markdown 2.4 ms per page, 20.49× faster than the next best tool; HTML to Markdown 0.24 ms per page, 8.12× faster; main content 1.0 ms per page, 7.26× faster (lower is better); Office 91.7 files/s, 3.40× the next best (higher is better).
English · 简体中文 · 日本語 · Español
What it is
pagesift reads the web and documents for software that thinks: it fetches a URL, rendering JavaScript only when that adds content, or opens a local file, and returns the content as Markdown or structured JSON. It covers single pages, whole sites, scanned PDFs, browser actions, change monitoring and research runs driven by your own model.
Can replace or sit alongside: Firecrawl (same v1/v2 API, self-hosted), Jina Reader (/r/ and /s/),
Crawl4AI, trafilatura, Readability, pymupdf4llm, Docling, Kreuzberg, xberg.
At a glance
- Input: URLs, HTML, PDF including scanned pages (OCR), image files (OCR), Word (.docx, .doc), Excel (.xlsx, .xlsb, .xls), PowerPoint (.pptx, .ppt), OpenDocument, RTF, WordPerfect, HWP, EPUB, MOBI, FB2, email (.eml, .mbox, .msg), archives (zip, tar, gz, bz2, xz, 7z), SQLite, dBASE, CSV, Markdown and other text formats, 373 source-code and config languages, WARC archives
- Output: Markdown, HTML, raw HTML, links, images, metadata, schema-based JSON; warnings when a result is incomplete
- Interfaces: CLI · Firecrawl v1/v2 HTTP API · Jina Reader · MCP (stdio or HTTP) · Python · Node.js / TypeScript · Rust crate · C ABI with Go, Java, Kotlin, C#, Ruby, PHP, Lua, Perl, Dart, Swift and Zig bindings · LangChain and LlamaIndex
- Platforms: Linux x86_64 / aarch64 (glibc ≥ 2.28 and musl), macOS arm64, Windows x86_64; Docker image
ghcr.io/yolow92/pagesift - Runtime: nothing to install for HTTP, PDF and Office. Optional: a browser for JavaScript pages, an NVIDIA GPU for OCR, your own model for
/v2/agent - Memory: 18–377 MB peak per worker across the 1.1 benchmarks without a browser; OCR with formula models needs about 1.7 GB; capacity is sized from the cgroup limit
- License: AGPL-3.0, or a commercial license
- Latest: 1.2.2 · release notes
Install and use
| Install | First call | |
|---|---|---|
| CLI | cargo install pagesift --locked | pagesift scrape https://example.com |
| Python | pip install pagesift | pagesift.scrape("https://example.com").markdown |
| Node.js | npm install @pagesift/node | (await new Scraper().scrape("https://example.com")).markdown |
| Server | docker run -p 3002:3002 ghcr.io/yolow92/pagesift:1.2.2 | curl localhost:3002/r/https://example.com |
| MCP | — | claude mcp add pagesift -- pagesift mcp |
CLI
pagesift scrape https://example.com # Markdown to stdout
pagesift scrape report.pdf # local PDF, Office, e-book, email, archive, image, code or WARC
pagesift --ocr scrape scan.pdf # OCR scanned pages; models download on first use
pagesift crawl https://docs.rs --limit 500 --out ./data/ # one file per page
pagesift crawl https://www.example.edu --query "graduate admission" --adaptive
pagesift extract --schema schema.json https://example.com # JSON by CSS selectors, repaired when the page changes
pagesift doctor # check browsers, GPU and models
Python
import pagesift
page = pagesift.scrape("https://example.com", formats=["markdown", "links"])
print(page.markdown, page.metadata["title"], page.links)
pages = pagesift.scrape_many(["https://example.com", "https://example.org"], concurrency=8)
scanner = pagesift.Scraper(ocr=True) # models download when the first scanned page arrives
print(scanner.parse(open("scan.pdf", "rb").read(), "scan.pdf").markdown)
Node.js / TypeScript
import { Scraper } from '@pagesift/node'
const scraper = new Scraper()
const page = await scraper.scrape('https://example.com', { formats: ['markdown', 'links'] })
console.log(page.markdown, page.metadata.title, page.links)
const items = await scraper.scrapeMany(['https://example.com', 'https://example.org'], { concurrency: 4 })
HTTP server
docker run -d -p 3002:3002 -v pagesift-data:/data -e PAGESIFT_API_KEYS=sk-test ghcr.io/yolow92/pagesift:1.2.2
curl -s localhost:3002/v2/scrape -H 'Authorization: Bearer sk-test' -H 'Content-Type: application/json' \
-d '{"url":"https://example.com","formats":["markdown"]}' # Firecrawl API
curl -s localhost:3002/r/https://example.com -H 'Authorization: Bearer sk-test' # Jina Reader
curl -s localhost:3002/v2/parse -H 'Authorization: Bearer sk-test' \
-F [email protected] -F 'options={"formats":["markdown"]}' # file upload
Firecrawl SDKs work by changing the API URL. Upload API · Jina headers
MCP
pagesift mcp # stdio, for one agent
pagesift mcp http --port 3003 # one shared local service
claude mcp add --scope user --transport http pagesift http://127.0.0.1:3003/mcp
Tools: pagesift_scrape, pagesift_batch_scrape, pagesift_crawl, pagesift_poll_job, pagesift_cancel_job,
pagesift_map, pagesift_interact, pagesift_interact_stop, and with a configured model pagesift_agent,
pagesift_agent_status.
Shared MCP service
What it can do
| Capability | What you get | Docs |
|---|---|---|
| Clean content | Main-content detection and Markdown that keeps headings, lists, tables, code and math | Benchmarks |
| Documents | Own Rust readers for PDF, current and legacy Office, OpenDocument, e-books, email, archives, images, databases and text formats, including damaged files and CJK fonts | Upload API |
| OCR | Scanned PDF pages through PP-OCRv6 and display formulas through PP-FormulaNet, in pure Rust on CPU or NVIDIA GPU | Upload API |
| Structured extraction | JSON by CSS selectors that are relocated when a site changes, or by a schema your model writes once and pagesift caches | Extraction |
| Browser actions | Clicks, typing and scrolling on the page, plus sessions you can keep working in | Interact |
| Agent | POST /v2/agent answers a question from the web with your own model, and checks each field against the page it came from | Agent API |
| Monitoring | Scheduled checks that separate real changes from dates, counters and ads, with webhooks | Monitor |
| Crawling | Sitemaps, query-focused crawls that stop when pages stop helping, trap handling, robots.txt and per-host limits | Benchmarks |
| Archives | WARC output on every crawl, and WARC files as input with no network | Release notes |
| Operations | Multi-server gateway, workers and standby; job persistence, durable webhooks, metrics, audit log | Architecture |
| Safety | Private-network and DNS-rebinding guards, and every incomplete result reports a warning | Bot policy |
How /v2/agent answers a question
flowchart LR
Q[Question + schema] --> M[Your model plans one step]
M --> T[pagesift runs it<br/>search, map, scrape, extract]
T --> E[Text archived as evidence]
E --> D{Enough?}
D -->|no, budget left| M
D -->|yes| A[Answer matched to the schema]
A --> V[Each field checked<br/>against the evidence]
V --> R[JSON + sources + warnings]
robots.txt, rate limits and network guards apply to every page. The model chooses URLs and queries, not fetch options.
Performance
↑ higher is better · ↓ lower is better. Strongest result per domain; methods and sources in the full report.
| Task | Metric | PageSift | Best other tool | Gap |
|---|---|---|---|---|
| PDF → Markdown — olmOCR-bench 1,269 pages, per page (single thread) | ms/page ↓ | 2.4 | pypdf 50.0 | ×20.49 |
| PDF → Markdown — B1 144 pages, 1 worker, resident server | files/s ↑ | 176.5 | pdf_oxide 100.6 | ×1.75 |
| PDF → Markdown — olmOCR-bench 1,269 pages | official score ↑ | 0.645 | pymupdf4llm 0.484 | +0.161 |
| HTML → Markdown — 600 generated documents, per page | ms/page ↓ | 0.24 | Turndown 1.9 | ×8.12 |
| HTML → Markdown — 600 generated documents, fidelity | mean F1 ↑ | 1.000 | markdownify 0.936 | +0.064 |
| Main content — Firecrawl 597 pages, single thread | p50 ms/page ↓ | 1.0 | crw 7.4 | ×7.26 |
| Main content — WCXB test split, 150 pages | F1 ↑ | 0.866 | Readability + Turndown 0.848 | +0.018 |
| Publication dates — htmldate 1,000 pages, date search | ms/page ↓ | 0.31 | htmldate (fast) 2.0 | ×6.45 |
| RAG chunking — 5 corpora, 1.4 MB | total ms ↓ | 7 | chonkie recursive 35 | ×5.01 |
| Office / e-books — B4 81 files, in-process | files/s ↑ | 91.7 | xberg 27.0 | ×3.40 |
| Office / e-books — B4 hold-out 39 files, structure kept | structure kept ↑ | 0.988 | xberg 0.878 | +0.110 |
| RAG query filter — 472 questions, default settings | answer recall ↑ | 0.929 | Crawl4AI BM25 0.673 | +0.256 |
| Wild crawl — polite, 40 sites × 60 pages, coverage | coverage ↑ | 0.740 | Crawl4AI (HTTP) 0.529 | +0.211 |
| Wild crawl — fast, 40 sites × 60 pages, coverage | coverage ↑ | 0.687 | Crawl4AI (HTTP) 0.499 | +0.188 |
| Scanned PDFs — B5 134 pages, olmOCR score without baseline, OCR on | olmOCR score ↑ | 0.314 | Docling (GPU) 0.125 | +0.189 |
| Scanned PDFs — B5 134 pages, olmOCR score with baseline, OCR on | olmOCR score ↑ | 0.543 | Docling (GPU) 0.410 | +0.133 |
| Hard PDFs — B3 100 pdf.js files, completion | completion ↑ | 0.720 | pymupdf4llm 0.680 | +0.040 |
| Peak memory per worker | PageSift MB ↓ | Other tool MB | Less memory |
|---|---|---|---|
| PDF, B1 pages | 32 | Docling (CPU) 3,675 (2026-10-28) | ×113.1 |
| HTML main content, A2 pages | 20 | Readability + Turndown 1,200 (2026-10-28) | ×60.8 |
| Crawl, 200 sites × 100 pages | 218 | spider 5,500 (2026-10-21) | ×25.2 |
| HTML main content, A2 pages | 20 | trafilatura 123 (2026-10-28) | ×6.2 |
| Office and e-books, B4 files | 47 | Kreuzberg 231 (2026-10-28) | ×4.9 |
| Crawl with browser, 200 sites × 100 pages | 669 | Google Chrome 2,300 (2026-10-21) | ×3.4 |
| PDF, B1 pages | 32 | Kreuzberg 76 (2026-10-28) | ×2.3 |
| JavaScript pages, A3 (live web) | 520 | Crawl4AI 982 (2026-10-28) | ×1.9 |
PageSift 1.1 and xberg 1.3.9. xberg measured on 2026-11-04; a range is two runs. A bold value is the best in its row.
| Metric | PageSift CLI | PageSift server | xberg | xberg layout mode |
|---|---|---|---|---|
| PDF B1, olmOCR score 1,269 pages ↑ | 0.645 | — | 0.436 | 0.472 |
| Office B4, structure kept, hold-out 39 files ↑ | 0.988 | — | 0.878 | — |
| PDF B1, 1 worker, files/s ↑ | 161.4 | 176.5 | 29.5–29.9 | 1.35 |
| PDF B1, 16 workers, files/s ↑ | 539.3 | 305.1 | 65.8–68.4 | 1.41 |
| Office B4, 1 worker, files/s ↑ | 91.7 | 69.1 | 27.0 | — |
| Office B4, 16 workers, files/s ↑ | 314.0 | 147.0 | 73.4–74.2 | — |
| PDF B1, 1 worker, peak MB ↓ | 32 | 211 | 147–172 | 1118 |
| Office B4, 1 worker, peak MB ↓ | 47 | 252 | 112 | — |
| Office B4, 1 worker, median ms per file ↓ | 4.5 | 2.2 | 3.2–3.3 | — |
fast, 40 sites × 60 pages, time (spider covered about half as many pages) 16.1 seconds vs spider 1.4 seconds; A2 replay, 269 pages, HTTP only, no rate limit, 1 worker 47.5 pages/s vs spider 156.6 pages/s; A2 269 random pages, resident worker, per page 4.5 ms/page vs Resiliparse 2.1 ms/page.
Architecture
The core is written from the file format up in Rust, and limits are measured at run time instead of being set by hand.
flowchart TD
CLI[CLI / Rust caller] --> Engine[pagesift-engine]
HTTP[Firecrawl and Jina HTTP API] --> Engine
Bindings[Python / Node / MCP / C ABI: Go, Java, C#, Ruby, PHP and more] --> Engine
Engine --> Hooks[pagesift-hooks: rules and hooks]
Hooks --> Policy[pagesift-policy: robots, rate limits, backoff, identity leases]
Policy --> Net[pagesift-net: HTTP, SSRF guards, validated proxy tunnels, optional TLS fingerprint]
Net --> Plan{pagesift-plan: render?}
Plan -->|No| DOM[pagesift-html: arena DOM]
Plan -->|Yes| CDP[pagesift-cdp: browser pool, automation-marker removal, challenge settle]
CDP --> DOM
Net -->|PDF| PDF[pagesift-pdf]
Net -->|Office, e-books, email, archives, text| Office[pagesift-office]
Net -->|Image| OCR[pagesift-ocr, pagesift-infer, pagesift-gpu]
Office -->|archive member, attachment| Office
Office -->|archive member, attachment| PDF
Office -->|source code| Syntax[pagesift-syntax]
PDF -->|scanned page| OCR
DOM --> Content[pagesift-content: main content, Markdown, metadata]
DOM --> Extract[pagesift-extract: selectors, relocation, chunking]
PDF --> Sink[pagesift-sink: outputs and cache format]
Office --> Sink
OCR --> Sink
Content --> Sink
Extract --> Sink
Engine --> Store[pagesift-store: cache, selector memory, records]
Engine -.-> ITNA[pagesift-itna: barrier classification, attempt and network budgets]
ITNA -.->|shared budget| Net
ITNA -.->|one bounded fallback| CDP
Net -.->|restricted cookie handoff| CDP
Access-barrier recovery is opt-in ([itna] enabled, off by default). pagesift-itna classifies barriers,
allows one bounded browser fallback, and shares one network budget across redirects and browser sub-requests.
Sessions are leased per owner, origin, egress and fingerprint; HTTP cookies reach the browser only through an
exact-origin handoff. Interactive CAPTCHAs are reported as needing a human and are not solved.
Own code down to the format. Parsing runs in process with no Python, JVM or Node runtime behind it. pagesift has its own zero-copy HTML5 parser, PDF file layer with JPEG, CCITT and JBIG2 decoders, readers for Office, e-books, email and archives, neural network inference with GPU kernels compiled from Rust, Chrome DevTools client, MCP server and append-only store. A worker costs tens of megabytes, not a loaded interpreter, and starts in milliseconds.
One worker per core. CPU work runs on resident workers grouped by NUMA node, which steal work inside their own node first. A single admission path covers CPU, memory and browser tabs, and capacity comes from the cgroup limit, so a container stays within its memory instead of being killed.
Measured instead of fixed. Concurrency follows a Universal Scalability Law fit, per-host limits follow a latency gradient, stage timeouts use survival analysis and retries use per-class success rates. Each one starts from a safe default and moves only on statistically significant evidence (δ = 0.05). User settings and safety limits stay hard limits.
A browser only when it pays. For each family of URL paths, pagesift learns whether rendering added content, and the
rendered result is kept only if it scores higher. Page data such as __NEXT_DATA__ and JSON-LD is read without a browser.
Lightpanda, moli and Chrome form a fallback chain, and --explain records every decision.
Honest results. A partial page, a truncated file or a skipped scan returns a warning code instead of looking complete. Agent answers report which values were found in the evidence, and selector repairs report the old and new selector.
From one binary to a fleet. serve --role gateway, worker and standby share the same binary, with site affinity by
rendezvous hashing and leases with fencing. Jobs and webhooks resume after a restart.
flowchart LR
C[Clients] --> G[Gateway<br/>API, jobs, webhooks]
G -->|same site, same worker| W1[Worker]
G --> W2[Worker]
G --> W3[Worker]
G -.->|job records| S[Standby<br/>takes over on lease loss]
When to use it, and when not
Good fit
- Feeding web pages and documents to an LLM, a RAG index or an agent
- Self-hosting a Firecrawl- or Jina Reader-style service with no per-page fees
- Mixed input: the same call handles HTML, PDF, scans, Office files and e-books
- Small machines and containers, where memory is bounded by the cgroup limit
Pick something else when
- Your input is image files. OCR covers scanned pages inside PDFs, not standalone images.
- AGPL does not work for you and a commercial license is not an option.
- You need a managed cloud service. pagesift is self-hosted.
License
AGPL-3.0. For proprietary linking or private deployment without AGPL obligations, see the
commercial license or write to [email protected].
What's new in 1.2.2
Crawl, batch and extract jobs are restricted to their owner. Search and extract page attempts count against the daily quota, and cached pages are checked against robots.txt. Unsupported snapshot and base64-image options are now rejected instead of silently ignored.
Release notes · 1.2.1 · all releases · CHANGELOG
Community
Questions or feedback: Discord · Issues · Discussions
Citation
@software{pagesift2026,
title = {PageSift: Rust Web and Document Extraction Engine for AI Pipelines},
author = {YOLOW92},
year = {2026},
url = {https://github.com/YOLOW92/pagesift},
note = {Version 1.2.2}
}