API Reference
UnblockingAPI is a web unblocker API that fetches public URLs and returns clean HTML — with optional JavaScript rendering, geo-routing and smart wait strategies for dynamic pages.
https://api.unblockingapi.comWant to test requests directly in your browser? Open the interactive Swagger UI to explore endpoints and try them live with your API key.
Quick start
Grab your API key and make your first request:
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://api.unblockingapi.com/unblock?url=https://example.com"Prefer hands-on help?
Our developers can help integrate UnblockingAPI into your existing application or scraper.
Get setup helpAuthentication
Every request needs your API key, sent any one of these ways:
X-Api-Key: <key>headerrecommendedAuthorization: Bearer <key>header?key=<key>query parameterhandy for quick browser tests# Header (recommended)
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://api.unblockingapi.com/unblock?url=https://example.com"
# Bearer token
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.unblockingapi.com/unblock?url=https://example.com"
# Query parameter
curl "https://api.unblockingapi.com/unblock?url=https://example.com&key=YOUR_API_KEY"Rate limits
Rate limits depend on your plan and are enforced per API key.
Each plan includes:
- a monthly credit allowance — one successful request costs 1 credit
- a concurrent request limit
- fair use and abuse prevention controls
Exceeding your concurrency limit returns 429; running out of credits returns 402. See Pricing for current plan limits.
Some plans may also include short-window burst limits to protect reliability.
/unblock
Fetch a public URL and get clean HTML back. Both GET and POST are supported — POST takes a JSON body with the same fields.
/unblock# GET request
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://api.unblockingapi.com/unblock?url=https://example.com"
# POST request
curl -X POST \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "render": true}' \
"https://api.unblockingapi.com/unblock"Parameters
urlstringrequiredURL to fetch. Must be http(s) and not point at a media/binary file.
renderbooleandefault: falseRender with a real browser (executes JavaScript). Required for the wait options. Slower than a plain fetch — try without it first, and only enable it if the response is missing content. Renders fetch the document and the scripts that build it; CSS, images and fonts are always skipped, since they only add transfer time for bytes that never reach your response.
locationstring2-letter country code for geo-routing where supported. Examples: us, gb, de.
wait_forstringdefault: stableWhen to capture the page (requires render=true). One of stable — capture once the DOM stops changing, domcontentloaded — capture immediately, networkidle — wait for the network to go quiet, or any CSS selector, which waits for that element to become visible and then settles. See Waiting for content.
settle_msintegerdefault: 5000Ceiling on the settle wait — not a fixed delay. Max 25000. Applies to stable and selector waits.
wait_rulesarrayConditional waits for pages with more than one possible layout. Each if selector is probed in order; the first visible one wins and its then replaces wait_for.
detect_msintegerdefault: 800How long to probe wait_rules guards before falling back to wait_for. Max 25000.
max_ageintegerdefault: 0Opt-in response cache. Accept a previously fetched copy of the same page, up to this many seconds old, instead of fetching again. Max 300. A hit returns in milliseconds and carries cached: true. Worth it when you poll the same URLs on a fixed interval. Leave it at 0 and every request fetches fresh — nothing is cached, read or written unless you ask.
templatestringParse the page with a named template and return structured JSON instead of HTML. Takes a reference like rasmus/cafes. The template supplies the fetch settings its parser needs, which override the ones you send. See Templates.
remove_scriptsbooleandefault: trueStrip <script> tags. On by default. Scripts are removed in the render worker before the page is sent back, so this also cuts transfer time.
remove_stylesheetsbooleandefault: trueStrip <style> tags and stylesheet links. On by default, and removed in the render worker. Inline style attributes are always kept.
remove_svgsbooleandefault: trueStrip <svg> tags from the returned HTML. On by default.
Response format
Every response follows the same envelope:
{
"job_id": "abc123",
"url": "https://example.com",
"status": "succeeded",
"http_response_code": 200,
"response_time_ms": 1250,
"render": false,
"location": "de",
"response_format": "html",
"response": "<!doctype html>..."
}job_idstringUnique ID for this request.
urlstringThe URL that was fetched.
status"succeeded" | "failed""succeeded" for 2xx and 404 targets; "failed" otherwise.
http_response_codeintegerThe target's actual HTTP status code. On a 500 response, this holds the real upstream code (e.g. 403, 429).
response_time_msintegerTime taken in milliseconds.
renderbooleanWhether browser rendering was used.
locationstring | nullCountry code used, or null.
response_format"html" | "json""html" normally, "json" when you named a template and its parser ran.
responsestring | objectThe HTML as a string, or the parsed object when a template ran.
api_namestringPresent only when you named a template. The template that answered.
parse_errorbooleanPresent (true) only when a template’s parser failed and you got raw HTML instead. See Templates.
cachedbooleanPresent (true) only when max_age was set and the response came from the cache. A hit still costs one credit.
errorstringPresent only when status is "failed".
Waiting for content
Dynamic pages finish loading long after the HTML arrives. These options say when to capture. All require render=true.
wait_for
stabledefaultCapture once the DOM stops changing. Best default for most pages — it adapts to whatever the page is doing instead of guessing a duration.
domcontentloadedfastestCapture immediately. Use when the content you want is in the initial HTML.
networkidlestringWait for the network to go quiet. Avoid on pages that poll — see the note below.
<css selector>stringAny other value is treated as a CSS selector: wait for that element to become visible, then settle. The most precise option when you know what you are looking for.
On pages that never go quiet — live scores, tickers, chat, polling widgets — networkidle will wait out its whole budget and return no sooner than the timeout. Prefer stable or a selector.
settle_ms — a ceiling, not a delay
Settling watches the page and captures as soon as nothing in the DOM has changed for 500 ms; every change restarts that window. A page that goes quiet after 900 ms comes back after 900 ms — settle_ms only caps how long that can take. Reaching it means the page never stopped changing, and it is captured as it is.
Raise it for pages that keep streaming content in (infinite scroll, lazily loaded sections); lower it to bound the worst case. It applies to stable and to selector waits, and is ignored for domcontentloaded and networkidle.
wait_rules — one request, several layouts
Some pages serve more than one layout: a consent gate, an interstitial, an A/B variant, a logged-out fallback. Rather than guessing which you will get, describe each one. Every if selector is probed in list order for up to detect_ms; the first one that is visible wins, and its then replaces wait_for for that request. If nothing matches, wait_for is used as normal.
An empty then means “this layout matched, capture it now”.
Examples
// Wait for results to become visible, then settle
{ "url": "https://example.com/search?q=shoes", "render": true, "wait_for": "#results" }
// A page that keeps loading content in — allow longer to go quiet
{ "url": "https://example.com/feed", "render": true,
"wait_for": "stable", "settle_ms": 12000 }
// Two possible layouts: a consent gate, or the results directly
{ "url": "https://example.com/search?q=shoes", "render": true,
"wait_for": "#results",
"wait_rules": [{ "if": "#consent-gate", "then": "#results" }],
"detect_ms": 800 }On a GET, pass wait_rules as a JSON string.
Error codes
200Success — the target returned a 2xx. Body carries the fetched content.
401Missing or invalid API key.
404Target returned 404. Treated as a successful result (status is "succeeded"), not a failure.
402Out of credits. Top up or upgrade your plan to resume.
422Invalid parameters — check the error message for details.
429Concurrency limit exceeded. Back off and retry.
500Request failed due to an upstream error, block, captcha challenge or render failure. Check http_response_code and error for details.
503Service temporarily unavailable — proxy pool exhausted or render backend saturated. Retry shortly.
504Timed out waiting for the target or render backend.
Working on a tricky target? Talk to us — we can help tune routing, rendering and request strategy for your use case.
Templates
A template turns one kind of page into clean JSON. Name one on your request and you get parsed fields back instead of HTML, from the same /unblock endpoint, with the same key and the same cost.
Templates are unlimited on every plan, the free one included. There is no approval step and no separate endpoint.
Naming one
Pass template with the template’s reference, which is its author’s handle and its slug. Nothing is ever applied unless you ask for it — omit the parameter and the same URL returns plain HTML, whatever templates exist for that site.
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://api.unblockingapi.com/unblock?url=https://example.com/listing&template=rasmus/cafes"The template also supplies the fetch settings its parser needs, and those win over yours — a template built against a JavaScript-rendered page will render whether or not you asked for it, and is billed like any render. The response names the template in api_name and sets response_format to json, so response is an object rather than a string.
{
"job_id": 86,
"url": "https://example.com/listing",
"status": "succeeded",
"http_response_code": 200,
"response_time_ms": 812,
"render": true,
"location": "se",
"response_format": "json",
"api_name": "cafes",
"response": {
"title": "Kafé Esaias",
"address": "Stora Nygatan 21",
"rating": 4.6
}
}When something goes wrong
A template is a reading of someone else’s markup, and markup changes. So a parser that breaks never costs you the response: you get the raw HTML back with parse_error: true and response_format back to html, rather than an error. Check that flag if you parse strictly.
A name that does not resolve is a 404, which covers both an unknown template and a private one belonging to somebody else. If the target itself answers with a non-2xx, the page is returned unparsed and still tagged with api_name — there was no page to read.
Where templates come from
You build them. Open a page in the editor, tap the things you want, and it writes a template that returns them. Publish it and it appears in the template library, where anyone can open, fork or call it — and you earn credits when a paying customer calls yours. The API reference lists every published template with the site it is built for.
Use must comply with the Acceptable Use Policy.
Open-source MCP server
@unblockingapi/mcp exposes this API to AI agents over MCP. Source and package are public.