API reference · v1
ScrapingBot API documentation
Scrape any website, and pull structured TikTok, Instagram, Google, Amazon and ChatGPT data, with one API key. It's plain HTTPS and JSON, so any language works, and failed requests are refunded automatically.
Base URL
Get an API key
100 free credits, no credit card. Examples use YOUR_API_KEY until you sign in.
Choose an API
Authentication
Every request is authenticated with an API key. Your keys live in the dashboard, where you can also create more and delete old ones. Send the key in whichever of these is most convenient:
- x-api-keyheaderRecommended.
x-api-key: YOUR_API_KEY - AuthorizationheaderBearer token form:
Authorization: Bearer YOUR_API_KEY. Handy for HTTP clients that have built-in bearer auth. - api_keyquery parameterUseful for a quick test in the browser. URLs end up in logs and browser history, so prefer a header in real code.
What is checked, in this order
- A key is present and valid. Otherwise
401. - Your balance is above zero. Otherwise
402. - You have a free concurrency slot. Otherwise
429(see concurrency). - Your balance covers this request's cost. Otherwise
402with the exact amount needed.
None of these rejections cost anything.
Send your key
curl "https://scrapingbot.io/api/v1/scrape?url=https://example.com" \ -H "x-api-key: YOUR_API_KEY"
Rejections
{ "success": false, "error": "API key required. Get yours at /dashboard" }
Quick start
Your first request takes a minute:
- Create a free account. You get 100 credits, no card needed.
- Copy your API key from the dashboard.
- Run the request on the right. It fetches
example.comover plain HTTP for 1 credit. - Read the page from
html.credits_usedtells you what the call cost andjob_idlets you look it up again for 24 hours.
Where to go next
- Page needs JavaScript? Add
render_js=true. - Getting blocked? Try a premium or stealth proxy.
- Want fields, not HTML? Use AI extraction.
- Need social data? Start with TikTok, Instagram, Google or Amazon.
- Building an AI agent? Connect the MCP server.
Request
curl -G "https://scrapingbot.io/api/v1/scrape" \ -H "x-api-key: YOUR_API_KEY" \ --data-urlencode "url=https://example.com"
import requests response = requests.get( "https://scrapingbot.io/api/v1/scrape", headers={"x-api-key": "YOUR_API_KEY"}, params={"url": "https://example.com"}, timeout=60, ) data = response.json() print(data["status"], data["credits_used"])
const params = new URLSearchParams({ url: "https://example.com" }); const response = await fetch(`https://scrapingbot.io/api/v1/scrape?${params}`, { headers: { "x-api-key": "YOUR_API_KEY" }, }); const data = await response.json(); console.log(data.status, data.credits_used);
<?php $query = http_build_query(["url" => "https://example.com"]); $ch = curl_init("https://scrapingbot.io/api/v1/scrape?" . $query); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["x-api-key: YOUR_API_KEY"], ]); $data = json_decode(curl_exec($ch), true); echo $data["status"], " ", $data["credits_used"], PHP_EOL;
Response
{ "success": true, "url": "https://example.com", "html": "<!doctype html><html lang=en><head><meta charset=utf-8><ti…", "status": 200, "duration": "0.79", "credits_used": 1, "job_id": "b8a5d61d-6148-4fb9-b2e6-84a268200472" }
Credits & charging
Every API draws from the same credit balance. The cost of a request is fixed by what you ask for, and responses report what was actually charged: credits_used on every Website API response, creditsUsed on successful TikTok, Instagram, Google and Amazon responses.
Website API costs don't stack
The most capable option you turn on sets the price: stealth proxy, then premium proxy, then rendering, then plain HTTP. AI extraction adds 5 on top. For example, render_js with premium_proxy is 10 credits, and stealth_proxy with ai_query is 80.
When you're charged
- Website API: when the target answers with a 2xx or 3xx status, or with 400 or 404 (the page really doesn't exist or rejected the request, which is still a completed scrape). These come back with
fault: "user". - Refunded automatically: timeouts, blocks and other 4xx answers such as 401, 403 and 429, any 5xx from the target, and errors on our side. These report
credits_used: 0. - Data APIs (TikTok, Instagram, Google, Amazon, ChatGPT): only a successful
200is charged. Any error is refunded. Amazon/productsalso refunds each ASIN it couldn't fetch. - Free: requests rejected before they run, such as a missing parameter, an invalid key or a concurrency limit, and job lookups.
Your balance must cover the full cost when a request starts; otherwise you get a 402 that tells you how many credits are needed.
Cost per request
| Request | Credits |
|---|---|
| Website, plain HTTP | 1 |
| Website, JavaScript renderingrender_js, screenshot or js_scenario | 5 |
| Website, premium proxypremium_proxy, rendered or not | 10 |
| Website, stealth proxystealth_proxy, always rendered | 75 |
| AI extraction add-onai_query or ai_schema | +5 |
| TikTokany endpoint | 1 |
| Instagramany endpoint | 5 |
| Google Searchper search | 10 |
| Amazonany endpoint except /products | 10 |
| Amazon batch products/products, per product returned | 10 |
| ChatGPTper prompt | 10 |
Concurrency & plans
Limits are based on how many requests you have in flight at the same time, not on requests per minute. Each plan has a concurrency limit; a slot is taken when a request starts and freed as soon as its response is sent.
Going over the limit returns 429 immediately and costs nothing. Size your worker pool to your plan's limit, and retry a 429 after a short, growing delay.
Calls made through the MCP server use the same slots and credits as direct API calls.
| Plan | Price | Credits | Concurrent |
|---|---|---|---|
| Free | $0 | 100 on sign-up | 1 |
| Starter | $49.99 / mo | 275,000 / mo | 10 |
| Startup | $99.99 / mo | 1,100,000 / mo | 50 |
| Pro | $249.99 / mo | 3,300,000 / mo | 100 |
| Business | $599.99 / mo | 9,000,000 / mo | 200 |
| Business+ | $999.99 / mo | 15,500,000 / mo | 200 |
Paid plans refresh their credits every billing cycle. Compare plans on the plans page.
A worker pool sized to your plan
import time import requests from concurrent.futures import ThreadPoolExecutor API_KEY = "YOUR_API_KEY" CONCURRENCY = 10 # your plan's limit def scrape(url): for attempt in range(5): r = requests.get( "https://scrapingbot.io/api/v1/scrape", headers={"x-api-key": API_KEY}, params={"url": url}, timeout=60, ) if r.status_code != 429: return r.json() time.sleep(2 ** attempt) # every slot is busy: wait, then retry raise RuntimeError("still at the concurrency limit") urls = ["https://example.com/a", "https://example.com/b"] with ThreadPoolExecutor(max_workers=CONCURRENCY) as pool: for result in pool.map(scrape, urls): print(result["status"], result["credits_used"])
Errors
Errors come back as JSON with success: false and a readable error message. Depending on the API you'll also see:
status: the HTTP status, on Website API responses and on most credit and concurrency errors.fault: on Website API failures, who caused it.usermeans the target page answered 400 or 404 (charged),systemmeans the site or our side failed (refunded),timeoutmeans it ran past 45 seconds (refunded).code: on TikTok errors, the same number as the HTTP status.
Retrying
Retry 408, 429, 502 and other 5xx responses with exponential backoff; they're refunded, so a retry never pays twice. Don't retry 400, 401 or 402 without changing something first.
Examples
{ "success": false, "status": 400, "error": "Missing required parameter: url" }
| Status | What happened | Charged |
|---|---|---|
| 400 | A parameter is missing or invalid, or the endpoint isn't supported. On the Website API, also a target page that answered 400 (fault: "user"). | Only target 400s |
| 401 | The API key is missing or invalid. | No |
| 402 | Your balance is empty, or too low for this request. | No |
| 404 | Website API: the target page doesn't exist (fault: "user"). Data APIs: the profile, post or product wasn't found. Also an unknown /api route or job ID. | Only target 404s |
| 405 | The MCP endpoint was called with something other than POST. | No |
| 408 | The request timed out. | No |
| 413 | The request body is larger than 1 MB. | No |
| 429 | Your plan's concurrency limit is reached. | No |
| 500, 502, 503… | The target site failed, a data source was temporarily unavailable, or something went wrong on our side. | No |
Stuck on something?
Try requests in the dashboard playgrounds, check every call in your usage log, or write to [email protected]. A real developer answers.