# Introducing Balanced Mode for Structured Extraction

> Balanced is our new default extraction mode: higher accuracy, with reasoning and independent verification baked into every response. It knows when a value isn't in the document instead of making one up.

- Canonical: https://www.datalab.to/blog/introducing-balanced-extraction-mode
- Published: 2026-06-04
- Authors: Vikram Oberoi

Today we're releasing **`balanced`** mode for structured extraction ([documentation](https://documentation.datalab.to/docs/recipes/structured-extraction/balanced-mode)). **`balanced`** is a higher-accuracy mode with reasoning and independent verification baked into every response.

Our original implementation is now **`fast`** mode and it retains the same results and pricing it's always had. It is tailor-made for latency- and cost-sensitive workloads.

We launched Structured Extraction last year and have previously written about it [here](/blog/structured-extraction-citations). We've also shown that structured extraction accuracy significantly [improves when it's grounded by our OCR vs. using frontier models outright](/blog/high-fidelity-ocr-drives-accurate-structured-extraction).

Structured extraction modes are selectable with the `extraction_mode` parameter on our `/extract` endpoint:

- **`balanced`**: our newest implementation and the new default. Highest accuracy, with reasoning and an independent verification pass on every field. The right choice for most workloads, and any time accuracy and verifiability are critical. **$25 per 1,000 pages**, plus a compute surcharge on complex schemas — none for most documents, typically $0–$2 when it applies.
- **`fast`**: our original implementation. Lower latency and cost, no per-field verification. The right choice for high-volume or latency-sensitive workloads. **$6 per 1,000 pages** (our pricing for this mode remains unchanged).

If you have made an extraction request in the last 30 days, your default remains **`fast`** so you retain the same behavior and pricing for all your `/extract` API requests. The new **`balanced`** default applies going forward and to new accounts. You can switch any request explicitly with `extraction_mode`.

