curl -sS -X POST "https://api.adscrawl.net/spa-extract" \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"url": "https://example.com/dashboard",
"mode": "extract",
"waitUntil": "domcontentloaded",
"waitFor": { "selector": "h1", "timeoutMs": 15000 },
"fields": {
"title": { "source": "dom", "selector": "h1", "parse": "string" },
"subtitle": { "source": "dom", "selector": "p.subtitle", "parse": "string" },
"count": { "source": "dom", "selector": ".metric-value", "parse": "number" }
},
"countryCode": "GLOBAL",
"userAgentMode": "random"
}'
const response = await fetch("https://api.adscrawl.net/spa-extract", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": "YOUR_API_KEY",
},
body: JSON.stringify({
url: "https://example.com/dashboard",
mode: "extract",
waitUntil: "domcontentloaded",
waitFor: { selector: "h1", timeoutMs: 15000 },
fields: {
title: { source: "dom", selector: "h1", parse: "string" },
subtitle: { source: "dom", selector: "p.subtitle", parse: "string" },
count: { source: "dom", selector: ".metric-value", parse: "number" },
},
countryCode: "GLOBAL",
userAgentMode: "random",
}),
});
const result = await response.json();
console.log(result.data);
import httpx
response = httpx.post(
"https://api.adscrawl.net/spa-extract",
headers={
"content-type": "application/json",
"x-api-key": "YOUR_API_KEY",
},
json={
"url": "https://example.com/dashboard",
"mode": "extract",
"waitUntil": "domcontentloaded",
"waitFor": {"selector": "h1", "timeoutMs": 15000},
"fields": {
"title": {"source": "dom", "selector": "h1", "parse": "string"},
"subtitle": {"source": "dom", "selector": "p.subtitle", "parse": "string"},
"count": {"source": "dom", "selector": ".metric-value", "parse": "number"},
},
"countryCode": "GLOBAL",
"userAgentMode": "random",
},
)
response.raise_for_status()
print(response.json()["data"])
{
"mode": "extract",
"page": {
"url": "https://example.com/dashboard",
"title": "Example Dashboard"
},
"data": {
"title": "Example Dashboard"
},
"missingFields": []
}
{
"mode": "inspect",
"page": {
"url": "https://example.com/dashboard",
"title": "Example Dashboard"
},
"candidates": {
"dom": { "metrics": [], "tables": [] },
"network": []
},
"suggestedPlan": {
"fields": {},
"schema": {
"type": "object",
"properties": {},
"additionalProperties": false
}
}
}
{
"mode": "extract",
"page": {
"url": "https://trends.google.com/trends/explore?q=adspower%2Cplaywright",
"title": "Google Trends"
},
"data": {
"averages": [
{ "query": "adspower", "extractedValue": 42 },
{ "query": "playwright", "extractedValue": 71 }
],
"interestOverTime": []
},
"missingFields": [],
"source": "sunbrowser",
"cached": false,
"stale": false,
"collectedAt": "2026-08-03T02:04:05.123456789Z",
"attempts": 2
}
{
"code": "INSUFFICIENT_CREDITS"
}
{
"code": "SPA_REQUIRED_FIELDS_MISSING"
}
Browser Tasks
Extract SPA Data
Extract structured data from JavaScript-heavy SPAs using custom CSS or network fields, built-in templates, or inspect mode to discover extraction candidates.
POST
/
spa-extract
curl -sS -X POST "https://api.adscrawl.net/spa-extract" \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"url": "https://example.com/dashboard",
"mode": "extract",
"waitUntil": "domcontentloaded",
"waitFor": { "selector": "h1", "timeoutMs": 15000 },
"fields": {
"title": { "source": "dom", "selector": "h1", "parse": "string" },
"subtitle": { "source": "dom", "selector": "p.subtitle", "parse": "string" },
"count": { "source": "dom", "selector": ".metric-value", "parse": "number" }
},
"countryCode": "GLOBAL",
"userAgentMode": "random"
}'
const response = await fetch("https://api.adscrawl.net/spa-extract", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": "YOUR_API_KEY",
},
body: JSON.stringify({
url: "https://example.com/dashboard",
mode: "extract",
waitUntil: "domcontentloaded",
waitFor: { selector: "h1", timeoutMs: 15000 },
fields: {
title: { source: "dom", selector: "h1", parse: "string" },
subtitle: { source: "dom", selector: "p.subtitle", parse: "string" },
count: { source: "dom", selector: ".metric-value", parse: "number" },
},
countryCode: "GLOBAL",
userAgentMode: "random",
}),
});
const result = await response.json();
console.log(result.data);
import httpx
response = httpx.post(
"https://api.adscrawl.net/spa-extract",
headers={
"content-type": "application/json",
"x-api-key": "YOUR_API_KEY",
},
json={
"url": "https://example.com/dashboard",
"mode": "extract",
"waitUntil": "domcontentloaded",
"waitFor": {"selector": "h1", "timeoutMs": 15000},
"fields": {
"title": {"source": "dom", "selector": "h1", "parse": "string"},
"subtitle": {"source": "dom", "selector": "p.subtitle", "parse": "string"},
"count": {"source": "dom", "selector": ".metric-value", "parse": "number"},
},
"countryCode": "GLOBAL",
"userAgentMode": "random",
},
)
response.raise_for_status()
print(response.json()["data"])
{
"mode": "extract",
"page": {
"url": "https://example.com/dashboard",
"title": "Example Dashboard"
},
"data": {
"title": "Example Dashboard"
},
"missingFields": []
}
{
"mode": "inspect",
"page": {
"url": "https://example.com/dashboard",
"title": "Example Dashboard"
},
"candidates": {
"dom": { "metrics": [], "tables": [] },
"network": []
},
"suggestedPlan": {
"fields": {},
"schema": {
"type": "object",
"properties": {},
"additionalProperties": false
}
}
}
{
"mode": "extract",
"page": {
"url": "https://trends.google.com/trends/explore?q=adspower%2Cplaywright",
"title": "Google Trends"
},
"data": {
"averages": [
{ "query": "adspower", "extractedValue": 42 },
{ "query": "playwright", "extractedValue": 71 }
],
"interestOverTime": []
},
"missingFields": [],
"source": "sunbrowser",
"cached": false,
"stale": false,
"collectedAt": "2026-08-03T02:04:05.123456789Z",
"attempts": 2
}
{
"code": "INSUFFICIENT_CREDITS"
}
{
"code": "SPA_REQUIRED_FIELDS_MISSING"
}
Submit a page URL and extraction configuration to retrieve structured data from a JavaScript-rendered SPA. You can use custom field definitions, a built-in template, or
inspect mode to discover what data is available on a page.
string
Full HTTP(S) URL for the target SPA using port 80 or 443. Required for most templates. For
google-trends-explore, prefer the keyword field instead. SimilarWeb requires a full page URL, not a bare domain.string
Recommended for
google-trends-explore. Provide 1 to 5 unique, non-empty comma-separated keywords, each at most 100 Unicode characters (for example, "adspower,playwright"). The server builds the canonical Trends URL automatically. Explicit null, numeric, or empty-string values return INVALID_KEYWORD and never fall back to url.string
Extraction mode. Defaults to
"extract".| Value | Behaviour |
|---|---|
"extract" | Runs field or template extraction and returns structured data. |
"inspect" | Returns DOM and network candidates discovered on the page along with a suggestedPlan you can copy into a future extract request. |
string
Built-in site template ID. When provided,
fields are supplied by the template rather than your request. Available template IDs:"similarweb-overview"— website traffic, engagement, and ranking metrics."google-trends-explore"— interest-over-time data and relative averages for up to 5 keywords."chrome-web-store-app-info"— extension metadata from the Chrome Web Store (with CRX manifest fallback).
object
Template-specific parameters declared by the selected template. Refer to the template’s
input specification from GET /spa-extract/templates.string
Navigation event to wait for before extraction. Custom extraction defaults to
"domcontentloaded". Site templates use the request value first, then the template default, then "domcontentloaded".| Value | Behaviour |
|---|---|
"domcontentloaded" | Waits for DOMContentLoaded — recommended for most SPAs. |
"load" | Waits for window.load including images and stylesheets. |
"networkidle" | Waits until no network connections for 500 ms. May timeout on long-polling sites. |
object
Wait for a specific element or text to appear after SPA navigation and actions complete.
selector and text may be combined.array
Optional page interactions executed in array order before extraction. Each step is capped at 30 seconds.
Show action types
Show action types
object
{ type: "wait", milliseconds: number } — Pause for 0 to 30,000 ms.object
{ type: "waitForSelector", selector: string, timeoutMs?: number } — Wait for an element to become visible.object
{ type: "click", selector: string } — Click the first matching element.object
{ type: "fill", selector: string, value: string } — Clear and fill the first matching input.object
{ type: "press", selector: string, key: string } — Press a key on the first matching element.object
{ type: "scroll", selector?: string, x?: number, y?: number } — Scroll an element into view or scroll the page. y defaults to 800.object
Record of named field definitions for
extract mode. Each key becomes a property in the response data object. Use this when you are not using a template.Show field definition
Show field definition
string
required
"dom" to read from the page HTML, or "network" to read from intercepted JSON responses.string
CSS selector for a DOM field.
string
DOM read mode:
"text" (default), "html", or "attribute".string
Attribute name, used when
value is "attribute".string
Substring to match against a response URL for a network field.
string
JSON path within the matched network response, for example
$.data.metrics[0].value.boolean
Whether a DOM field should return all matching elements as an array.
string
Coerce the value to
"string", "number", "integer", "boolean", or "json".string
Optional regular expression. When a capture group is present, group 1 is used.
boolean
Missing required fields return
422 SPA_REQUIRED_FIELDS_MISSING.object
Legacy alias for
fields, used only when fields is absent. String values are treated as DOM CSS selectors. Does not validate the response JSON and does not return schemaValid or schemaErrors fields. Prefer fields for all new integrations.number
Maximum time to wait for the task to complete, in milliseconds. Must be a positive integer no greater than
3,600,000.object
string
Browser locale, for example
"en-US". May follow trusted proxy metadata when omitted.string
IANA timezone identifier, for example
"Asia/Shanghai". May follow trusted proxy metadata when omitted.object
object
Custom proxy configuration. Cannot be combined with
countryCode.Show proxy fields
Show proxy fields
string
Full proxy URL such as
http://host:port or socks5://host:port. Cannot be combined with host.string
"http" or "socks5". Used in the split form.string
Proxy host. Used in the split form.
number | string
Port from 1 to 65535.
string
Proxy username. Must be supplied together with
password.string
Proxy password. Must be supplied together with
username.string
Managed residential proxy region. Cannot be combined with
proxy."GLOBAL"— dynamic exit from 15 popular regions.- Two-letter country code — prefers a trusted proxy with dynamic fallback.
- Omitted — a random trusted proxy is selected automatically.
string
"random" lets the server pick a User-Agent from its library. Requests without an explicit userAgent default to "random".string
Operating system used when
userAgentMode is "random". Accepted values: "windows" (default) or "macos".string
Explicit User-Agent string. Overrides the random selection.
object
Browser fingerprint settings. When omitted, every signal defaults to random while keeping OS, GPU, CPU, memory, fonts, and device signals coherent.
Show fingerprint fields
Show fingerprint fields
string
"forward", "real", or "disabled".string
"random" or "real". Controls WebGL vendor and renderer metadata.string
"random", "real", or "disabled".string
"random" or "real". Controls WebGL image noise.string
"random" or "real". Controls canvas noise.string
"random" or "real". Controls audio fingerprint noise.string
"random" or "real". Controls layout measurement noise.string
"random" or "real". Returns an OS-matched speech voice list.string
"random" or "real". Returns an OS-matched font list.string
"random" or "real". Generates a coherent CPU thread count and memory pair.string
"random", "enabled", or "disabled".array
Cookie list injected into the browser context before navigation.
google-trends-explore ignores omitted, null, or empty-array values. Any non-empty or malformed cookies on a Trends request return 400 INVALID_TRENDS_COOKIES.Show cookie fields
Show cookie fields
string
required
Cookie name.
string
required
Cookie value.
string
required
Target domain such as
.example.com.string
Cookie path. Defaults to
/.boolean
Whether the cookie is sent only over HTTPS.
boolean
Whether the cookie is inaccessible to client-side JavaScript.
string
SameSite attribute.
boolean
Set
true for a session cookie.number
Unix expiry timestamp in seconds. Also accepted as
expires or expiry.Response
string
"extract" or "inspect", mirroring the request mode.object
Extracted structured data. Keys match your
fields definition or the template’s output fields.array
List of field keys that were not found.
string
"sunbrowser" — result came from a live browser collection. "cache" — result was served from the server cache. Present on Trends responses.boolean
Whether this response was served from cache.
boolean
Whether the cached result is stale.
string
RFC3339Nano timestamp of when the result was actually collected.
number
Collection attempt count. Cache HIT responses use
0; stale responses use the attempt count at the time the Worker reported them.object
Present in
inspect mode. DOM and network extraction candidates discovered on the page.object
Present in
inspect mode. A plan with fields and schema you can copy into a future extract request.| Code | Meaning |
|---|---|
| 200 | Inspection results or extracted structured data. |
| 400 | Invalid URL, keyword, proxy, region, User-Agent, or Trends cookies. |
| 401 | Missing or invalid x-api-key. |
| 402 | Insufficient balance (INSUFFICIENT_CREDITS). |
| 404 | Chrome Web Store listing unavailable and CRX fallback could not recover it. |
| 422 | Required fields missing, invalid template or field config, or Worker rejected the task. |
| 429 | Task rate limited, or Google Trends upstream 429. |
| 502 | Proxy or target failure, invalid Trends data, or all candidate identities exhausted. |
| 503 | Queue, Worker, or managed resources unavailable; or Trends identity plan expired. |
| 504 | Task, navigation, or proxy timeout; or Trends response not observed. |
| 500 | Unclassified task execution failure. |
One credit is consumed after request validation but before the task is enqueued. Request bodies are limited to 1 MiB.
More examples
curl -sS -X POST "https://api.adscrawl.net/spa-extract" \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"url": "https://example.com/dashboard",
"mode": "extract",
"waitUntil": "domcontentloaded",
"waitFor": { "selector": "h1", "timeoutMs": 15000 },
"fields": {
"title": { "source": "dom", "selector": "h1", "parse": "string" },
"subtitle": { "source": "dom", "selector": "p.subtitle", "parse": "string" },
"count": { "source": "dom", "selector": ".metric-value", "parse": "number" }
},
"countryCode": "GLOBAL",
"userAgentMode": "random"
}'
curl -sS -X POST "https://api.adscrawl.net/spa-extract" \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"template": "similarweb-overview",
"url": "https://www.similarweb.com/website/dolphin-anty.com/#overview",
"countryCode": "GLOBAL"
}'
curl -sS -X POST "https://api.adscrawl.net/spa-extract" \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"template": "google-trends-explore",
"keyword": "adspower,playwright"
}'
curl -sS -X POST "https://api.adscrawl.net/spa-extract" \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"url": "https://example.com/dashboard",
"mode": "inspect"
}'
curl -sS -X POST "https://api.adscrawl.net/spa-extract" \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"url": "https://example.com/dashboard",
"mode": "extract",
"waitUntil": "domcontentloaded",
"waitFor": { "selector": "h1", "timeoutMs": 15000 },
"fields": {
"title": { "source": "dom", "selector": "h1", "parse": "string" },
"subtitle": { "source": "dom", "selector": "p.subtitle", "parse": "string" },
"count": { "source": "dom", "selector": ".metric-value", "parse": "number" }
},
"countryCode": "GLOBAL",
"userAgentMode": "random"
}'
const response = await fetch("https://api.adscrawl.net/spa-extract", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": "YOUR_API_KEY",
},
body: JSON.stringify({
url: "https://example.com/dashboard",
mode: "extract",
waitUntil: "domcontentloaded",
waitFor: { selector: "h1", timeoutMs: 15000 },
fields: {
title: { source: "dom", selector: "h1", parse: "string" },
subtitle: { source: "dom", selector: "p.subtitle", parse: "string" },
count: { source: "dom", selector: ".metric-value", parse: "number" },
},
countryCode: "GLOBAL",
userAgentMode: "random",
}),
});
const result = await response.json();
console.log(result.data);
import httpx
response = httpx.post(
"https://api.adscrawl.net/spa-extract",
headers={
"content-type": "application/json",
"x-api-key": "YOUR_API_KEY",
},
json={
"url": "https://example.com/dashboard",
"mode": "extract",
"waitUntil": "domcontentloaded",
"waitFor": {"selector": "h1", "timeoutMs": 15000},
"fields": {
"title": {"source": "dom", "selector": "h1", "parse": "string"},
"subtitle": {"source": "dom", "selector": "p.subtitle", "parse": "string"},
"count": {"source": "dom", "selector": ".metric-value", "parse": "number"},
},
"countryCode": "GLOBAL",
"userAgentMode": "random",
},
)
response.raise_for_status()
print(response.json()["data"])
{
"mode": "extract",
"page": {
"url": "https://example.com/dashboard",
"title": "Example Dashboard"
},
"data": {
"title": "Example Dashboard"
},
"missingFields": []
}
{
"mode": "inspect",
"page": {
"url": "https://example.com/dashboard",
"title": "Example Dashboard"
},
"candidates": {
"dom": { "metrics": [], "tables": [] },
"network": []
},
"suggestedPlan": {
"fields": {},
"schema": {
"type": "object",
"properties": {},
"additionalProperties": false
}
}
}
{
"mode": "extract",
"page": {
"url": "https://trends.google.com/trends/explore?q=adspower%2Cplaywright",
"title": "Google Trends"
},
"data": {
"averages": [
{ "query": "adspower", "extractedValue": 42 },
{ "query": "playwright", "extractedValue": 71 }
],
"interestOverTime": []
},
"missingFields": [],
"source": "sunbrowser",
"cached": false,
"stale": false,
"collectedAt": "2026-08-03T02:04:05.123456789Z",
"attempts": 2
}
{
"code": "INSUFFICIENT_CREDITS"
}
{
"code": "SPA_REQUIRED_FIELDS_MISSING"
}