scrapewright
Health Uyari
- License — License: NOASSERTION
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 6 GitHub stars
Code Basarisiz
- eval() — Dynamic code execution via eval() in extension/background.js
- new Function() — Dynamic code execution via Function constructor in extension/background.js
- network request — Outbound network request in extension/background.js
- network request — Outbound network request in extension/lib/llm-client.js
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
LLM-powered web scraping platform. Build reusable scraping services as step-graph state machines via an AI-guided wizard, expose them through a local HTTP API. Chrome Extension (MV3) + Node.js native messaging host. Data never leaves your machine.
Scrapewright
The open-source, self-hosted AI web scraper that turns natural language into HTTP API services.
English | 简体中文
Developed and maintained by Hunan Singhand Intelligent Data Technology Co.,Ltd · Released under GPLv3
Scrapewright is an LLM-powered web scraping platform and AI web crawler that converts plain-English descriptions of what you want to extract into reusable, HTTP-callable scraping services. Describe the target page and fields in natural language, and a large language model analyzes the site, generates the scraping script, runs it inside a real Chrome browser, and returns structured JSON — no CSS selectors to hand-write, no Playwright or Puppeteer code to maintain. The same step-graph engine also doubles as a lightweight web test automation / browser automation tool: click, type, wait, assert, branch — declarative, replayable, self-healing.
Because it runs as a Chrome Extension (Manifest V3) plus a lightweight Node.js Native Messaging Host, Scrapewright executes inside a genuine browser — its core advantage for hard targets. JavaScript-heavy SPAs, asynchronously loaded (XHR / fetch / streaming) content, deeply nested same-origin iframes, and complex multi-step interactions (pagination, detail-page drill-down, modal dismissal, login flows) all just work, with full DOM rendering and no navigator.webdriver footprint. Your logins, cookies, and fingerprint carry over as-is, so login-required and anti-bot-protected sites work out of the box. Every scraping service is exposed through a standard REST / HTTP API with JSON Schema I/O, so it drops cleanly into any backend, data pipeline, RPA flow, or AI agent stack.
Great for: login-required sites (intranets, paid content, SaaS dashboards), AI chatbot answer capture, paginated list + detail-page crawling, iframe-heavy government / portal pages, low-frequency high-value queries, knowledge-graph building, web test automation, and no-code data extraction for non-developers.
Design whitepaper: English · 中文
Quick start
After loading the
extension/folder atchrome://extensions/(Developer mode → Load unpacked):./bin/scrapewright setup --auto # auto-detect extension ID, install native host, self-checkThen open the extension → Options → configure your LLM (OpenAI / Moonshot Kimi / Anthropic / GLM) → + New Service → describe what you want to scrape in natural language → test → deploy → call it from anywhere:
curl -X POST http://localhost:8765/api/v1/services/my-service/execute \ -H "X-API-Key: $SCRAPEWRIGHT_API_KEY" -H "Content-Type: application/json" \ -d '{"input": {"query": "hello"}}'
Table of Contents
- Background: Why Scrapewright
- Core Features
- System Requirements
- Installation · Startup Modes · Troubleshooting
- HTTP API · Script DSL
- Project Structure · Communication Architecture · Development
- Comparison with Other Solutions
- Distributed Deployment · Technical Architecture
- Copyright & License
Background: Why Scrapewright
Traditional web scraping tools and browser-automation frameworks — Scrapy, Puppeteer, Playwright, Selenium, BeautifulSoup, Cheerio — share several pain points that make web data extraction harder than it should be:
- High development cost — every target site needs hand-written CSS selectors, pagination handling, and anti-bot countermeasures. Maintenance cost keeps accumulating as sites change.
- Painful dynamic pages — SPA frameworks (React, Vue, Angular), nested iframes, and JavaScript-rendered content are hard to reach via plain HTTP requests or simple HTML parsers.
- Poor reusability — scraping scripts are typically bespoke per site; they don't transfer to structurally similar pages, so the spider you wrote for site A won't help with site B.
- No unified interface — different scraping jobs have no standardized input/output shape, which makes orchestration, scheduling, and scaling hard.
How Scrapewright answers each — this is what makes it a different kind of AI web scraper:
- AI-driven — describe what you want in natural language; the LLM analyzes page structure, generates the scraping script, and self-repairs on errors. Think "AI agent for the browser," but config-time instead of run-time.
- Real browser environment — runs as a Chrome extension inside a full browser, with first-class JavaScript rendering, iframe traversal, and dynamic loading. No headless-detected footprint.
- Standardized API — every scraping service is callable through a uniform HTTP API, with JSON Schema constraints on both input and output. The same shape every time, no matter how gnarly the target site.
- Visual no-code wizard — a 7-step flow takes you from describing the requirement to a tested deployment, no code required. Non-technical users can ship a scraper.
Core Features
| Feature | Description |
|---|---|
| AI script generation | Provide the target URL + a natural-language description; the LLM analyzes the page and generates a scraping script |
| Multi-step orchestration | Conditional branches, loops, pagination, and per-detail-page crawling are first class |
| Cross-iframe scraping | Automatically searches and scrapes same-origin iframe content (e.g. nested announcement pages on government sites) |
| Deep detail-page scraping | The $openTab API opens each list item's detail page in turn and extracts structured data |
| AI auto-repair | On execution failure, captures a DOM snapshot, analyzes the error, and asks the LLM to rewrite the script before retrying |
| Element intent annotation | Visually annotate page elements with intent (click / type / extract / wait), specify wait conditions (appear / disappear / content-stable) and output field mappings, so the LLM consumes your intent directly instead of guessing |
| Service management | Import/export, enable/disable, edit existing services, and one-click export of Markdown API docs (handy for sharing or feeding to AI agents) |
| Unified ops CLI | ./bin/scrapewright (setup / doctor / status / restart / logs / id) auto-detects the extension ID — no manual transcription |
| Async execution queue | Concurrent requests queue automatically and return asynchronously; well suited to batch scraping |
System Requirements
- Chrome browser (latest stable)
- Node.js >= 18
Installation
1. Load the Chrome Extension
- Open Chrome and navigate to
chrome://extensions/ - Toggle on Developer mode in the top-right corner
- Click Load unpacked and select the project's
extension/directory - After it loads, note the Extension ID shown on the extension card (e.g.
dmbnejooocdfjmnebpglhedhfcgncgdl) — you'll need it for the Native Host install
2. Install the Native Messaging Host
Recommended: one-line install. The unified CLI at the project root auto-detects the extension ID from Chrome (no need to copy from
chrome://extensions/), installs the Native Host, and self-checks:./bin/scrapewright setup --auto
scrapewright command overview (full text at ./bin/scrapewright help):
| Command | Purpose |
|---|---|
scrapewright setup --auto |
Auto-detect extension ID + install + self-check (first choice on a new machine) |
scrapewright status |
Show host process, connection state, and whether the ID matches the manifest |
scrapewright doctor |
Full diagnostic (node / manifest / wrapper / path-drift) + /health probe |
scrapewright restart |
Kill the host; in native mode, click Reconnect in the extension's Options to let Chrome relaunch it (use after editing host.js) |
scrapewright logs -f |
Tail the host log in real time |
scrapewright id |
Detect the current extension ID and check for drift vs the manifest |
scrapewright uninstall |
Uninstall the Native Host |
On Windows use
.\bin\scrapewright.cmd ...(same commands). Theinstall-host.sh/install-host.ps1scripts below are the lower-level primitives the CLI calls internally — reach for them directly in CI or when you need manual control.
The Native Messaging Host is a Node.js process that bridges the HTTP API and the Chrome extension.
Linux / macOS:
cd native-host
npm install
./install-host.sh <extension-id>
Example:
./install-host.sh dmbnejooocdfjmnebpglhedhfcgncgdl
Windows (PowerShell):
cd native-host
npm install
.\install-host.ps1 -ExtensionId "<extension-id>"
Note:
<extension-id>must be the actual Extension ID; wildcards are not supported by Chrome. Find it onchrome://extensions/.
The installer registers the Native Messaging Host with the system:
- Linux / macOS: writes
~/.config/google-chrome/NativeMessagingHosts/com.scrapewright.host.json
(macOS:~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.scrapewright.host.json) - Windows: writes registry key
HKCU:\Software\Google\Chrome\NativeMessagingHosts\com.scrapewright.host
Important: The Native Messaging manifest stores the absolute path to
host-launcher. Make sure to run the installer from the project directory you'll actually use for development/running. If you later move or rename the project directory (e.g. extracting from a downloadedscrapewright-masterarchive into a permanent location), you must re-run./install-host.sh <extension-id>(Windows:.\install-host.ps1 -ExtensionId <id>). Otherwise Chrome keeps launching the stale Host from the old directory, and you'll see "Native Messaging never connects, extension silently falls back to long-polling". Run./install-host.sh --doctor(Windows:.\install-host.ps1 -Doctor) to self-check.
After installation, restart Chrome (or click Reconnect in the Native Host Status card on the extension's Options page).
3. Configure the LLM
- Click the extension icon → the Options (service management) page opens
- Click Settings (top-right) → under LLM Configuration, fill in:
- Provider — pick an LLM provider (OpenAI / Moonshot / Kimi / Anthropic / GLM)
- Model — model name (e.g.
gpt-4o,kimi-for-coding,glm-5.1) - API Key — your API key
- Base URL (optional) — custom API endpoint, useful for corporate proxies or OpenAI-compatible gateways. Must include the path prefix (e.g.
https://api.openai.com/v1), not just the domain
- Click Save
4. Create a Scraping Service
On the Options page click + New Service to enter the AI wizard (7 steps):
| Step | Description |
|---|---|
| Step 1: Target URL | Enter the target site URL (press Enter to advance) |
| Step 2: Describe Needs | Describe the scraping requirement in natural language; click Research (or Ctrl+Enter) and the AI analyzes the page and generates a script |
| Step 3: Annotate Elements | If the AI needs help, visually annotate page elements; once done, the AI optimizes the script using your annotations |
| Step 4: Service Name & Script | Name the service; review and edit the AI-generated script |
| Step 5: I/O Schema & Test Input | Confirm input/output parameter shapes (JSON Schema) and edit the test input data |
| Step 6: Execute Test | Watch the live execution log (open page → load → execute → success/failure) |
| Step 7: Results | Review test results. On failure, choose Auto-Fix (AI self-repair) or Deploy Anyway (deploy despite the error) |
5. Manage Services
In the Services section of the Options page:
- Enable / Disable — toggle a service on or off
- Edit — return to the wizard to edit (pre-filled with the existing config)
- Export — export a single service as JSON
- Export All — export every service
- Import — import services from JSON (duplicates are skipped automatically)
- Delete — delete a service
The bottom of the Options page shows Execution History (the most recent 20 runs) with timestamp, service name, and success/failure status.
Startup Modes
The Host supports two communication modes: Native Messaging (Chrome auto-launches it) and HTTP long-polling (you start it manually). The two modes auto-switch; no extra configuration is needed.
Mode A: Native Messaging (recommended)
After step 2 of installation, Chrome automatically connects to the Host via Native Messaging on startup — nothing to do manually.
Mode B: Manual Start (HTTP long-polling)
If Native Messaging is unavailable (not installed, install failed, or you want manual control), start the Host by hand and the extension will fall back to HTTP long-polling automatically:
# Default port 8765
cd native-host && node host.js
# Custom port (must match the port set on the extension Options page under Server Configuration)
cd native-host && node host.js --port=19880
# Or via environment variable
SCRAPEWRIGHT_PORT=19880 node host.js
On startup you'll see:
[ScrapewrightHost] Startup diagnostics:
Mode: HTTP Long-Polling (manual start)
Extension should connect to: http://localhost:19880/api/v1/extension/poll
Scrapewright host listening on port 19880
Waiting for extension to connect via long-polling...
Ensure extension settings use port 19880
Note: In manual mode, make sure the port on the extension Options page under Server Configuration matches the
--portargument. The extension auto-falls-back to long-polling whenever Native Messaging drops.
Troubleshooting / FAQ
Symptom: The extension reports "Native host has exited", Native Messaging never works, or the Host log shows native stdin closed WITHOUT ever receiving an extension message / Falling back to poll mode.
Most common cause: the project directory was moved. The Native Messaging manifest stores the absolute path at install time. If you relocated the project from
~/Downloads/scrapewright-masterto~/projects/scrapewright, Chrome is still launching the stalehost.jsfrom the old location; it's incompatible with the new extension and stdin closes immediately. Fix: re-run./install-host.sh <extension-id>(Windows:.\install-host.ps1 -ExtensionId <id>) from the new directory.Run the diagnostic:
cd native-host && ./install-host.sh --doctor # macOS / Linux .\install-host.ps1 -Doctor # WindowsPay attention to the
path points into current host dircheck — it compares the manifest path to the script's current directory, prints a fix command on drift, and runs a wrapper smoke test to verify node + host.js initialize cleanly.Tail the Host log:
tail -f ~/Library/Logs/scrapewright/host.log # macOS tail -f ~/.cache/scrapewright/host.log # Linux Get-Content -Wait "$env:LOCALAPPDATA\scrapewright\host.log" -Tail 20 # WindowsA healthy connection shows
mode: native messaging (Chrome-launched)not followed by "closed WITHOUT ever receiving". Boot crashes (before the logger initializes) land instartup-error.lognext tohost.log— that's the real stack trace behind Chrome's opaque "Native host has exited".When you don't want to restart Chrome: click Reconnect in the Native Host Status card on the extension's Options page (lighter than restarting Chrome). After editing Host code, you still need to restart Chrome or reload the extension.
HTTP API
All execution is asynchronous. A call returns a jobId immediately; fetch the result via the status or wait endpoint. Concurrent requests queue automatically; only one job runs at a time.
Configuration
| Parameter | Default | Description |
|---|---|---|
--port=N |
8765 |
HTTP listen port (CLI argument) |
SCRAPEWRIGHT_PORT |
8765 |
HTTP listen port (env var; CLI argument takes precedence) |
SCRAPEWRIGHT_API_KEY |
dev-key |
API authentication key |
You can also change the port dynamically from the extension Options page under Server Configuration (applies immediately, no restart needed).
Authentication
All external API requests must carry the X-API-Key header.
Endpoints
Submit a job
POST /api/v1/services/{service-name}/execute
Request body:
{ "input": { "query": "hello" } }
Response (202 Accepted):
{
"success": true,
"jobId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "queued",
"queuePosition": 1
}
Concurrent requests queue automatically;
queuePositionis your place in line (0 = currently executing).
Wait for result (blocking)
GET /api/v1/jobs/{jobId}/wait?timeout=120
Long-polls until the job completes. timeout is in seconds (max 300, default 120).
Response (once the job finishes):
{
"success": true,
"job": {
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "completed",
"result": { "thinking": "...", "answer": "..." },
"error": null,
"queuePosition": 0,
"createdAt": 1717700000000,
"startedAt": 1717700001000,
"completedAt": 1717700015000
}
}
Query job status
GET /api/v1/jobs/{jobId}
Same response shape as /wait, but non-blocking — returns the current state immediately.
Cancel a job
POST /api/v1/jobs/{jobId}/cancel
Only queued jobs (status: "queued") can be cancelled. In-flight jobs cannot be cancelled.
List all jobs
GET /api/v1/jobs
List all services
GET /api/v1/services
Response:
{
"success": true,
"services": [
{
"name": "baidu-chat",
"displayName": "Baidu AI Chat",
"targetUrl": "https://chat.baidu.com",
"enabled": true,
"inputSchema": { ... },
"outputSchema": { ... }
}
]
}
Health check
GET /health
No API key required. Use it for load-balancer, K8s, or scheduler liveness probes.
Response:
{
"status": "ok",
"extensionConnected": true,
"queueLength": 0,
"queueRunning": false,
"uptime": 3600
}
| Field | Description |
|---|---|
status |
"ok" = extension connected; "degraded" = extension not connected |
extensionConnected |
Whether the extension is connected via Native Messaging or long-polling |
queueLength |
Number of queued jobs |
queueRunning |
Whether a job is currently executing |
uptime |
Host process uptime in seconds |
curl example
# Submit a job
JOB_ID=$(curl -s -X POST http://localhost:8765/api/v1/services/my-service/execute \
-H "X-API-Key: dev-key" \
-H "Content-Type: application/json" \
-d '{"input": {"query": "hello"}}' | jq -r '.jobId')
echo "Job ID: $JOB_ID"
# Wait for the result (blocks until completion)
curl -s "http://localhost:8765/api/v1/jobs/$JOB_ID/wait?timeout=60" \
-H "X-API-Key: dev-key" | jq .
# Or poll status manually
curl -s "http://localhost:8765/api/v1/jobs/$JOB_ID" \
-H "X-API-Key: dev-key" | jq '.job.status'
Job states
| State | Description |
|---|---|
queued |
Waiting in the queue |
running |
Currently executing |
completed |
Finished successfully; result is in the result field |
failed |
Failed; error details in the error field |
cancelled |
Cancelled |
Error types
| Error | Description |
|---|---|
ELEMENT_NOT_FOUND |
Target element not found; the AI will attempt to auto-repair the script |
SCRIPT_ERROR |
Script execution error; the AI will attempt to auto-repair the script |
SCRIPT_TIMEOUT |
Script execution timed out (default 60s) |
LOGIN_REQUIRED |
The target site requires login; the user must log in manually and retry |
Extension timeout |
Host cannot reach the extension — verify the extension is loaded and the port matches |
Script DSL
User scripts run inside a sandboxed iframe and interact with the target page through async APIs:
| API | Description |
|---|---|
$(selector) |
Wait for an element to appear (up to 30s); returns element data |
$click(selector) |
Click an element |
$type(selector, text) |
Type text (supports INPUT, TEXTAREA, contenteditable) |
$extract(selector, attr?) |
Extract text content or an attribute value |
$wait(selector, delayMs?) |
Wait for an element to appear, with optional delay |
$exists(selector, timeoutMs?) |
Check whether an element exists (recommended for polling) |
$check(selector, property) |
Read an element property (e.g. checked) |
$list(selector) |
Get all matching elements (including same-origin iframes) |
$count(selector) |
Count matching elements |
$openTab(url, fn) |
Open a new tab and run a function body in it; returns the result |
Scripts also have access to injected context:
__input__— parameters passed in by the external caller__stepResults__— a map of return values from all steps, keyed by step id__lastResult__— the previous step's return value
Project Structure
extension/ # Chrome Extension (Manifest V3)
background.js # Service Worker — execution queue, script orchestration, retry, AI auto-fix, long-poll client
content-script.js # Content script — DOM op proxy, element annotation, page snapshot
sandbox.html/js # Sandbox page — eval/new Function runs here (MV3 CSP requirement)
wizard.html/js/css # 7-step AI wizard — service create/edit flow
options.html/js/css # Options page — LLM settings, service management, execution history
popup.html/js # Popup
lib/
llm-client.js # LLM client — supports OpenAI / Moonshot / Kimi / Anthropic / GLM
offscreen-executor.js # Script executor — Offscreen API wrapper with timeout protection
step-orchestrator.js # Step orchestrator — conditional step-graph execution, loop detection, auto-retry
service-registry.js # Service registry — persisted to chrome.storage.local
wizard-utils.js # Wizard utilities — DSL guide, JSON sanitization, schema rendering
import-utils.js # Import utilities — data validation, dedup filtering
dom-snapshot.js # DOM snapshot — compact structure extraction (used by tests)
debug-logger.js # Debug logger — structured logs + auto-cleanup
script-executor.js # Legacy executor (kept for $openTab compatibility)
test/ # Extension unit tests
native-host/ # Node.js Native Messaging Host
host.js # HTTP server — Native Messaging + HTTP long-polling dual transport
lib/
native-messaging.js # Length-prefixed JSON codec (UTF-8 safe)
install-host.sh # Linux / macOS installer
install-host.ps1 # Windows installer
host.cmd # Windows launcher wrapper
test/ # Tests
Communication Architecture
External program
|
| HTTP POST /api/v1/services/{name}/execute
v
+------------------+ +------------------+
| host.js | Native Messaging (stdin | background.js |
| (Node.js) | /stdout, Chrome-launched)| (Service Worker)|
| | +--------+---------+
| or HTTP long- | | |
| polling: | <---- HTTP long-poll ----| Auto-fallback |
| /extension/poll | | |
| /extension/resp | | |
+------------------+ +--------+---------+
|
| chrome.tabs.sendMessage
v
+------------------+
| content-script.js|
+--------+---------+
|
| postMessage
v
+------------------+
| sandbox.html |
| (eval allowed) |
+------------------+
The Host and extension communicate over two channels and switch automatically:
- Native Messaging — used when Chrome auto-launches the Host (stdin/stdout pipe, low latency)
- HTTP long-polling — used when the Host is started manually (the extension polls
GET /api/v1/extension/polland posts responses toPOST /api/v1/extension/response)
Development
# Run Native Host tests
cd native-host && npm test
# Run a single test file
cd native-host && node --test test/host.test.js
# Start the Host manually (custom port)
cd native-host && node host.js --port=19880
After editing extension files, reload the extension at chrome://extensions/ (click the refresh icon on the extension card). After editing Native Host code, restart the Host process.
Restarting after a code update
To pick up code changes, restart the Host process:
Windows (PowerShell, admin):
# Kill the old process
taskkill /F /IM node.exe
# Close and restart Chrome
taskkill /F /IM chrome.exe
start chrome
Linux / macOS:
# Kill the old process
pkill -f "node.*host.js"
# Restart Chrome or reload the extension
After restarting Chrome, refresh the extension at chrome://extensions/; Chrome will launch the Native Host with the new code.
In manual-start mode, just Ctrl+C the current node host.js and run it again.
Comparison with Other Solutions
AI-assisted web scraping / browser automation falls into four technical lanes. Scrapewright sits in the client-side extension lane, complementary to the other three rather than a replacement.
Honest premise: every approach needs a browser. The difference is whose browser — Scrapewright reuses the user's daily Chrome (with login state / cookies / fingerprint intact); the others typically use a separately deployed headless / server-side Chromium (clean profile).
The four lanes
| Lane | Representative products | Runs in | Login state |
|---|---|---|---|
| Server-side headless scraping | Firecrawl, Crawl4AI, Spider | Chromium on a server | Requires Cookie / auth token injection |
| Server-side AI agent | Skyvern, Browser-use | Browser on a server | Automated login (form fill + CAPTCHA solving) |
| Developer coding-style | Claude Code + Puppeteer/Playwright | Developer's machine or CI | Manual (Cookie injection / login script) |
| Client-side extension (this project) | Scrapewright | The user's daily Chrome | Natively reuses the user's logged-in session |
vs CDP + AI coding (Claude Code / Cursor + Puppeteer/Playwright)
Developers can use AI coding tools like Claude Code to write Puppeteer/Playwright scrapers for a target site. That's the most flexible option, but the working mode and fit differ:
| Dimension | Scrapewright | CDP + AI coding |
|---|---|---|
| Usage | One-time AI wizard config → HTTP API service, reused long-term | Write / maintain code for every site |
| Who can use it | Non-technical users (wizard-style annotation + generation) | Developers only |
| Browser | User's daily Chrome (shared profile / login / fingerprint) | Headless or standalone Chromium (clean profile) |
| Login state | Directly reuses the user's logged-in session, zero extra cost | Needs Cookie injection / login scripts / CAPTCHA handling |
| Anti-bot detection | Extension content script; no navigator.webdriver footprint |
CDP can be fingerprinted via navigator.webdriver and similar signals |
| Flexibility | Step-graph DSL (structured, covers most scraping logic) | Arbitrary code (most flexible; can intercept / mock network requests) |
| Maintainability | auto-fix (LLM repairs selectors and logic on script failure) | Code maintenance (Claude Code can help, but human review needed) |
| Deployment | User's local Chrome + lightweight Node.js host | Server-side Node + Chromium |
| Concurrency | Single browser, serialized (scale out via multi-instance) | Multiple headless instances in parallel |
| Best for | Low-frequency high-value jobs, login-required, non-technical users | Large-scale, flexible logic, dev teams, CI/CD integration |
Scrapewright's edge: configure once → reusable service (not "write code every time") + native login-state reuse + non-technical users + auto-fix self-healing.
CDP + AI coding's edge: fully flexible code + Git versioning + server-side concurrency + fine-grained network-layer control.
vs sibling AI scraping products
| Product | Type | Runs in | Login state | LLM role | Core difference vs Scrapewright |
|---|---|---|---|---|---|
| Firecrawl | Hosted API | Cloud server | Cookie / token required | LLM extracts structured data | We reuse the user's login + generate executable step-graph scripts (not just HTML→Markdown extraction); local deploy (data never leaves the machine) |
| Crawl4AI | Open-source Python library | Server (Playwright) | Cookie passthrough supported | LLM extracts as Markdown | We're a client-side extension + AI wizard (non-technical users vs Python developers) |
| Skyvern | AI agent | Server | Automated login (form + CAPTCHA) | LLM drives every step | We're a configurable HTTP service (vs interactive agent); reuse real login state (vs simulated login) |
| Browser-use | AI agent | Server | Manual | LLM drives the browser in real time | We configure once into a repeatable service (vs interactive driving every time) |
| AgentQL | Smart selector API | Server | Handled separately | LLM picks elements | We provide full step-graph orchestration + auto-fix (vs single-point selector intelligence) |
The above is based on each product's 2025–2026 public docs. These products iterate fast — cross-check the current state.
Where Scrapewright honestly fits
Good at (recommended):
- Login-required scraping — enterprise intranets, paid content platforms, personal account data. Your already-logged-in browser just works, zero login cost (this is the biggest differentiator: Skyvern has to simulate login, Firecrawl needs Cookie injection, CDP needs a login script).
- Non-technical users customizing scrapes — AI wizard (visual element intent annotation) + HTTP API service, no code.
- Low-frequency high-value queries — AI Q&A capture, organization / person lookups, knowledge graph construction. Not mass crawling — automation of specific queries.
- Complex page structures — iframe nesting (e.g. government announcements), dynamic loading, streaming content (AI answers via
$waitForStable).
Not good at (use something else):
- Large-scale high-concurrency scraping (10k+ URLs) — single-browser bottleneck; use Firecrawl / Crawl4AI / multi-instance CDP.
- 24x7 unattended — depends on the user's Chrome running; use a server-side approach.
- Fine-grained network-layer control — intercept / mock requests, custom headers; use CDP (Puppeteer / Playwright).
One-line positioning: Scrapewright is not a general-purpose crawler engine — it's an "AI scraping assistant inside your team's browser". It turns the repetitive "open browser → log in → operate → extract" workflow into an HTTP service callable by external programs. It shines for login-required, low-frequency high-value scraping that non-technical users also want to do.
Distributed Deployment
Scrapewright supports parallel multi-instance deployment; each instance uses an independent Chrome Profile for complete isolation. The core idea: zero extension changes — N independent Chrome instances, each with its own Profile and port.
Architecture
Scheduler
├── POST localhost:8760/api/v1/services/{name}/execute → instance 0
├── POST localhost:8761/api/v1/services/{name}/execute → instance 1
└── POST localhost:8762/api/v1/services/{name}/execute → instance 2
Each instance has its own Chrome Profile (cookies / login state), its own host.js process, and its own execution queue.
Why not make the extension itself concurrent?
Chrome MV3 limits each extension to 1 offscreen document (the script execution surface) — a hard platform-level cap. Making the extension internally concurrent would require rewriting the entire script execution path at very high cost. The multi-Profile approach instead uses Chrome's native multi-process capability: every instance is fully independent, with no extension code changes at all.
Local multi-instance deployment
# 1. Edit the config
vim deploy/config.yaml
# 2. Start 5 instances
cd deploy && ./scrapewright-manager.sh start
# 3. Check status
./scrapewright-manager.sh status
# 4. Stop all instances
./scrapewright-manager.sh stop
Config keys (deploy/config.yaml):
| Key | Default | Description |
|---|---|---|
basePort |
8760 |
Starting HTTP port (instance N uses basePort+N) |
baseDebugPort |
9220 |
Starting Chrome remote debugging port |
instances |
5 |
Number of instances |
headless |
false |
Headless mode (set to true when no login state is needed) |
Docker / K8s deployment
# Build the image
docker build -f deploy/Dockerfile -t scrapewright .
# K8s deployment
kubectl apply -f deploy/k8s.yaml
# Scale to 10 instances
kubectl scale deployment scrapewright --replicas=10
In K8s each Pod runs 1 Chrome + 1 host.js, with the /health endpoint serving as liveness and readiness probe. The scheduler reaches the service via scrapewright.default.svc.cluster.local:8765.
Login-required sites
- Local deployment: start Chrome in headed mode → manually log in to the target site → cookies persist into the Profile directory
- K8s deployment: pack the logged-in Profile as a PersistentVolume and mount it into the Pod
Throughput reference
| Instances | Throughput | Memory |
|---|---|---|
| 1 | ~2 jobs/min | 2GB |
| 5 | ~10 jobs/min | 8GB |
| 10 | ~20 jobs/min | 16GB |
| K8s 20 Pods | ~40 jobs/min | Per-node |
Technical Architecture
Three-layer bridge
External program → HTTP API → Node.js Host → Native Messaging / HTTP long-polling → Chrome Extension → target page
This shape comes from a Chrome MV3 constraint: a service worker cannot run an HTTP server directly. The Node.js process doubles as the HTTP server and the Native Messaging Host, avoiding the complexity of multi-process deployment. When Native Messaging is unavailable, the system automatically falls back to HTTP long-polling.
Multi-step orchestration engine
A service is defined by a step graph; each step carries a script, a condition, success/failure transition targets, and a max-iteration budget:
- Directed-graph execution:
onSuccess(success → next) /onFailure(failure / give-up → fallback) point at the next step id, orTERMINATE(stop). - Poll / retry: a step with
maxIterations>1returning{ done:false }reruns itself; on data or{done:true}it followsonSuccess; when the budget is exhausted or it returns{failed:true}it followsonFailure(theSELFsentinel is no longer used). - Dual iteration guard: per-step
maxIterations+ globalmaxStepIterations(default 50) prevent runaway loops. - Cross-step data flow:
__stepResults__(history results indexed by step id) and__lastResult__(previous step's result, carrying state across a step's own retries).
AI-driven script generation and repair
- Two-round HTML protocol: round one sends a compact DOM summary (~8000 tokens) and the LLM returns candidate selectors; round two fetches only the full HTML of the candidate elements so the LLM can confirm or correct. This avoids truncation while keeping token usage efficient.
- Step-level auto-repair: on failure, only the failing step's script is rewritten; the step-graph topology is preserved. Repair uses the current page's DOM snapshot + error context + prior step results.
- Element annotation assist: when the LLM's selector confidence is below threshold, the visual element annotation mode kicks in automatically, turning user intent into structured annotations.
Cross-iframe scraping
Every $ API automatically traverses same-origin iframes. querySelectorDeep searches the main document and all same-origin iframe DOMs; $list aggregates matches across all documents. This is essential for sites that lean heavily on iframe nesting (e.g. government bulletin pages).
Security sandbox
User scripts run inside a dedicated sandbox iframe (declared via the sandbox key in manifest.json) — the only context where new Function() / eval() is permitted under MV3. Scripts can only interact with the target page through the whitelisted API ($, $click, etc.); they cannot reach chrome.* APIs or the page's own JavaScript context.
Key Chrome MV3 constraints
Chrome Manifest V3 imposes several hard constraints that directly shaped the design:
| Constraint | Impact | Mitigation |
|---|---|---|
| Service worker cannot run an HTTP server | Extension can't expose an API directly | Add a Node.js Native Messaging Host as the HTTP bridge |
eval / new Function forbidden in service worker and content script |
Cannot execute user scripts directly | Create a sandbox iframe (declared in manifest) and run dynamic code there |
| Each extension can have only 1 offscreen document | Script execution surface is a singleton | Serialize execution through ExecutionQueue; multi-instance deployment sidesteps the limit |
| Service worker can be killed after ~30s idle | Long-poll loops may break | chrome.alarms heartbeat every 24s, auto-reconnect on disconnect |
chrome.storage.local capped at 10MB |
Large job data may overflow | 100-job cap + 24h TTL cleanup; future migration to IndexedDB |
Copyright & License
This project is released under the GNU General Public License v3.0 (GPLv3).
What you can and must do
- ✅ Allowed: free use, copy, modification, and distribution of this program, including commercial use
- ✅ Allowed: integrate this project into a larger system
- ⚠️ Obligation: any distribution or public deployment must include the complete corresponding source code
- ⚠️ Obligation: modified versions must be open-sourced under the same license (GPLv3), with clear marking of changes
- ⚠️ Obligation: preserve the original copyright and license notices
In short: you can use it free, sell it, and build on it — but the moment you distribute (including SaaS-style network deployment), you must open-source your derivative code under the same terms.
The full legal text is in LICENSE. Official GPLv3 summary: https://www.gnu.org/licenses/gpl-3.0.html
Developer
Hunan Singhand Intelligent Data Technology Co.,Ltd
Website: https://www.singhand.com
Contributing
Bug reports and feature suggestions via Issues are welcome. Submitting a Pull Request means you agree to release your contribution under the GPLv3 license.
Scrapewright
Copyright (C) 2026 Hunan Singhand Intelligent Data Technology Co.,Ltd
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi