# Cost control (/docs/cost)



OpenBrowse charges nothing itself. A run's cost is the LLM tokens it consumes at your provider's list prices, plus the per-solve fee of any CAPTCHA sent to CapSolver. The published [benchmark](/benchmarks) puts a full 14-record extraction between $0.22 and $1.62 depending on model and reasoning effort.

## How cost is computed [#how-cost-is-computed]

After every step, the run's cost is recomputed from the **real token usage the provider reported**, priced per model: uncached input, cache reads, cache writes and output are each priced at their own rate, so the figure tracks what your provider bills rather than an estimate. Screenshots, tool schemas, fetched page content and sandbox output are all inside the API-returned token totals, so nothing needs adding on top.

Prompt caching is always on and provider-managed: the system prompt and the latest state message are cache-marked for Anthropic, and OpenAI caches automatically server-side. This is a large part of why like-for-like token counts come out well under the hosted service's; the benchmark's matched pairing (same model, same reasoning) used 3.55x fewer tokens.

Two pricing details the engine gets right that a naive estimate would not:

* OpenAI's `gpt-5.6` models have a higher tariff for requests whose prompt exceeds 272,000 tokens; the engine applies the long-context rate exactly when the provider does.
* CapSolver solves are priced from the cost field CapSolver itself returns per task, not a flat guess, and are folded into `totalCostUsd`. `CAPTCHA_MAX_COST_USD` (default `$0.03`) caps what a single **run** may spend on solving in total, not what one solve may cost; see [solving CAPTCHAs](/docs/captchas).

Costs surface in three places: the session record's `llmCostUsd`, `totalCostUsd` and token counts (updated after every step, not just at the end), the per-step costs in the dashboard, and the run exports. Displayed dashboard figures round up to the whole cent, the amount actually charged.

## The hard cap: maxCostUsd [#the-hard-cap-maxcostusd]

```ts
const session = await client.sessions.create({
  task: "Capture every open vacancy and return the full schema for each.",
  model: "gpt-5.6-terra",
  reasoningEffort: "none",
  maxCostUsd: 3.0,
  outputSchema: mySchema,
});
```

`maxCostUsd` must be a finite number above zero. The budget is checked at the end of every step: with room to spare the run simply carries on, and as spend nears the cap the run compares what remains against its own average step cost so far, running another step if it fits and stopping if it does not. Going over is therefore possible in theory, when one step costs well above the run's average, but unlikely in practice; most budgeted runs stop just short of their cap. A budget stop carries `failureKind` `budget_exceeded`, and a run that already holds data still submits what it has, as the next section describes. The status is `stopped`, or `idle` on a `keepAlive` session, which stays addressable for follow-ups rather than ending. A caller polling a budgeted keep-alive session for `stopped` will wait for ever.

### A capped run keeps what it produced [#a-capped-run-keeps-what-it-produced]

A budget stop resolves its output the same way an ordinary finish does, rather than discarding the work and charging you for nothing. The answer store's contents stand when the store holds them, `result.json` otherwise, and `isTaskSuccessful` is true when that output matches the requested schema. Either way the output is written, so null or partial values remain visible and the caller can decide whether the delivered result is sufficient before escalating.

The salvage never calls the LLM. The budget that ended the run is the same budget schema repair would spend.

One consequence worth knowing: a capped run whose store is schema-valid can carry `isTaskSuccessful: true` **and** `failureKind: "budget_exceeded"`. The first says a result was delivered; the second says the run stopped at its spending limit, so read them together.

### On a keep-alive session, the cap is per dispatch [#on-a-keep-alive-session-the-cap-is-per-dispatch]

Holding one agent across turns makes `maxCostUsd` a session-lifetime total, which would let a long conversation slowly strangle itself. Each dispatch therefore tops the pot back up by the allowance the session was created with. A session created with `maxCostUsd: 3` that has spent $2.40 runs its next task with a $5.40 ceiling, rounded up to the whole cent.

Naming `maxCostUsd` on the follow-up itself overrides that for one dispatch, as an absolute ceiling rather than an increment. A session created without a budget stays unbudgeted. The bound is per task, not per conversation.

## Scaling caps written for hosted pricing [#scaling-caps-written-for-hosted-pricing]

If your callers were written against Browser Use Cloud, their `maxCostUsd` values are priced for a service that charges platform fees on top of tokens. `CLOUD_MAX_COST_FACTOR` scales every incoming cap without touching the clients: set it above 0 and at most 1, and an incoming `$6` cap with a factor of `0.5` becomes a local `$3` budget. The scaled value is rounded up to the whole cent so a small cap can never collapse to zero, which would read as no budget at all. The session record echoes the local, scaled budget in `maxCostUsd`.

The variable is validated at startup; an out-of-range or non-numeric value stops the server with a clear error rather than being silently ignored.

## What actually moves the bill [#what-actually-moves-the-bill]

In benchmark order of leverage:

1. **Reasoning effort, on OpenAI models.** `gpt-5.6-terra` at `none` cost $0.24; the same model at `high` cost $0.66 for the same 14 records. Set `reasoningEffort` explicitly; see [choosing a model](/docs/models).
2. **Model choice.** The spread between the cheapest and dearest full extraction was 7.4x, with no difference in records recovered.
3. **Prompt scope.** A tight prompt finishes in fewer steps, and steps are where tokens go. The 36-step budget run and the 11-step focused run recovered identical data.
4. **Schema design.** Nullable fields and enums let the store settle absent data quickly instead of sending the agent hunting for values the site never publishes.
5. **Fields you already know.** Anything recoverable from one plain HTTP GET — the title, the meta description, `og:` tags, the page's own links — costs nothing to fetch yourself and a browser step each to have an agent read back. Hand them over as schema `default`s and the agent never spends a token on them. On one org-enrichment task this was the difference between 30 steps and 8.
6. **Fields that only apply sometimes.** A field that is null by design on the branch the run took is still chased by the completeness gate unless the schema says otherwise. Both keywords are described under [structured output](/docs/structured-output#telling-the-schema-what-you-already-know).

Token-heavy behaviour inside a run is already managed for you: repeated large tool outputs are deduplicated into back-references, oversized dumps are capped to previews with the data saved to files, and steps that only do store or file work skip the screenshot and DOM re-serialisation entirely.

## Concurrency is a cost control too [#concurrency-is-a-cost-control-too]

`MAX_CONCURRENT_SESSIONS` (default 1) bounds how many runs can spend at once. At the cap a session is still accepted, and its run queues for a slot rather than failing, so a burst of submissions cannot multiply your worst-case spend; it serialises it.
