> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zenrows.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> The Zenrows API (Fetch, Extract via extract=auto, and Batch) is described in OpenAPI 3.1 at https://www.zenrows.com/openapi.json and listed in the RFC 9727 API catalog at https://www.zenrows.com/.well-known/api-catalog. Use the spec for exact parameter names and types.

# Track usage and control spend

> See what every request costs, check your plan's usage from code, set spending caps per API key, and get each page at the lowest cost.

Zenrows reports what every request costs, on the response itself, and lets you set limits per API key and per CLI run. This page shows how to read cost as you go, check your plan's balance from code, and keep large jobs on the configuration that gets each page for the fewest credits.

**Uses:** [Fetch](/fetch/api-reference) response headers, the [plan usage endpoint](/fetch/features/other#plan-usage), [API key credit caps](/first-steps/api-key-credit-caps), [Adaptive Stealth Mode](/fetch/features/adaptive-stealth-mode) (`mode=auto`), [`zenrows batch estimate`](/cli/batch/introduction) and CLI policy

## Ask your AI agent

With the [Zenrows MCP server](/mcp/overview) connected, paste this prompt. Checking usage is free.

```text theme={"dark"}
Check my Zenrows credits. Tell me how many are left, when the billing period ends,
and whether this API key has any credit caps.
```

## Read the cost of each request

Every Fetch response carries its cost. `X-Request-Credits` is the number of credits the request used, and `X-Request-Cost` is the same amount in US dollars.

<CodeGroup>
  ```python Python (Requests) theme={"dark"}
  import requests

  params = {
      "apikey": "YOUR_ZENROWS_API_KEY",
      "url": "https://www.scrapingcourse.com/ecommerce/",
      "mode": "auto",
  }

  response = requests.get("https://api.zenrows.com/v1/", params=params, timeout=180)
  response.raise_for_status()

  print("Credits:", response.headers["X-Request-Credits"])
  print("Cost (USD):", response.headers["X-Request-Cost"])
  print("Request ID:", response.headers["X-Request-Id"])
  ```

  ```javascript Node.js theme={"dark"}
  const params = new URLSearchParams({
    apikey: "YOUR_ZENROWS_API_KEY",
    url: "https://www.scrapingcourse.com/ecommerce/",
    mode: "auto",
  });

  const response = await fetch(`https://api.zenrows.com/v1/?${params}`, {
    signal: AbortSignal.timeout(180_000),
  });
  if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);

  console.log("Credits:", response.headers.get("X-Request-Credits"));
  console.log("Cost (USD):", response.headers.get("X-Request-Cost"));
  console.log("Request ID:", response.headers.get("X-Request-Id"));
  ```

  ```bash cURL theme={"dark"}
  curl -s -o /dev/null -D - "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&mode=auto" | grep -i "x-request"
  ```

  ```bash CLI theme={"dark"}
  zenrows fetch https://www.scrapingcourse.com/ecommerce/ --json | jq '{costCredits, costUsd}'
  ```
</CodeGroup>

## Example output

```text theme={"dark"}
Credits: 1
Cost (USD): 0.001
Request ID: 6ad00d404582d23747335acdf4c3b65b
```

Log `X-Request-Credits` with each URL. Summed per domain, it shows which targets drive your spend.

## Check your plan's balance from code

`GET /v1/subscriptions/self/details` returns your plan's usage. It is free and doesn't count against your concurrency, so call it before a large run or on a schedule:

```python Python (Requests) theme={"dark"}
import requests

response = requests.get(
    "https://api.zenrows.com/v1/subscriptions/self/details",
    headers={"X-API-Key": "YOUR_ZENROWS_API_KEY"},
    timeout=30,
)
response.raise_for_status()
details = response.json()

print(f"{details['usage_credits']} of {details['credit_limit']} credits used ({details['usage_percent']}%)")
print("Period ends:", details["period_ends_at"])
print("Key caps:", details.get("api_key", {}).get("caps", []))

# Usage per product, under plan.products
for key, product in details.get("plan", {}).get("products", {}).items():
    print(f"  {key}: {product.get('usage_credits', 0)} credits")
```

```text theme={"dark"}
1649 of 5000 credits used (32%)
Period ends: 2026-11-14T23:01:31Z
Key caps: []
  api: 2 credits
  data_apis: 0 credits
  extract: 0 credits
  proxy_residential: 0 credits
  scraping_browser: 1647 credits
