Skip to Content

credits & pricing

the crawlbrulee api uses credit-based billing. every page we deliver is classified by the engine that delivered the result: http, browser, screenshot, or cache. the engine sets the base cost, the delivered proxy tier applies a multiplier, and generating requested screenshot slices adds one flat credit, and so does a zero data retention request. failures and fully cached results cost 0 — see what counts as a failure for the exact list.

credit rules

credit rules version 2.2.1 · effective October 9, 2026

version 2.2.1 supersedes version 2.2.0, effective October 5, 2026.

the sections in this group are the credit rules referenced by section 4 of the terms and conditions . they govern how requests consume credits. the plan and included credits presented for your purchase, together with the price and billing interval in the checkout or transaction confirmation from our merchant of record, govern your subscription.

credit cost for your requests

the formula is:

credits = ( engine base × proxy multiplier ) + screenshot slicing + zero data retention

each part comes back on every response, in response_meta.usage (see checking your usage).

delivered enginebase creditswhen it applies
http1plain http fetches and /api/map
browser3a browser delivered the result without a screenshot
screenshot5a requested viewport or full-page screenshot was delivered
cache0the base result was served from cache
delivered proxymultiplier
basic×1
advanced×5

auto is a request preference, not a billed tier. the response reports and bills the proxy that actually delivered the result. generating a screenshot-slice variant through actions_after adds a flat 1 credit after the proxy multiplier, regardless of how many image tiles it contains. failures cost 0 (see what counts as a failure).

extraction options (markdown, raw_html, links, images, elements), location emulation, and JavaScript rendering do not add a separate fee. elements adds nothing on a cache hit either. JavaScript rendering can change the delivered engine from http to browser, and a delivered screenshot uses the screenshot base instead of the browser base.

in rare cases, we return the requested page result without an optional screenshot. you’re charged for the engine that actually delivered it — normally browser, not screenshot. slice credits apply only when a requested slice variant is generated.

examples

delivered resultcost
http, basic proxy1 credit
browser, basic proxy3 credits
screenshot, advanced proxy25 credits
screenshot that generates a slice variant, basic proxy6 credits
screenshot with a slice variant and zero_data_retention, basic7 credits
cache hit with no newly produced slices0 credits
a 404 page, http, basic proxy1 credit
a 503 page from the site (any engine or proxy)0 credits
an error from us (for example antibot_blocked)0 credits

zero data retention

a request sent with zero_data_retention: true adds a flat 1 credit after the proxy multiplier when its result is billed and fresh. a cache hit adds 0, and so does a page we don’t bill. in an organization where we turned it on for every request, the same rule applies to every request, whether or not it sends the field. the option is off until we enable it for your organization; ask us at sales@crawlbrulee.com.

what counts as a failure

a failure costs 0 credits. there are two kinds.

1. an error from us. we answer with a non-2xx status and no page, so nothing is billed. this covers every error on the errors page, including:

  • the site’s anti-bot protection blocked us (403 antibot_blocked)
  • we could not reach the site at all (502 target_unreachable)
  • the site redirected in a loop (422 too_many_redirects)
  • the site rate-limited us (429 too_many_requests with limited_by: "target_site")
  • the page was too large or too complex, or its content type isn’t supported (422 page_too_large, 415 unsupported_content, 422 unsupported_screenshot_output)
  • something went wrong on our side (500, 503)
  • the request itself was rejected (400, 401, 429 for your own limits)

2. a page the site served with a status we don’t bill. when the site sends back a page, you get a 200 with that page and its status in page_status_code. we bill it by that status:

page_status_codebilled?why
2xxyesthe page you asked for
404, 410yesthe site’s real answer: the page is not there
401, 402yesthe site’s real answer: log-in or payment needed
any other 4xx (for example 400, 405)yesthe site’s real answer to that url
403nooften a block, even when it isn’t seen as one
451noa legal block that can depend on the country you scrape from
407, 408, 429nothe page didn’t really get through
5xxnothe site failed; asking again later may give a real page

in short: we bill 2xx and 4xx pages, except 403, 407, 408, 429 and 451. we never bill 5xx pages. a page we don’t bill still comes back with its content, and every *_credit_cost field in its response_meta.usage is 0 (engine, proxy and proxy_multiplier still show what ran).

the rest of the billing rules apply as usual: a billed page costs what the engine and proxy that delivered it cost, whatever its status.

screenshot slices

slicing a full-page screenshot (via actions_after) adds a flat 1 credit when the requested slice variant is generated, regardless of how many image tiles it contains. the primary screenshot is covered by the screenshot engine base. slices are computed at response time, so they can also be produced from a cached base result:

scenariocredits
fresh screenshot, no slicingscreenshot base × proxy
fresh screenshot that generates a slice variantscreenshot base × proxy + 1
cache hit that generates a new slice variant1
cache hit where the requested slice variant is cached0
cache hit, no slicing requested0

the billed slice variant is keyed on the slice request. asking for a slice height you have not used before charges for the new slices the first time; later cache hits are free when those slices are already cached.

concurrency limits

your org has a maximum number of simultaneous active scrapes. the pool is shared between sync and async requests.

when you exceed it, you’ll get a 429:

