Credits
What each Spicrawl request costs by engine, 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 engine that ran. ai_extract Coming soon adds 4. Failures, cache hits and non-billable target statuses cost 0. 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|x-engine|cache-state):'X-Credits-Charged: 3
X-Request-Cost: 3
X-Credits-Remaining: 976
X-Engine: obscura
Cache-State: missPrice table
Credits per successful request.
| Engine | How you select it | Credits |
|---|---|---|
fetch | Default (no JavaScript) | 1 |
obscura | js_render=true | 3 |
chromium | engine=chromium | 8 |
Remote browser session (GET /v1/browser) | CDP connect | 8 per started minute |
- Your own proxy (
proxy) adds no proxy surcharge. Spicrawl's managed residential exits Coming soon are not available yet. ai_extractComing soon adds 4 credits on top of the engine price. It is the only additive item.mode=autotriesfetch, thenobscura, and bills only the rung that succeeded. If every rung fails, it bills 0.- A bot challenge through your own
proxy(or apremium_proxyComing soon exit) can move the request to the Camoufox stealth browser Coming soon, billed the same way: 25 credits if Camoufox returned the page, the first engine's price if that engine returned it, 0 if every rung was challenged. See Anti-bot.
Remote browser sessions
A GET /v1/browser CDP session is priced the same as one real-Chromium 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 engine:
| 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 |
Cache hit (Cache-State: hit) | 0 |
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 unless it is served from the cache.
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": "…", "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 Camoufox on a bot challenge Coming soon never fails this check. With max_cost below 25 the request runs without it, at the price of its first engine.
Read the bill in headers
| Header | Meaning |
|---|---|
X-Credits-Charged | Credits actually billed for this request. 0 on any failure, cache hit or non-billable target status. |
X-Request-Cost | Price of the engine that ran. 0 on a cache hit. |
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 | Engine that ran: fetch, obscura or chromium. Under mode=auto, the rung 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 an obscura 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 Camoufox on a bot challenge Coming soon, that is 25; if the allowance covers the first engine but not 25, 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. 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". 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 items apply only js_render, proxy and block_resources today and return the raw page, so ai_extract is never added to a batch item's price. See Batch.