Credits
What each Spicrawl request costs by rendering tier, what is free, and how to cap spend with max_cost and batch budgets.
You pay credits only for a successful request. The price depends on the rendering tier that served the request and on the proxy class it ran on. ai_extract Coming soon adds 4, and a solved challenge or CAPTCHA adds 5. Failures and non-billable target statuses cost 0. A cache hit is billed at the same price as the fetch that stored it. The X-Credits-Charged header on every response tells you what that request billed, and X-Credits-Remaining what is left of your monthly allowance after it.
curl -sS -D - -o /dev/null "https://api.spicrawl.com/v1/scrape" \
-H "Authorization: Bearer $SPICRAWL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/products/42", "js_render": true, "max_cost": 3}' \
| grep -i -E '^(x-credits-charged|x-request-cost|x-credits-remaining|cache-state):'X-Credits-Charged: 3
X-Request-Cost: 3
X-Credits-Remaining: 976
Cache-State: missPrice table
Credits per successful request.
| Rendering tier | How you reach it | Credits: direct, datacenter or your own proxy | Credits: managed premium exit Coming soon |
|---|---|---|---|
| Plain fetch | Default (no JavaScript) | 1 | 10 |
| JavaScript rendering | js_render=true | 3 | 25 |
| Full-browser rendering | screenshot=true, response_format=pdf, a screenshot action, any actions, an explicit block_resources, solve_captcha=true, stealth=true Coming soon, or an automatic anti-bot escalation | 8 | 32 |
| Stealth rendering Coming soon | The last step of mode=auto or of an anti-bot escalation | 25 | 25 |
Remote browser session (GET /v1/browser) | CDP connect | 8 per started minute |
- Your own proxy (
proxy) adds no proxy surcharge: it is priced in the first price column. Spicrawl's managed residential exits Coming soon are not available yet. ai_extractComing soon adds 4 credits on top of the rendering price. Together with the solve surcharge below, these are the only additive items.- A solve adds 5 credits on top of the rendering price, once per request. It applies only when a challenge or CAPTCHA was solved on the tier that served the page. It is not charged when the solve failed, when the request failed, or on a cache hit. For example, a
solve_captcharequest that is solved on full-browser rendering costs 8 + 5 = 13, and the same request whose solve fails costs 8. The surcharge does not refuse a request: ifmax_costis lower than the price plus 5, the request runs without solving, at its normal price. See Cloudflare. - You do not pick the rendering tier. The
engineandheadlessrequest fields are deprecated and ignored: rendering is chosen automatically from the request (the response carriesX-Warning: ENGINE_IGNORED). The flags above choose it, and a request is billed for the tier that served it. mode=autotries a plain fetch, then JavaScript rendering, then full-browser rendering, then stealth rendering Coming soon, moving up only when the previous step was met by a challenge. It bills only the tier that served the page. If every step fails, it bills 0.- A bot challenge (Cloudflare and similar) on a request through your own
proxymoves a plain fetch orjs_renderrequest to a stronger rendering path on the same exit, billed the same way: only the tier that returned the page (full-browser rendering 8, stealth rendering Coming soon 25), 0 if every step was challenged. Automatic handling on managed premium exits is coming soon Coming soon. On the default shared pool a challenged page returnsERR::UPSTREAM::CHALLENGEat 0 credits; retry through your own residentialproxy. If a request uses your own proxy and hits a blocking challenge that Spicrawl solves, your proxy's address and credentials are shared with the third-party solving service for that solve. Without your own proxy, a blocked request may be completed through a residential exit of ours at no change in price beyond the solve surcharge. See Anti-bot. - A cache hit (
Cache-State: hit) is billed at the same price as the fetch that stored it, so a repeat costs what the first request did. The cache saves the fetch (latency and load on the target), not credits. See Caching.
Remote browser sessions
A GET /v1/browser CDP session is priced the same as one full-browser page: 8 credits per started minute (a 10-second session is 1 minute = 8 credits). At admission the session holds the price of its whole session_ttl against your monthly allowance (default session_ttl 180 s = 24 credits; the 60–900 s range = 8–120 credits); if the remaining allowance cannot cover that hold, the session is refused with 402 ERR::LIMIT::QUOTA_EXCEEDED before any browser is leased, and a shorter session_ttl may fit. At close, the session is charged for the minutes it actually held (capped at session_ttl's minutes) and the unused part of the hold is returned immediately. A session the platform ends (the browser backend dropped it, or the API shut down) costs 0. A session that never opens costs 0 and returns its hold.
Free, at any rendering tier:
| Feature | Extra credits |
|---|---|
impersonate (on by default) | 0 |
extract (selector extraction) | 0 |
autoparse | 0 |
links | 0 |
network_capture | 0 |
| Markdown, text, JSON envelope | 0 |
What costs 0
| Outcome | Charged |
|---|---|
Any error response (application/problem+json), including bot challenges and timeouts | 0 |
| A plain fetch that returns a near-empty, script-driven HTML page (under 100 visible characters) | 0, reported as ERR::UPSTREAM::CHALLENGE |
Target answered with a status other than 200, 404 or 410 and not in allowed_status_codes | 0. You still get HTTP 200 and the site's body. |
| A requested screenshot that was not delivered | Reported in warnings, charged 0 |
Refused before running: validation errors, ERR::LIMIT::MAX_COST_EXCEEDED, limits | 0 |
Target statuses 200, 404 and 410 are billable successes. Add others with allowed_status_codes, for example [403] if a 403 page is the content you want.
Retrying a failed request costs nothing extra, but POST /v1/scrape is not idempotent: repeating a request that succeeded bills it again, even when the cache serves the repeat.
Cap a request with max_cost
max_cost is a credit ceiling for one request. 0 (the default) means no ceiling. Spicrawl checks it against the dearest outcome the request could reach before anything runs. If that outcome is over the ceiling, the request fails with 400 ERR::LIMIT::MAX_COST_EXCEEDED at 0 credits.
| Request | Checked against |
|---|---|
{"url": "…"} | 1 |
{"url": "…", "js_render": true} | 3 |
{"url": "…", "screenshot": true} | 8 |
{"url": "…", "mode": "auto"} | 25 (the top rung of the ladder) |
Under mode=auto, max_cost: 3 fails every time, because the top rung costs 25. To stay under 3, send js_render=true instead of mode=auto.
The move to a stronger rendering path on a bot challenge never fails this check. A step that costs more than max_cost is left off, so the request runs without it, at the price of its first tier.
Read the bill in headers
| Header | Meaning |
|---|---|
X-Credits-Charged | Credits actually billed for this request. 0 on any failure or non-billable target status. On a cache hit, the price of the fetch that stored it. |
X-Request-Cost | Price of the rendering tier that ran. On a cache hit, the price of the tier that fetched the stored copy. |
X-Credits-Remaining | Credits left in your monthly allowance after this request, rounded down. Absent when your organization has no monthly limit. See Monthly credit ceiling. |
X-Engine | The rendering tier that served the request: fetch (plain fetch), js (JavaScript rendering) or browser (full-browser rendering). Informational, not a setting. Under mode=auto, the step that produced the result. |
X-Proxy-Source | custom (your proxy) or direct. |
X-Credits-Charged and X-Request-Cost differ exactly when nothing was billed: a site answering 403 gives X-Request-Cost: 3 and X-Credits-Charged: 0 on a JavaScript render. The JSON envelope repeats the charge as credits.
Monthly credit ceiling
Each organization has a monthly credit ceiling (the beta has one plan for everyone: 1,000 credits/month). The allowance month is the org's own anniversary month: it runs from the day the org was created and resets at 00:00 UTC on that day every month (an org created on the 29th, 30th or 31st resets on the last day of a shorter month). Before a request runs, Spicrawl reserves its dearest possible cost against the allowance. For a request that could move to a stronger rendering path on a bot challenge, that is the dearest step it could reach (25 on your own proxy); if the allowance covers the first tier but not that, the request runs without the move. When the allowance is used up, requests fail with 402 ERR::LIMIT::QUOTA_EXCEEDED (not retryable), naming the exact reset date, until the ceiling is raised or the allowance resets. A cache hit is held first, at its own price, and is refused with the same 402 when the allowance left is below it: nothing is served or charged. See Errors.
To see how many credits are left, read X-Credits-Remaining on a /v1/scrape response, or on a batch submit, append or retry response. It is the allowance left after that request's charge (for a batch call, after its hold), in whole credits rounded down, and it counts credits held for work in flight the same way allowance.used_micro below does. It is never negative; on a 402 it can be above 0, meaning less than that request needed. It is absent when your organization has no monthly limit, when the request was refused before the credit check (a validation error, a rate or concurrency limit), or when the balance could not be read at that moment.
For the full picture, or without a request to read the header from, call GET /v1/usage/summary (needs a key with the read scope; 1 credit = 1,000,000 micro-credits):
allowanceis the ceiling as it is enforced:limit_micro,used_micro,remaining_micro,limit_source(default, oroverridewhen your organization has its own limit),window_startandresets_at.allowance.remaining_microis the number to show as "credits left". It includesextra_micro, any extra credits granted to your organization on top of the monthly limit: they are spent after the monthly allowance and are kept when it resets. Itsused_microcounts credits currently held for work in flight (an open browser session holds its wholesession_ttlprice; a batch job holds its unfinished items' prices) as well as credits spent.creditsis metered usage for the period from the daily rollup:included_micro,used_micro,remaining_micro. It counts spent credits only, batch items included, but not credits held for work still running, so it can be lower thanallowance.used_micro.
An organization with no subscription is on the free plan: plan.code is free, plan.subscription_status is none, plan.period_source is allowance_month, and credits.included_micro is the monthly ceiling.
Batch budgets
A batch job is billed per item, only for items that succeed, at the same prices as /v1/scrape. Submitting a job charges nothing (X-Credits-Charged: 0), but its X-Credits-Remaining already counts the whole hold (estimated_credits) as used.
| Field | Where | Meaning |
|---|---|---|
max_cost | request, per item | Ceiling for each item, as on /v1/scrape. Checked at submission: an item whose dearest outcome is over it fails the whole submission with 400 ERR::LIMIT::MAX_COST_EXCEEDED, with Item N: in detail. |
credit_budget | request, whole job | Ceiling for the whole run in whole credits. The worker stops charging work beyond it. Omit it to use the job's projected cost. An open job has no ceiling unless you set one, because its projection covers only the items it was submitted with. |
estimated_credits | job object | Credits reserved against the monthly allowance at submission: the dearest outcome of every item. It is a hold, not a charge; credits held for items that fail, are cancelled or skipped are returned within about a minute of the item finishing. Items appended to an open job are reserved the same way when they are added; the append response's X-Request-Cost is their total, and it fails with 402 ERR::LIMIT::QUOTA_EXCEEDED if the allowance cannot cover them. |
progress.credits_charged | job object | Credits actually charged so far. |
Batch refuses ai_extract, extract and the other parameters its worker cannot run with a 400 at submission, so a batch item is never priced or charged for them. See Batch.