{ "name": "usage_allocation_error", "message": "Concurrency limit exceeded", "details": { "error_name": "usage_allocation_error", "reason": "concurrency_limit", "details": { "current_concurrent": 5, "max_concurrent": 5 } } }

async jobs handle this gracefully — a submitted job waits in pending until a concurrency slot opens, then executes automatically.

checking your usage

per-request: response_meta.usage

this is the customer-facing indicator of what a single request cost — don’t try to derive it yourself from the proxy tier and add-ons. the service usage ledger determines your balance, subject to correction of manifest errors. 200 responses from /api/scrape and /api/map, async status and result responses once the job is done, and successful scrape.complete webhooks carry a response_meta.usage object. it shows the total and each part of the price:

{ "response_meta": { "usage": { "total_credit_cost": 1, "engine_credit_cost": 1, "proxy_multiplier": 1, "screenshot_slicing_credit_cost": 0, "zero_data_retention_credit_cost": 0, "engine": "http", "proxy": "basic" } } }
fieldtypedescription
total_credit_costintegercredits charged for this request. always engine_credit_cost × proxy_multiplier + screenshot_slicing_credit_cost + zero_data_retention_credit_cost
engine_credit_costintegerthe engine base charged: 1 for http, 3 for browser, 5 for screenshot, 0 for cache. 0 when the page isn’t billed
proxy_multiplierinteger1 for basic, 5 for advanced. always shown, even when the engine cost is 0
screenshot_slicing_credit_costinteger1 when screenshot slices were made on this request, otherwise 0. 0 when the page isn’t billed
zero_data_retention_credit_costinteger1 when the request used zero data retention and the result was billed and fresh, otherwise 0
enginestringdelivered billing engine — http, browser, screenshot, or cache
proxystringproxy tier that delivered the result — basic or advanced, never auto
creditsintegerdeprecated — use total_credit_cost, which always has the same value
screenshot_slicesintegerdeprecated — use screenshot_slicing_credit_cost, which always has the same value

credits and screenshot_slices are deprecated and will be removed in a future version. they still come back on every response for now, with the same values as total_credit_cost and screenshot_slicing_credit_cost. switch your code to the new names. if you also read older responses that don’t have the new fields yet, fall back to the old ones.

a few examples of the breakdown:

delivered resultengine_credit_costproxy_multiplierscreenshot_slicing_credit_costtotal_credit_cost
http, basic1101
browser, advanced (also for a 404 page)35015
screenshot with new slices, advanced55126
cache hit that makes new slices01 or 511
a 503 page from the site, browser, advanced0500

/api/map has no screenshots, so its usage leaves out screenshot_slicing_credit_cost and screenshot_slices. its engine is http for fresh discovery or cache for a cached result.

aggregate: GET /api/usage

GET /api/usage returns a snapshot of the current billing cycle — credits, quota, and your concurrency limit. useful for pre-flight balance checks, dashboards, and alerting.

curl https://api.crawlbrulee.com/api/usage \ -H "Authorization: Bearer $CRAWLBRULEE_API_KEY"

Response:

{ "total_credits": 20000, "used_credits": 3425, "available_credits": 16575, "used_quota_percent": 17.1, "max_concurrency": 5, "usage_reset": "2026-07-17T00:00:00.000Z" }
fieldtypedescription
total_creditsintegercredits available this billing cycle (plan base + purchased + gifted)
used_creditsintegercredits spent so far this cycle
available_creditsintegermax(0, total_credits - used_credits); reads 0 once the allowance is spent
used_quota_percentnumberpercent of total_credits used, to 1 decimal
max_concurrencyintegermaximum simultaneous active scrapes for your org
usage_resetstringiso 8601 utc time when the cycle ends and used_credits resets

the crawlbrulee sdk exposes this as client.usage().

credit exhaustion

when you run out of credits:

  • requests fail with a credit_limit error (http 429), and keep failing until the cycle resets.
  • to keep going before the reset, upgrade your plan or buy a credit pack.
{ "name": "usage_allocation_error", "message": "Credit limit exceeded", "details": { "error_name": "usage_allocation_error", "reason": "credit_limit", "details": { "current_usage": 750, "current_reserved": 0, "max_credits": 750 } } }

optimizing credit usage

a few ways to keep costs down:

  • use caching — the default 2-day freshness window makes fully cached repeat requests free. a newly produced screenshot-slice variant costs +1. don’t set max_age: 0 unless you need fresh data.
  • use the lightest engine that fits — http is 1 credit, browser is 3, and screenshot is 5 before the proxy multiplier. request JavaScript or screenshots only when the output needs them.
  • start with basic — advanced multiplies the engine base by 5. use it when the higher success rate is worth the cost, or use auto for general-purpose scrapers.
  • normalize your urls — every non-tracking query param is part of the cache key, so dropping the ones that don’t change the page widens your cache hits.
  • avoid actions_before when possible — it makes requests ineligible for cache hits, so every call costs full price. cleanup is different: ads_and_popups and exclude_selectors are part of the cache key, so keep them the same from call to call and repeat requests still hit the cache.
  • batch with async — async jobs wait for concurrency slots automatically instead of failing.

the fastest way to cut costs: check if you’re re-scraping urls within 2 days. if so, the cache is already saving you credits automatically.