You can try both modes out in the [Datalab Playground](https://datalab.to/app/playground) today or via API:

```python
import requests

resp = requests.post(
    "https://www.datalab.to/api/v1/extract",
    headers={"X-Api-Key": "YOUR_KEY"},
    files={"file": open("bank_statement.pdf", "rb")},
    data={
        "page_schema": open("schema.json").read(),
        "extraction_mode": "balanced",  # the default; use "fast" for lower latency/cost
    },
)
```

## When should I use **`balanced`** mode over **`fast`** mode for structured extraction?

**`balanced`** mode trades off latency for accuracy. It is strictly more accurate than **`fast`** mode on our internal benchmarks (on all dimensions), but it is especially designed for:

**1. Hard schemas, complex documents, and long documents:**

**`balanced`** mode shines when extraction requires significant domain knowledge and inference across documents.

It is better at fields that require recall (e.g. finding every instance of an item for a list), fields that can be easily confused (e.g. parties in complicated contracts), and fields that require inference across many sections across an entire document.

**2. Data verification workflows:**

**`balanced`** mode responses always come with detailed reasoning strings per-field-and-list-item. We also perform an independent verification pass and tell you, for each field and list item:

- a **pass/fail verdict** from a second, independent model that re-checks the value and its citations against the document
- when it doesn't pass, **why** — the value disagrees with the document, the citations don't support it, the document supports no value at all, or (for a list) entries are missing

This allows clients to route problematic extractions to reviewers for additional verification, whether they are agents or humans in the loop.

When accuracy is paramount and you need to be able to trust what you ship downstream, we recommend reaching for **`balanced`** mode: its results are strictly better and it comes with all the tools you need to build reliable workflows.

## In what cases does **`balanced`** pull ahead of **`fast`**?

**`balanced`** mode is more accurate across the board.

In aggregate, the difference looks modest, but the gap widens when a field takes more work:

- **Reasoning or inference** of different kinds (more below)
- **Tracing or combining** information across the document
- **Recall** — finding every matching item
- **Disambiguating look-alikes**

In practice, this looks like counting line items in complex multi-page invoices, reconciling figures that are tens of pages apart, applying a clause only when its conditions are met, or picking the right party in a dense contract.

These cases align with domains where extraction mistakes are most expensive, like financial reconciliation, legal review, healthcare, and other regulated workflows.

**The gains using `balanced` mode are heavily concentrated in these hard cases.**

To measure this, we deliberately plant complications in documents: the things that make a field hard. Here's how the two modes score on each, widest gap first:

| What the field needs            | What that means                                            | Example                                                              | fast  | balanced |
| ------------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------- | ----- | -------- |
| **Exclude a subset**            | return the items, but leave out the ones matching a rule   | every signer on a contract _except_ the named parties                | 59.9% | 82.0%    |
| **Counting & totals**           | count items or add up a column                             | how many line items are on the invoice                               | 76.8% | 94.8%    |
| **Combine across the document** | the answer is built by merging facts from different places | total cost = the fees section + the expenses section                 | 76.4% | 92.1%    |
| **Implied, not stated**         | the value follows from other facts in the doc              | contract length in months, from the start and end dates              | 76.7% | 90.9%    |
| **Complete lists**              | capture every matching item, none dropped                  | every party named in the contract                                    | 72.2% | 83.4%    |
| **Conditional**                 | return a value only if a rule holds                        | a late fee, only if the invoice is overdue                           | 84.4% | 93.8%    |
| **Follow a reference**          | one value, found by linking two places in the doc          | a person named on page 1, whose address is in an appendix on page 15 | 77.8% | 86.7%    |
| **Genuinely absent**            | the doc never states it, so the answer is null             | payment terms a contract never mentions                              | 85.1% | 92.1%    |
| **Look-alikes present**         | a similar value could fool you; pick the right one         | the tenant's name, when a similar guarantor name also appears        | 90.6% | 94.4%    |
| **Printed plainly**             | the value is written in the doc; just read it              | the invoice number in the header                                     | 90.8% | 92.8%    |

`balanced` comes out ahead on every complication we test and by the widest margins exactly where extraction is hardest. The trade-off is latency: median time per document roughly doubles.

## Reasoning and verification, baked in

Both modes return citations: the document blocks each value came from. (We wrote about citations [here](/blog/structured-extraction-citations).)

`balanced` mode adds two things to every field:

- **`reasoning`**: how the model arrived at the value.
- **`verification`**: an independent pass that re-checks the value and its citations against the document, and reports `PASS` or a failure with feedback.

Here's a real field from a bank-statement schema — the total of all fees charged, which requires summing fee rows scattered across five pages:

```json
{
  "total_fees_charged": 94.08,
  "total_fees_charged_citations": [
    "/page/0/Table/9",
    "/page/2/Table/8",
    "/page/3/Table/8",
    "/page/4/Table/8",
    "/page/5/Table/8"
  ],
  "total_fees_charged_meta": {
    "extraction_status": "EXTRACTED",
    "reasoning": "Summed every bank fee row across all five ledger pages: 6x0.56 transfer fees + 6x0.03 ABB fees + 56.00 monthly terminal fee + 3x3.18 admin charges + 25.00 minimum-balance fee = 94.08.",
    "citations": ["/page/0/Table/9", "/page/2/Table/8", "..."],
    "verification": {
      "status": "PASS",
      "feedback": "Recomputed the sum from the enumerated fee rows; matches 94.08."
    }
  }
}
```

Reasoning and our verifier's verdicts are baked into each response for agent or human-in-the-loop verification workflows. Auto-accept the `PASS` fields, route anything that didn't verify cleanly to an agent or human, and provide the reasoning and the citations so the review is cheaper and takes less time.

## Knowing when a value isn't there

One-shot extractors have a bad habit: when a schema asks for a field the document doesn't contain, they invent a plausible-looking answer. For high-stakes workflows, a confident wrong value is worse than no value.

**`balanced`** mode is built to say "not here." When the document doesn't support a value, it returns `null`, marks the field `NOT_RESOLVABLE`, and explains why. The verification pass confirms the absence rather than rubber-stamping a guess.

Take this field from the same bank-statement schema:

> **`remittance_swift_bic`** — "SWIFT/BIC code of the issuing bank, for incoming international wires."

This statement has no incoming-wire section at all — there's no SWIFT/BIC anywhere in the document — so the answer is `null`:

```json
{
  "remittance_swift_bic": null,
  "remittance_swift_bic_citations": [],
  "remittance_swift_bic_meta": {
    "extraction_status": "NOT_RESOLVABLE",
    "reasoning": "The schema asks for the issuing bank's SWIFT/BIC for incoming wires, but the statement contains no international-remittance or wire-receive section, and no SWIFT/BIC code appears anywhere in the document.",
    "citations": [],
    "verification": {
      "status": "PASS",
      "feedback": "Searched the cover page, ledger, and footnotes; no SWIFT/BIC is present, so null is correct."
    }
  }
}
```

A bank statement is full of code-like tokens — the masked account number, transaction reference codes — and a one-shot extractor asked for a SWIFT/BIC will often grab one of them. `balanced` recognizes the document simply doesn't contain one, returns `null`, and the verification pass confirms the absence rather than rubber-stamping a guess.

## How Datalab compares to other services

Datalab's pricing is one flat rate per page that covers both parsing the document and extracting from it.

`fast` runs **$6 per 1,000 pages** no matter how dense or complex the pages are, and `balanced` **$25 per 1,000 pages** plus a compute surcharge that reflects the work our extraction agent actually does on your document — most documents have no surcharge, and it typically runs $0–$2 when it applies. There isn't a comparable **$6** option in the market, which is what makes `fast` distinctive for high-volume work.

For higher-accuracy extraction, we anchored our benchmarking on **Reducto** as the primary competitor — its standard extraction is the closest comparable to `balanced`.

As of today's post, Reducto bills in **credits** ($0.015 each, after a 15K-credit free tier) and charges **Parse and then Extract separately**:

- **Parse** runs **1–2 credits per page** (more with agentic parsing)
- **Extract** adds **2 credits per page** on top.

So a realistic standard-extraction bill is **~3–4 credits per page (≈ $45–60 per 1,000 pages)** versus `balanced`'s **$25 per 1,000 pages** plus the compute surcharge (typically $0–$2 per document, and zero for most). Your exact Reducto cost varies with page complexity; our per-page rate doesn't.

On accuracy, `balanced` and Reducto's standard extraction are comparable at the field level, but `balanced` gets meaningfully more documents _entirely_ right:

|                        | Field accuracy | Whole-document accuracy | Price / 1K pages         |
| ---------------------- | -------------- | ----------------------- | ------------------------ |
| Datalab **`fast`**     | 86.8%          | 24.9%                   | **$6**, all-in           |
| Datalab **`balanced`** | **92.0%**      | **31.6%**               | **$25**, all-in          |
| Reducto (standard)     | 91.7%          | 24.0%                   | ~$45–60, parse + extract |

`balanced`'s lead is widest exactly where fields take _work_: combining facts across a document (92.1% vs. 76.4%), counting and totals (94.8% vs. 81.7%), excluding a subset (82.0% vs. 69.2%), and recognizing when a value genuinely isn't there (92.1% vs. 82.8%).

Those are the cases that drive the most expensive mistakes in financial, legal, and healthcare workflows.

Reducto also offers a **deep extract** tier for the hardest documents. It is more accurate than all the options above, but at materially higher latency than `balanced` and a materially higher bill: **4 credits per page plus a per-field charge** on top of parsing ≈ $75+ per 1,000 pages, plus fields.

## What's next

We're investing across all three modes:

- **A new `accurate` mode** — an even-higher-accuracy tier for the hardest schema/document pairs, for when getting every field right matters more than latency or cost.
- **Continuing to improve `balanced`** — pushing accuracy and verification quality further on the cases that take real work.
- **Bringing `balanced`'s strengths to `fast`** — we're working to bring the reasoning and verification gains from `balanced` down to `fast`, so high-volume workloads get richer, more auditable output without stepping up a tier.

## Get started

`balanced` mode is live now and is the new default — every `/extract` call uses it unless you pass `extraction_mode=fast`. Try it in the [playground](https://www.datalab.to/playground).

- New to structured extraction? [Sign up](https://www.datalab.to/auth/sign_up) and try it on your own documents.
- Want help deciding which mode fits your workload, or want us to benchmark `balanced` against your documents? Email us at [hi@datalab.to](mailto:hi@datalab.to).
