docs

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.

  1. Get a free keyNo credit card. Keep the key private.
  2. Run one commandAgent command for AI tools. REST curl for apps and scripts.
  3. Use JSON or MarkdownIf it fails, Haunt tells you why instead of inventing data.
agent setup

Using an AI agent? Run this.

This gives your agent a Haunt tool it can call when it needs web data.

recommended Install for your agent Use this for Claude, Cursor, Windsurf, or any MCP-compatible client.
npx -y --package @hauntapi/cli@latest haunt-cli init
agent-readable Let the agent read setup Give this to an agent that needs the setup steps before it calls tools.
curl -sS https://hauntapi.com/agents/skill.md
python Wire it into a Python agent For LangChain, LlamaIndex, or CrewAI. One install gives the client and the tools.
pip install hauntapi
Hosted MCP details

Hosted clients can use https://hauntapi.com/mcp/server with bearer auth. Local MCP uses @hauntapi/mcp-server.

Agents can call try_demo_extract before you add a key, then extract for JSON or extract_markdown for clean page text. Hosted MCP also accepts extract_url as a compatibility alias.

Hosted no-key demo
curl -sS https://hauntapi.com/mcp/server -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"try_demo_extract","arguments":{}}}'
Hosted real extraction
curl -sS https://hauntapi.com/mcp/server -H "Content-Type: application/json" -H "Authorization: Bearer PASTE_YOUR_KEY_HERE" -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"extract","arguments":{"url":"https://example.com","prompt":"Extract the page title"}}}'
Hosted usage check
curl -sS https://hauntapi.com/mcp/server -H "Content-Type: application/json" -H "Authorization: Bearer PASTE_YOUR_KEY_HERE" -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_usage","arguments":{}}}'
rest api

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.

  1. Paste your key: replace PASTE_YOUR_KEY_HERE.
  2. Change the page: start with https://example.com, then use your own URL.
  3. Check the result: look for "success": true. If it failed, read error_code and message.
Get a free key
REST curl
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"}'
request

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.

FieldUse
urlThe page to read.
promptWhat you want back, in plain English.
response_formatOptional. markdown for clean page text, otherwise JSON.
deviceOptional. mobile or desktop to force that browser profile.
schemaOptional. A JSON Schema for the exact shape. A mismatch fails as schema_validation_failed, never a wrong guess.
max_ageOptional. Seconds to cache a repeat of the same call. Max 24 hours.
js_scenarioPaid. Up to 10 browser steps first: wait, wait_for, click, scroll, fill.
many urls

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 items
  • succeededhow many worked
  • credits_usedtotal charged
  • resultsin the order you sent
batch curl
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" }
  ]
}'
response

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 cause
  • providerwhen known
  • retryablewhether to try again
  • suggested_actionwhat to do next
simple response
{
  "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 }
  }
}
failures

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.

not_found
{
  "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
}
Extraction failures
captcha_required

The page wants human verification.

login_required

The page is behind a login.

access_denied

The site refused the request.

thin_public_content

Not enough public content to answer from.

schema_validation_failed

The data did not match your schema.

not_found

No matching data on the page. Try a narrower prompt.

Bad first request
missing_api_key

No key was sent with the request.

invalid_api_key

The key is wrong or has been regenerated.

invalid_request

The request body is malformed.

monthly_quota_exceeded

No credits left this month.

rate_limit_exceeded

Too many requests in a minute.

concurrency_limit_exceeded

Too many calls running at once.

account_suspended

The account is disabled.

hard-to-reach pages

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.

costs

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.

What each call costs
  • 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
What each plan includes
PlanMonthly creditsRateScope
Free1,00010/minPublic pages
Starter10,00030/minResidential proxy
Pro30,00060/minResidential proxy · your headers (beta)
Scale80,000120/minResidential proxy · your headers (beta)
Check your balance anytime:
check credits
curl -sS https://hauntapi.com/v1/extract/usage -H "X-API-Key: PASTE_YOUR_KEY_HERE"
advanced

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.

advanced output
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"}'