Instant Snap API

Rate limits and quota

A capture holds a browser open for the whole request. Three ceilings apply to how fast you can ask for captures, and none of them is the same thing as your plan allowance.

The limits

ValueMeaning
Your plan's API rate limitThe requests a minute your plan accepts: 40 on Starter, 80 on Pro, 150 on Business, 200 on Business Plus and 10 on the free trial. It limits how fast requests are accepted, not how quickly captures finish. The allowance belongs to the workspace, not to a key, and it is shared with your Auto Schedules — unless you reserve part of it for each on the Capacity page. A request past it answers 429 rate_limited with the seconds until the next minute.
60 requests per minute, per IP addressCounted before your key is even looked at. Several keys behind one address share this ceiling.
300 reads of a capture per minute, per IP addressGET /captures/{id} has a window of its own, five times the one above, so polling an async capture never spends what your captures need.
2 captures at a time per workspaceA request that arrives while two of your captures are still rendering waits briefly, then answers 503 capture_busy.
100 async captures waiting or running per workspaceAn async capture is not refused when your captures are busy: it waits its turn, for up to 15 minutes. Past 100 in the queue a new one answers 429 queue_full.

No per-key or daily limits

There is no separate limit per key and no daily ceiling. What a day can hold is your plan’s allowance for the period, below.

Limits are not quota

Two different things can refuse a capture, and they need different responses from your code:

ValueMeaning
429 rate_limitedYou are going too fast. Wait and the same request succeeds. Nothing has been spent.
402 quota_exhaustedYour plan allowance for the period is gone. Waiting a minute changes nothing — the answer is a larger plan or the next billing period.
403 feature_not_availableYour plan does not include a field you sent, such as proxy or cookies. No amount of usage or waiting turns this into a yes.

Do not retry a 402 or a 403

A retry loop that treats every refusal alike will hammer the API for the rest of the billing period and never succeed. Retry 429 and 503; surface 402 and 403 to a human.

Concurrency and capture_busy

Separately from the rate limits, a workspace has at most two captures rendering at once. A request that arrives while both are in progress waits briefly, and if neither finishes in time it answers 503 capture_busy.

  • capture_busy is not your fault and does not count against your quota.
  • It is always worth retrying, and it usually succeeds on the next attempt.
  • If you see it often, lower your own concurrency rather than raising your retry count — submitting more work to a full queue does not make it emptier.

Backing off correctly

A refusal tells you how long to wait, in both the Retry-After header and the retry_after_seconds field. Use it rather than a fixed sleep:

429 Too Many Requests
HTTP/1.1 429 Too Many Requests
Retry-After: 31

{
  "success": false,
  "error_code": "rate_limited",
  "error_message": "Too many requests; please wait before retrying.",
  "retry_after_seconds": 31
}
A retry that respects the answer
async function capture(body, attempt = 0) {
  const response = await fetch(url, { method: "POST", headers, body });

  if (response.status === 429 || response.status === 503) {
    const payload = await response.json();
    const wait = (payload.retry_after_seconds ?? 2 ** attempt) * 1000;

    if (attempt >= 4) throw new Error(payload.error_code);

    await new Promise((resolve) => setTimeout(resolve, wait));
    return capture(body, attempt + 1);
  }

  return response;
}
  • Honour the value you were given before falling back to exponential backoff.
  • Cap the number of attempts. An unbounded retry is how one late capture becomes an outage.
  • Add a little jitter if many workers share a key, or they will all wake up at the same instant and be refused together.

There are no X-RateLimit headers

The API does not publish X-RateLimit-Limit, X-RateLimit-Remaining or X-RateLimit-Reset on successful responses. You learn your remaining headroom by being refused, not by reading it off every answer — so count your own calls if you need to pace yourself, and treat a 429 as the signal it is rather than as an error.

Staying under them

  • Queue work rather than firing it, and send at most two captures at a time. Pace the queue to your plan's rate limit rather than to how fast answers come back.
  • Reserve capacity for the API on the Capacity page if your schedules and your code run at the same time, so one cannot hold up the other.
  • Cache. A capture of a page that has not changed is a capture you did not need — the id is stable for 24 hours and reading it back does not consume a capture.
  • For recurring captures, an Auto Schedule does the same work without spending Instant Snap API calls at all.

Did this page answer your question?

Tell us what is missing