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

# OCR Text

> Returns exact page-by-page text of a document using Google Vision, without an LLM rewrite.

# OCR Text (Google Vision)

This document covers `ocr_text`, which returns the exact page-by-page text of a document using Google Vision. No LLM reads or rewrites the pages, so the output cannot truncate mid-schema, summarize, or hallucinate documents — the failure modes that make LLM-driven splitting fragile on large multi-document bundles.

Use it when you need faithful page-addressed text for evidence lookup or citation, or when LLM-based splitting/parsing of a file fails and you still need its content.

## Authentication and enablement

No integration binding and no user credentials. The tool downloads the file through the platform's file storage and calls the deployment's Google Vision credentials (`google_vision.api_key`), which are already covered by the outbound-call audit — using this tool adds no new outbound HTTP surface.

`DefaultEnabled` is `false`: the tool must be explicitly enabled per agent. On a deployment where `google_vision.api_key` is unset, the tool still registers (so it is visible in the UI) but every call fails loudly rather than silently returning empty text.

## Inputs

| Field        | Required | Description                                                                                    |
| ------------ | -------- | ---------------------------------------------------------------------------------------------- |
| `file_url`   | yes      | URL of the PDF or image to OCR. Pass the file reference provided with the task (a `${VAR_N}`). |
| `start_page` | no       | First page to OCR, 1-indexed and inclusive. PDFs only.                                         |
| `end_page`   | no       | Last page to OCR, 1-indexed and inclusive. Requires `start_page`. PDFs only.                   |

Omit both page fields to OCR the whole file. For large documents, window the work: pass `start_page`/`end_page` and call the tool once per window, the same way batched extraction does. **Returned page numbers are always the original document's page numbers**, so citations stay addressable against the source file no matter how the document was windowed.

`end_page` without `start_page`, a negative page number, `end_page` below `start_page`, or a page window on a non-PDF file are all rejected before any OCR runs.

## Output

Structured content:

```json theme={null}
{
  "file_name": "bundle.pdf",
  "page_count": 10,
  "total_pages": 398,
  "start_page": 31,
  "end_page": 40,
  "total_chars": 5761,
  "pages": [{ "page": 31, "text": "Michael Zadravec ...", "word_count": 412 }]
}
```

`page_count` is the number of pages in **this** call; `total_pages` is the whole document. `start_page` / `end_page` are the first and last original page numbers present in `pages`. `total_chars` counts runes, not bytes.

### The result is stored as a variable

Each successful call registers its structured content as a task variable and the result carries the handle as `output_variable`. Reference it in a later tool's arguments instead of copying the text into the call:

* `"ocr_result": "${VAR_5}"` — the whole window, as JSON. **Use this form for a string-typed field**, which is what both current consumers declare.
* `"pages": "${VAR_5}.pages"` — just the page array, for a field declared as an array.

Match the form to the field's declared type. The accessor form strips the surrounding quotes and splices a raw JSON array, and binding coercion only converts string→other at the top level — never inside `input`. Handing an array to a `type: string` field means the tool receives a `list` where it expects a dict, its `isinstance(...)` check fails, and the OCR context comes through **empty with no error**.

**Always pass the reference rather than the text.** A page window is 10–30KB, and a model that retypes it into the next call corrupts the JSON often enough to matter: on one production task, 3 of 5 downstream calls failed on a surplus brace or a stray escape, each failure silently dropping a 40-page window from the result.

One variable is created per call, so a document OCR'd in ten windows produces ten variables. They are told apart by their metadata (filename and page range), which is shown next to each `${VAR_N}` — the model can pick the right window without loading any of their text.

Under `harness_v2`, an oversized result is collapsed in the model's context to its `${VAR_N}` plus a short preview. The text is still passable to any tool via the reference, and still readable on demand via `request_variables`. Agents that need the model itself to read the page text on every turn should not enable `harness_v2`.

OCR variables are the one type **not** auto-injected into a bare `python_code_tool` call's `input` dict. Other variables arrive there as `input['VAR_N']` whether the program asked for them or not; a document's page windows would be hundreds of KB of text the program mostly does not read. Pass the window you want explicitly — `"ocr_result": "${VAR_5}"` — and it arrives like any other argument.

## Limits and behaviour

* **Cost**: billed per call (flat), independent of page count. Window a large document to keep each call's payload manageable, not to save money.
* **Malformed PDFs degrade rather than fail.** If the page count cannot be read or the requested range cannot be sliced, the tool OCRs the whole file and filters down to the requested window. The output is the same; the call is slower and costs a full-document OCR.
* **Rotation**: per-page rotation detected during a whole-file OCR is persisted to the source file for the review viewer. It is deliberately skipped for windowed calls, where the OCR engine's page numbers are range-relative and would be recorded against the wrong pages.
* **Images** have no page dimension and always come back as a single page numbered 1.
* Word order within a page is Vision's reading order. Layout, tables, and column structure are **not** reconstructed — if you need fielded data, use an extraction tool.

## Errors

All of these come back as a normal tool error (`isError: true`) with a readable message, never a crash:

| Message                                                | Cause                                                 |
| ------------------------------------------------------ | ----------------------------------------------------- |
| `Google Vision is not configured on this deployment`   | `google_vision.api_key` is unset.                     |
| `download failed: …`                                   | `file_url` is unreachable or expired.                 |
| `start_page/end_page are only supported for PDF files` | A page window was requested on an image.              |
| `start_page N beyond document end (M pages)`           | The window starts past the last page.                 |
| `vision OCR failed: …`                                 | Google Vision rejected or could not process the file. |

A failed call registers **no** variable, so a downstream tool can never be handed an empty `${VAR_N}` that reads as "the document was blank". A call that succeeds but produces no pages (a fully blank window) likewise registers nothing.