```

`plan.products` breaks the usage down by product key (`api` is Fetch, `scraping_browser` is Browser), and `api_key.caps` lists this key's caps with their remaining credits and reset times. From the terminal, `zenrows usage` prints the same summary.

## Choose the lightest configuration that gets the page

Each Fetch request costs credits by configuration:

| Configuration | Credits per request |
| - | - |
| Basic request | 1 |
| `js_render=true` | 5 |
| `premium_proxy=true` | 10 |
| `js_render=true` and `premium_proxy=true` | 25 |

`mode=auto` starts light, adds rendering and premium proxies only when a page needs them, and bills only the configuration that succeeds. For example, it billed 1 credit for the scrapingcourse.com catalog, 5 for an Amazon product page and 25 for a Google results page, each without any tuning.

When you run the same domain at volume, read `X-Request-Credits` from a handful of `mode=auto` requests, and that's the cost to plan for. Requests that don't succeed aren't charged, so retries cost only the attempt that succeeds.

<Tip>
  `block_resources` controls which resource types the rendering browser loads. Zenrows already blocks images and stylesheets by default, so pages load fast without any setting. See [Block resources](/fetch/features/block-resources) before changing it.
</Tip>

## Cap what each API key can spend

Give each project, environment or customer its own API key, and set credit caps per key on the [API keys page](https://app.zenrows.com/settings/api-keys): per billing period, daily, weekly or monthly. A key that reaches a cap returns `402` with [AUTH014](/api-error-codes#AUTH014) while your other keys keep working. See [API key credit caps](/first-steps/api-key-credit-caps).

Responses from a capped key include `X-Key-Credits-Remaining`, the lowest remaining balance across its caps. Read it to slow down or switch keys before a cap is reached.

## Estimate and cap jobs from the CLI

Before you submit a [Batch](/batch/introduction) job, estimate it locally. The estimate is a ceiling: tasks in Adaptive Stealth Mode count at 25 credits each, and each task bills only what it actually uses.

```bash CLI theme={"dark"}
zenrows batch estimate jobs.jsonl
```

```text theme={"dark"}
Job spec: jobs.jsonl
valid jobs: 3/3
estimated credits, upper bound (1x basic / 5x js / 10x proxy / 25x both or auto): 75
✓ Spec is valid.
```

Set a cap per run in the workspace policy. The CLI checks every `batch create` against it before any cloud call:

```bash CLI theme={"dark"}
zenrows policy set max_credits_per_run 50
zenrows batch create jobs.jsonl
```

```text theme={"dark"}
✗ [POLICY_LIMIT_EXCEEDED] This batch is estimated at 75 credit(s), over the policy cap of 50.
  cause: policy.max_credits_per_run bounds the estimated credit cost of a single run.
```

`max_pages_per_run` bounds how many URLs one batch submits and how many pages one crawl fetches. See all keys with `zenrows policy show`.

After a job runs, its real spend is in the job's stats: `zenrows batch status <job-id> --json` returns `stats.spend.credits`. The three-task job estimated above billed 3 credits.

## Customize it

| Change | How |
| - | - |
| Bound a crawl's cost | Set `max_pages`, see [Crawl endpoints](/crawl/endpoints#pricing) |
| Bound a Browser session's cost | Close sessions as soon as the task ends, see [Browser](/browser-sessions/introduction) |
| Alerts before credits run out | Manage email alerts in [notifications](/first-steps/manage-notifications) |
| Plans and credit prices | See [Pricing](/first-steps/pricing) |

## Troubleshooting

* **`AUTH004` (402)**: the plan's credits for this period are used. Check `period_ends_at`, then top up or upgrade to continue now. See [AUTH004](/api-error-codes#AUTH004).
* **`AUTH014` (402)**: this key reached one of its caps. Raise the cap or wait for its window to reset. See [AUTH014](/api-error-codes#AUTH014).
* **`POLICY_LIMIT_EXCEEDED` in the CLI**: the job's estimate is above your `max_credits_per_run`. Split the job, raise the cap, or use `--manual` with only the options the site needs.
* **A domain costs more than you planned**: it needs rendering and premium proxies on its pages. Keep `mode=auto` so each page uses only what it needs, and send only the URLs you need, for example by filtering a crawl with `include_patterns`.

## Related recipes

<CardGroup cols={2}>
  <Card title="Resolve common response codes" icon="tool" href="/academy/production/fix-common-errors">
    Symptom-to-fix for 422, 429, 402 and more.
  </Card>

  <Card title="Automate scraping from your terminal with the CLI" icon="terminal" href="/academy/surfaces/cli-workflows">
    Batch, crawl and trace runs from the CLI.
  </Card>

  <Card title="Scrape a list of URLs" icon="list" href="/academy/scrape-from-a-list-of-urls">
    Run thousands of URLs as one Batch job.
  </Card>

  <Card title="Scrape pages protected by anti-bot systems" icon="shield-check" href="/academy/fetch/protected-sites">
    Let Adaptive Stealth Mode pick the right configuration per page.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.