Start with one command.
Give Haunt a web page and a plain-English prompt. It returns clean JSON, or Markdown when you need page text. Pick the agent command if you use Claude, Cursor, or Windsurf. Pick the REST curl if you are writing code.
Three steps.
- Get a free keyNo credit card. Keep the key private.
- Run one commandAgent command for AI tools. REST curl for apps and scripts.
- Use JSON or MarkdownIf it fails, Haunt tells you why instead of inventing data.
Using an AI agent? Run this.
This gives your agent a Haunt tool it can call when it needs web data.
npx -y --package @hauntapi/cli@latest haunt-cli init
curl -sS https://hauntapi.com/agents/skill.md
pip install hauntapi
Writing code? Use this curl.
Replace the key, change the URL and prompt, then run it. Use X-API-Key for your API key. That is the first real API call.
- Paste your key: replace
PASTE_YOUR_KEY_HERE. - Change the page: start with
https://example.com, then use your own URL. - Check the result: look for
"success": true. If it failed, readerror_codeandmessage.
curl -sS https://hauntapi.com/v1/extract -H "Content-Type: application/json" -H "X-API-Key: PASTE_YOUR_KEY_HERE" -d '{"url":"https://example.com","prompt":"Extract the page title"}'What you send.
Send a public URL and say what you want back. Haunt returns JSON, Markdown, raw HTML, screenshots, or a clear failure.
Request bodies are processed to produce your result, not kept as scrape history. Page content is never stored, results are cached only if you set max_age, and submitted URLs and prompts are deleted after 60 days.
| Field | Use |
|---|---|
url | The page to read. |
prompt | What you want back, in plain English. |
response_format | Optional. markdown for clean page text, otherwise JSON. |
device | Optional. mobile or desktop to force that browser profile. |
schema | Optional. A JSON Schema for the exact shape. A mismatch fails as schema_validation_failed, never a wrong guess. |
max_age | Optional. Seconds to cache a repeat of the same call. Max 24 hours. |
js_scenario | Paid. Up to 10 browser steps first: wait, wait_for, click, scroll, fill. |
Extract from a list in one call.
Send up to 20 URLs to /v1/extract/batch in one call. Each item can carry its own prompt and schema, or use the batch-level ones.
Only successful items are charged. A blocked or bad URL fails on its own, it does not sink the rest. Batch is on every plan; higher tiers just run more at once.
counttotal itemssucceededhow many workedcredits_usedtotal chargedresultsin the order you sent
curl -sS https://hauntapi.com/v1/extract/batch -H "Content-Type: application/json" -H "X-API-Key: PASTE_YOUR_KEY_HERE" -d '{
"prompt": "product name and price",
"schema": { "type": "object", "properties": { "name": {"type":"string"}, "price": {"type":"string"} }, "required": ["name"] },
"items": [
{ "url": "https://example.com/product/1" },
{ "url": "https://example.com/product/2" }
]
}'The response tells you what happened.
data is the answer. trace is the receipt: where it fetched from, which mode, and how confident it is.
The example is the quickstart call. example.com is nearly empty, so Haunt answers from page metadata and reports the low confidence honestly. Content-rich pages use llm mode with higher confidence.
When a call fails, diagnostics gives your agent something to branch on:
reasona normalised causeproviderwhen knownretryablewhether to try againsuggested_actionwhat to do next
{
"success": true,
"data": { "title": "Example Domain" },
"charged": true,
"credits_used": 2,
"credits_remaining": 998,
"confidence": 0.6,
"trace": {
"fetch": { "source": "direct" },
"extraction": { "mode": "metadata_fallback", "confidence": 0.6 }
}
}When Haunt says no.
If a page is login-only, blocked, too thin, or needs human verification, Haunt says so. It does not solve CAPTCHAs, bypass login walls, or make up missing data.
No matching data was visible? Try a narrower prompt. Check trace and evidence to see what happened.
{
"success": false,
"error_code": "not_found",
"mode": "not_found",
"error": "Could not find requested data in the page content",
"message": "Could not find requested data in the page content",
"charged": false,
"credits_used": 0
}captcha_requiredThe page wants human verification.
login_requiredThe page is behind a login.
access_deniedThe site refused the request.
thin_public_contentNot enough public content to answer from.
schema_validation_failedThe data did not match your schema.
not_foundNo matching data on the page. Try a narrower prompt.
missing_api_keyNo key was sent with the request.
invalid_api_keyThe key is wrong or has been regenerated.
invalid_requestThe request body is malformed.
monthly_quota_exceededNo credits left this month.
rate_limit_exceededToo many requests in a minute.
concurrency_limit_exceededToo many calls running at once.
account_suspendedThe account is disabled.
Getting past blocks.
Plenty of shops turn away anything coming from a cloud server. On paid plans, when a normal request is blocked Haunt retries the page through a residential proxy: a real home broadband connection running a real browser. That reaches many sites that block cloud traffic, some behind Cloudflare included.
- Automatic on paid plans, and only when a page is actually blocked
- Costs 10 credits instead of the usual 2, because that traffic is expensive to buy
- If the page still will not load, you pay nothing
It is best effort, not a promise to open every page.
Credits and limits.
Credits are not one-to-one with requests. Failed, blocked, login, CAPTCHA, provider, and server errors never burn credits, and Haunt does not bill automatic overages. Very large pages add a small surcharge, shown below. Go over your per-minute rate and you get a 429 with a Retry-After header: wait, then retry with a simple backoff. Upgrade anytime on the pricing page.
- Simple public fetch or non-LLM output1
- Normal structured extraction2
- JavaScript-rendered, waited, or viewport screenshot4
- Authenticated structured extraction4
- Residential proxy fetch (paid plans, on a block)10
- Full-page screenshot, large page, or heavy browser8
- Large-page surcharge, per ~10k tokens of content+1, up to +3
curl -sS https://hauntapi.com/v1/extract/usage -H "X-API-Key: PASTE_YOUR_KEY_HERE"
Need Markdown instead of JSON?
JSON is the default. Set response_format to markdown for clean page text, for an agent, RAG, notes, or a .md file. raw_html and screenshot are there for lower-level needs. Big screenshots return screenshot_too_large instead of a huge image.
curl https://hauntapi.com/v1/extract \
-H "Content-Type: application/json" \
-H "X-API-Key: $HAUNT_API_KEY" \
-d '{"url":"https://example.com","prompt":"Return Markdown","response_format":"markdown"}'