Quickstart
Register for a free API key at captureweb.dev/signup. No credit card required. You get 100 credits to start.
curl -X POST https://api.captureweb.dev/v1/screenshot \
-H "Authorization: Bearer pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://stripe.com","format":"png"}' \
--output screenshot.pngAuthentication
Pass your API key in the Authorization header on every request:
Authorization: Bearer pk_live_YOUR_KEY
Keys start with pk_live_. Get yours at /signup. Store it securely — it's shown once.
Credits
Credits are consumed per successful render:
| Endpoint | Credits | Notes |
|---|---|---|
/screenshot | 1 | Per render |
/pdf | 1 | URL or HTML input |
/markdown | 1 | |
/content | 1 | |
/links | 1 | |
/json | 1 | |
/scrape | 1 | |
/snapshot | 2 | Returns all formats in one call |
| Cache hit | 0 | Same URL within cache TTL |
| Failed render (4xx/timeout) | 0 |
Response headers on every request: x-credits-used, x-credits-remaining, x-cache (hit/miss), x-render-source, x-render-time.
Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | invalid_api_key | Key missing or invalid |
| 402 | credits_exhausted | Monthly credits used up |
| 429 | rate_limit_exceeded | Too many requests. Check retry_after_seconds |
| 422 | validation_error | Bad request body |
| 500 | internal_error | Something went wrong on our end |
/screenshot
| Field | Type | Default | Description |
|---|---|---|---|
url | string | required | URL to capture |
format | png | jpeg | webp | png | Output format |
full_page | boolean | false | Capture full scrollable height |
dark_mode | boolean | false | Enable dark mode |
width | number | 1280 | Viewport width px |
height | number | 800 | Viewport height px |
quality | number | 90 | JPEG/WebP quality (1-100) |
block_banners | boolean | false | Hide cookie banners and overlays |
wait_mode | load | idle | selector | load | When to consider page ready |
wait_selector | string | — | CSS selector to wait for |
async | boolean | false | Return job ID immediately |
webhook_url | string | — | URL to POST result to (async only) |
Accepts either url or html. For HTML input, the PDF is generated directly from the raw HTML — no URL needed.
| Field | Type | Default | Description |
|---|---|---|---|
url | string | — | URL to render (mutually exclusive with html) |
html | string | — | Raw HTML to render (mutually exclusive with url) |
format | A4 | Letter | A4 | Page size |
landscape | boolean | false | Landscape orientation |
async | boolean | false | Return job ID immediately |
webhook_url | string | — | URL to POST result to (async only) |
/snapshot
Cheapest way to get all formats. One call returns screenshot, PDF, HTML, and Markdown together — faster and cheaper than calling each endpoint separately.
/scrape
| Field | Type | Description |
|---|---|---|
url | string | required |
selectors | array | Array of {name, selector, attribute?} objects |
wait_mode | load | idle | Render wait strategy |
/markdown
Strips navigation, ads, and boilerplate. LLM-ready output.
/content
/links
/json
/a11y
Extracts the full ARIA accessibility tree after JavaScript rendering. Useful for UI automation, accessibility audits, and giving AI agents a structured, semantic page representation.
| Field | Type | Default | Description |
|---|---|---|---|
url | string | required | URL to inspect |
interesting_only | boolean | true | Return only semantically meaningful nodes — omit generic containers |
root | string | — | CSS selector to anchor the tree to a specific subtree |
fresh | boolean | false | Bypass cache |
Response: { url, tree, title, source, cached } where tree is the nested ARIA node object.
/brand
Extracts brand assets from any domain using a plain HTTP fetch — no browser required. Fast (~300ms) and reliable. Ideal for directories, CRMs, and any product that needs brand metadata at scale.
| Field | Type | Default | Description |
|---|---|---|---|
url | string | required | The domain or URL to extract brand data from |
Response: { url, favicon, logo, og_image, og_title, og_description, colors[], fonts[], twitter_card, source, method, timing_ms, credits }
colors— top brand colors as hex strings, sorted by frequencyfonts— font families found in CSS and Google Fonts linkslogo— best candidate logo URL (apple-touch-icon → img[src*=logo] → OG image)favicon— resolved favicon URL
Async mode
Any endpoint accepts "async": true. The request returns immediately with a job ID. Poll GET /v1/jobs/:id or receive the result via webhook.
{
"url": "https://example.com",
"async": true,
"webhook_url": "https://yoursite.com/hook"
}Job status values: pending → running → completed | failed
/crawl
| Field | Type | Default |
|---|---|---|
url | string | required — seed URL |
max_depth | number | 2 (max 5) |
max_pages | number | 50 (max 500) |
include_pattern | regex string | — |
exclude_pattern | regex string | — |
webhook_url | string | — |
Render chain
Every request is automatically routed through up to 5 tiers. You never configure this — it's automatic.
| Tier | Method | Speed | When used |
|---|---|---|---|
| 1 | Plain fetch | ~300ms | Static sites, SSR pages |
| 2 | Headless browser (fast) | ~800ms | Light JS, cached responses |
| 3 | Headless browser (full) | ~3s | SPAs, dynamic content |
| 4 | Stealth browser | ~8s | Bot-protected, CAPTCHA, fingerprint evasion |
| 5 | Text extractor | ~2s | Text/Markdown fallback when rendering fails |
The x-render-source header on every response tells you which tier was used.
Rate limits
| Plan | Requests / minute |
|---|---|
| Free | 5 |
| Starter | 30 |
| Pro | 60 |
| Ultimate | 120 |
429 responses include retry_after_seconds in the JSON body. Rate limits reset every minute on a sliding window.
Agents & MCP
CaptureWeb ships an MCP (Model Context Protocol) server that gives Claude, Cursor, Codex, and any MCP-compatible client the ability to see the web — screenshots, PDFs, clean Markdown, structured JSON, and accessibility trees from any URL.
Install via npx — no separate install step needed. The server connects over stdio and exposes all CaptureWeb endpoints as first-class MCP tools.
Claude Desktop
Open ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) and add:
{
"mcpServers": {
"captureweb": {
"command": "npx",
"args": ["-y", "@captureweb/mcp"],
"env": {
"CAPTUREWEB_API_KEY": "pk_live_YOUR_KEY"
}
}
}
}Restart Claude Desktop. CaptureWeb tools appear in the tool picker automatically.
Cursor
Open Cursor → Settings → MCP and add:
{
"captureweb": {
"command": "npx",
"args": ["-y", "@captureweb/mcp"],
"env": {
"CAPTUREWEB_API_KEY": "pk_live_YOUR_KEY"
}
}
}MCP tools
Every CaptureWeb endpoint is exposed as an MCP tool. Claude can call these directly when you ask it to capture or extract from a URL.
| Tool | Description | Credits |
|---|---|---|
screenshot | Pixel-accurate PNG/JPEG/WebP — returns an inline image block | 1 |
pdf | Export any URL as PDF — returns a resource block | 1 |
markdown | Clean, LLM-ready Markdown — nav/footer stripped | 1 |
content | Full rendered HTML after JS execution | 1 |
links | All hyperlinks as a JSON array | 1 |
scrape | Structured data via CSS selectors | 1 |
json_extract | AI-powered JSON extraction with a plain-English prompt | 1 |
snapshot | Screenshot + Markdown in one navigation | 2 |
a11y | Full ARIA accessibility tree as JSON | 1 |
crawl | Async full-site crawl — returns job ID | 1/page |
Example prompts once connected:
- "Take a screenshot of stripe.com/pricing and describe the layout"
- "Extract all product names and prices from amazon.com as JSON"
- "Get the markdown from the OpenAI blog and summarise the last 5 posts"
- "Check the accessibility tree of github.com — is the main nav keyboard-accessible?"
- "Take a full-page screenshot of linear.app in dark mode"
Skills
A Skill is a YAML file that gives any Claude Code project instant knowledge of the CaptureWeb API — no MCP server required. Drop it in your project and use it as a slash command.
Download captureweb-skill.yaml and save it to .claude/commands/captureweb.md in your project. Then in any Claude Code session, type /captureweb to activate it.
The skill includes the full endpoint reference, auth header format, and caching behaviour — so Claude knows exactly how to call the API without any extra context from you.
Agents.md
captureweb.dev/agents.md is a plain-text reference designed to be fed directly into any AI agent. It covers MCP setup, all 10 tools, REST examples in Python and TypeScript, and caching behaviour.
Paste this into your agent to let it handle setup automatically:
curl -s https://captureweb.dev/agents.md | claude -p "Follow these setup instructions"
Or open the file directly and copy it into any system prompt, CLAUDE.md, or agent context window.
Using the REST API in agent code
Prefer calling the API directly from your agent? Use the Authorization: Bearer header on any endpoint.
import os, requests
API = "https://api.captureweb.dev"
KEY = os.environ["CAPTUREWEB_API_KEY"]
# Extract Markdown for RAG
res = requests.post(f"{API}/v1/markdown",
headers={"Authorization": f"Bearer {KEY}"},
json={"url": "https://openai.com/blog"}
)
markdown = res.json()["markdown"]
# Screenshot
res = requests.post(f"{API}/v1/screenshot",
headers={"Authorization": f"Bearer {KEY}"},
json={"url": "https://stripe.com/pricing", "full_page": True}
)
open("screenshot.png", "wb").write(res.content)const API = "https://api.captureweb.dev"
const KEY = process.env.CAPTUREWEB_API_KEY
// Accessibility tree for agent navigation
const res = await fetch(`${API}/v1/a11y`, {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://github.com" }),
})
const { tree } = await res.json()Cache is automatic — repeated calls to the same URL within 24 hours are free. Pass "fresh": true to force a new render.