# Image to Text OCR: Markdown, Word Boxes & RAG Chunks (`bongo-seakhoa/image-to-text-ocr-markdown`) Actor

Extract text from PNG, JPG, TIFF and WebP images offline with Tesseract. Markdown, plain text, word boxes, confidence scores and RAG chunks. No API key.

- **URL**: https://apify.com/bongo-seakhoa/image-to-text-ocr-markdown.md
- **Developed by:** [Bongo Seakhoa](https://apify.com/bongo-seakhoa) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 image processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Image to Text OCR: Markdown, Word Boxes & RAG Chunks

Extract the text from PNG, JPEG, TIFF, WebP, BMP and GIF images with Tesseract OCR, offline inside the Actor. Each image gives you plain text, Markdown, a confidence score and RAG-ready chunks, and optionally word and line boxes with pixel coordinates. No API key and no AI service: built for scans, screenshots and clean document exports that you want to search, index or feed to a retrieval pipeline.

### What it outputs

- **Text and Markdown per image.** Plain `text` keeps the lines as Tesseract read them. `markdown` rebuilds paragraphs and joins words hyphenated at line ends; it also marks headings (from text size) and bullet and numbered lists where it can tell them apart. That structure is best-effort, because OCR gives no document structure: a heading can come out as plain text, or a large line as a heading. The full Markdown is also saved as a `.md` file.
- **Confidence you can filter on.** Every image row has `mean_confidence` (0-100) and `word_count`; an image whose mean word confidence is below 60 is marked `partial` with a `LOW_CONFIDENCE` warning.
- **Word and line boxes** (optional). JSON files with the pixel box, confidence and text of every word or line, plus Tesseract's block, paragraph and line numbers.
- **RAG chunks.** The Markdown split at headings, paragraphs and sentences, with `heading_path`, character offsets and a stable `chunk_id`, in the same chunk format as the PDF to Markdown & RAG Chunks Actor.
- **Rotation fixed.** Scanned pages turned sideways or upside down are detected and turned upright before OCR (`rotation_deg` says by how much). Phone photos are turned upright from their EXIF orientation. When detection is unsure and the text reads poorly, OCR is tried again with the image turned 90 and 270 degrees and the best reading is kept.
- **Multi-page TIFFs.** Each page is its own row and its own charge, up to `maxFramesPerFile`.
- **Honest failures.** Broken, unsupported, oversized or unreachable files get a status row with an error code and are never charged.
- **No AI service.** Everything runs inside the Actor's container: Tesseract OCR 5 with its own trained language data, and Pillow for reading the images. Nothing is sent to a language model or a third-party API.

### How to use it

1. Paste one or more **image URLs** (direct links to the files).
2. Or pick a **key-value store** that holds your files (upload them in Apify Console under Storage), optionally naming the record keys to use. Without keys, the run reads the records the store holds when the run starts; records added later are not included.
3. Leave the defaults or adjust the options, then start the run.
4. Open the **Output** tab. **Overview** lists every image with its status, confidence and charges; **Images** shows the text and Markdown; **Chunks** lists the RAG chunks. Markdown and box files are in the run's key-value store.

Starting the Actor with no input converts a small bundled synthetic sample so you can see the output format first. The sample is charged none of this Actor's events; Apify's standard Actor start fee still applies, as it does to every run.

### Input

```json
{
    "sources": [
        "https://example.com/scans/invoice-0042.png",
        { "url": "https://example.com/scans/contract.tiff" }
    ],
    "ocrLanguages": ["eng", "deu"],
    "layout": "auto",
    "outputs": ["text", "markdown", "chunks"],
    "chunkSize": 1500
}
```

| Field | Default | What it does |
|---|---|---|
| `sources` | none | Image URLs (PNG, JPEG, TIFF, WebP, BMP, GIF), as strings or `{"url": ...}` objects. At most 1,000 per run. |
| `keyValueStoreId` | none | A key-value store holding images. Without `keyValueStoreKeys`, every record whose key has an image file extension (`.png`, `.jpg`, `.tiff` ...) or no extension at all (like `scan-0001`) is read, up to 1,000; the format comes from each file's first bytes. Records named like other files (`.json`, `.txt` ...) are left out and counted under `ignored_keys` in the `SUMMARY` record. A record that turns out not to be an image gets a free `UNSUPPORTED_FORMAT` row. |
| `keyValueStoreKeys` | `[]` | Record keys to read from that store. |
| `ocrLanguages` | `["eng"]` | 1 to 3 of `eng`, `deu`, `fra`, `spa`, `ita`, `por`, `nld`, `hun`. |
| `layout` | `auto` | `auto` (pages, documents), `single_block` (one block of text) or `sparse` (screenshots, forms, signs). |
| `autoRotate` | `true` | Detect pages turned by 90, 180 or 270 degrees and turn them upright first. Skipped below about 300 px of height. |
| `mode` | `convert` | `estimate` counts the images and TIFF pages that would be read and the projected price, without OCR and without event charges. |
| `outputs` | `["text", "markdown", "chunks"]` | Any of `text`, `markdown`, `words` (word boxes file), `lines` (line boxes file), `chunks`. |
| `chunkSize` | `1500` | Maximum characters per chunk (200-8,000). |
| `chunkOverlap` | `150` | Characters repeated between consecutive chunks (0-1,000, at most half of `chunkSize`). |
| `maxPixelsMp` | `12` | Images above this many megapixels are scaled down before OCR (2-20). |
| `maxFileSizeMb` | `50` | Larger files are not downloaded (1-200; also capped at a quarter of the run's memory). |
| `maxFramesPerFile` | `50` | TIFF pages read per file (1-200); later pages are left out and not charged. |
| `perImageTimeoutSecs` | `120` | Time limit per image or TIFF page (10-600 s); a slower one fails with `TIMEOUT` and is not charged. |

### Output

The dataset holds several kinds of rows, told apart by `record_type`. Filter on it when you read the dataset through the API. The examples below are rows of the bundled sample, trimmed where marked with `...`.

An **image row** (`record_type: "image"`), one per image and one per TIFF page. This is the bundled sample's row from a run of the Actor image in CI on 2026-10-02:

```json
{
    "record_type": "image",
    "document_id": "2ba212a710c13dbf",
    "document_index": 0,
    "source": "bundled-sample:sample.png",
    "source_type": "sample",
    "status": "ok",
    "error_code": null,
    "error_message": null,
    "file_name": "sample.png",
    "file_size_bytes": 35438,
    "format": "png",
    "frame_index": 0,
    "frame_count": 1,
    "width": 1200,
    "height": 900,
    "rotation_deg": 0,
    "languages": ["eng"],
    "layout": "auto",
    "mean_confidence": 95.6,
    "word_count": 87,
    "text": "Warehouse Inspection Summary\n\nThis page is a synthetic sample made for the Image to Text OCR\nActor. It holds a heading, ...\n\nReference: SYN-2026-0042\nSite: North Storage Hall\nInspected on: 2 October 2026\nResult: Passed",
    "markdown": "# Warehouse Inspection Summary\n\nThis page is a synthetic sample made for the Image to Text OCR Actor. It holds a heading, ...\n\nReference: SYN-2026-0042\n\nSite: North Storage Hall\n\nInspected on: 2 October 2026\n\nResult: Passed",
    "markdown_url": "https://api.apify.com/v2/key-value-stores/.../records/img0001-2ba212a710c13dbf-f000.md",
    "words_url": null,
    "lines_url": null,
    "chunk_count": 1,
    "warnings": [],
    "charged_events": {},
    "elapsed_ms": 901,
    ...
}
```

`charged_events` is empty because the sample is free; for your images it shows `{"image-processed": 1}`. In a multi-page TIFF, the row of the first page that was read carries the charge for the whole file and the other pages' rows show `{}`. `words_url` and `lines_url` link JSON files when you select those outputs; each word has `text`, `conf`, the box `x`, `y`, `w`, `h` in pixels, and Tesseract's `block`, `par`, `line` and `word` numbers.

A **chunk row** (`record_type: "chunk"`) from the same run:

```json
{
    "record_type": "chunk",
    "document_id": "2ba212a710c13dbf",
    "chunk_id": "b18251fcc0c9f0d3388379f2",
    "chunk_index": 0,
    "text": "# Warehouse Inspection Summary\n\nThis page is a synthetic sample made for the Image to Text OCR Actor. ...\n\nResult: Passed",
    "char_start": 0,
    "char_end": 506,
    "heading_path": ["Warehouse Inspection Summary"],
    "page_start": null,
    "page_end": null,
    "approx_tokens": 127,
    "frame_index": 0,
    "source": "bundled-sample:sample.png",
    "document_index": 0
}
```

Images have no pages, so `page_start` and `page_end` are always `null`; `frame_index` says which image or TIFF page the chunk comes from.

The dataset is not in reading order: an image's chunk rows are stored before its image row, and in a multi-page TIFF the row of the first page read comes after the other pages. Sort by `document_index`, `frame_index` and `chunk_index` (or `record_type` first) when the order matters, for example before exporting to CSV or Excel.

Error codes in `error_code`: `UNSUPPORTED_FORMAT` (not one of the supported image formats; a PDF gets a link to the PDF Actor), `IMAGE_TOO_LARGE` (over 60 megapixels), `IMAGE_TOO_SMALL` (under 8 pixels on a side or 200 pixels in all, such as tracking pixels and spacers), `CORRUPT_IMAGE` (the file is damaged), `DOWNLOAD_FAILED`, `FILE_TOO_LARGE`, `BLOCKED_DESTINATION`, `TIMEOUT`, `OUT_OF_MEMORY`, `WORKER_CRASHED`, `INTERNAL_ERROR`, `INVALID_INPUT`, and `CHARGE_LIMIT` for skipped images. Warnings: `NO_TEXT_FOUND`, `LOW_CONFIDENCE`, `DOWNSCALED`, `ROTATION_UNCERTAIN`, `FRAMES_TRUNCATED`, `FIRST_FRAME_ONLY`, `FRAMES_FAILED`, and `CHARGE_LIMIT` on a TIFF whose later pages were cut off by your maximum charge.

Every chunk row has `document_id`, `chunk_id`, `chunk_index`, `text`, `char_start`, `char_end`, `heading_path`, `page_start`, `page_end` and `approx_tokens`, the same fields as the other Actors listed below, so their chunks can share one vector index. `markdown[char_start:char_end]` is exactly the chunk's `text`.

Row `status` is `ok`, `partial` (OCR ran but its mean word confidence is below 60, so the text may contain errors: warning `LOW_CONFIDENCE`), `failed` (nothing extracted; `error_code` says why) or `skipped` (not started: `CHARGE_LIMIT` when your maximum charge was reached, `TIMEOUT` when the run was about to time out). If Apify restarts a run while an item is being charged, that item is not processed again: its row carries a `BILLING_UNCERTAIN_AFTER_RESTART` warning, and its `charged_events` may not list every charge made before the restart. A restart just after an image's chunk rows were saved can repeat those rows with the same `chunk_id`, and the rows of a TIFF's other pages with the same `document_id` and `frame_index` (the image is charged once), so dedupe chunks by `chunk_id` and page rows by `document_id` and `frame_index`. The run's key-value store also gets a `SUMMARY` record with the counts for the whole run (files, and TIFF pages under `frames`), plus `charge_limit_reached` when your maximum charge cut a file short and `ignored_keys` when a key-value store held records that were not read.

### Pricing

This Actor is priced per event: you pay for what was processed.

| Event | Price | When it is charged |
|---|---|---|
| `image-processed` | $0.007 | Once per image, and once per TIFF page, on which OCR ran (status `ok` or `partial`), including images where OCR found no text. |

Apify adds the Actor start fee to every run ($0.00005 per run at up to 1 GB of memory, once more for each extra GB). Chunks, files and dataset rows are not charged separately: this Actor does not use the `apify-default-dataset-item` event.

Worked examples:

- 1,000 screenshots: 1,000 x `image-processed` = $7.00, plus the start fee. One run at the default 1 GB and 1-hour timeout reads about 250 screenshots, so give such a batch a longer timeout (about 4 hours) or split it into runs; see Limits.
- A 10-page TIFF: 10 x `image-processed` = $0.07. The same TIFF in `estimate` mode: no event charges.

Never charged by this Actor: items that fail (unsupported, too large, too small, unreachable, unreadable), items skipped at your maximum charge or the run timeout, the bundled sample, `estimate` mode, and TIFF pages beyond `maxFramesPerFile`. Only Apify's start fee applies to those runs.

**Your maximum charge is respected.** Before each item the Actor checks what is left of your run's maximum total charge and processes only what it can charge for, keeping one unit's price unspent below your limit. An item that cannot be afforded, and every item after it, is listed as `skipped` with `CHARGE_LIMIT` and is not charged; the run normally finishes as *Succeeded*. Rerun the skipped items with a higher limit.

### Limits: read before you buy

- **Scans, screenshots and clean exports.** Tesseract reads printed text well. Camera photos taken at an angle, in poor light or of curved pages come out much worse, and handwriting is not supported.
- **An image where OCR ran but found no text is still charged** one `image-processed` event (its row has the warning `NO_TEXT_FOUND`).
- **Speed**: at the default 1 GB of memory, about 3-4 s for a small label, 12-15 s for a full-HD screenshot, 17-19 s for a 200 DPI letter page and 21-38 s for a 300 DPI A4 scan (measured on Apify on 2026-10-02 with synthetic images; real files vary). 2 GB is about twice as fast, so choose it for large batches. If your images are already upright, setting `autoRotate` to `false` saves another 40-50%.
- **Run timeout**: a run stops at its timeout, 1 hour by default. At 1 GB that is about 200-300 images or pages; the rest are listed as `skipped` with `TIMEOUT` and are not charged. For bigger batches raise the timeout in the run options, choose 2 GB, or split the batch.
- **Languages**: only the 8 listed, at most 3 per run. Mixing scripts lowers accuracy.
- **Size**: images are scaled down above `maxPixelsMp` (12 megapixels by default, at most 20; warning `DOWNSCALED`) and refused above 60 megapixels (`IMAGE_TOO_LARGE`). Images under 8 pixels on a side or 200 pixels in all fail with `IMAGE_TOO_SMALL` and are not charged.
- **No table structure**: with `layout` `auto`, Tesseract usually reads a table column by column, so values lose their row (all the labels first, then all the amounts). For invoices, receipts and other tables use `layout` `single_block`, which keeps each row on one line; it can miss a very large title. Lines that end in amounts keep their line breaks in `markdown`.
- **Headings and lists** in `markdown` are best-effort guesses from text size and markers; check them before relying on them.
- **Photos**: a photo of a page with a background or slight blur may not be turned upright when it has no EXIF orientation (for example after a messenger app re-saved it). Such images come out `partial`, usually with `ROTATION_UNCERTAIN`; send them upright or rotate them first.
- **Formats**: PNG, JPEG, TIFF, WebP, BMP and the first frame of a GIF or animated WebP (warning `FIRST_FRAME_ONLY`). The format is read from the file's first bytes, not its name. PDFs are refused: use the [PDF to Markdown & RAG Chunks](https://apify.com/bongo-seakhoa/pdf-to-markdown-rag-chunks) Actor. HEIC, AVIF, SVG and camera RAW files are not supported.
- **Boxes and sizes**: word and line boxes, `width` and `height` are in pixels of the image as OCR saw it, after rotation and downscaling (`original_width` and `original_height` give the size before downscaling).
- **No image clean-up** beyond rotation and downscaling: no deskew, denoise or dewarp.
- **Links**: only public http(s) addresses are fetched, and every redirect is checked the same way. Links to private, local or cloud-metadata addresses, and links carrying a user name or password, fail with `BLOCKED_DESTINATION` and are not charged.
- **Per run**: at most 1,000 listed sources plus up to 1,000 records read from a key-value store; files up to `maxFileSizeMb` but never more than a quarter of the run's memory.

### FAQ

**Is my file sent to an AI service?** No. OCR runs inside the Actor's container with Tesseract. Your images go nowhere else, and no language model is involved.

**Why is an image `partial`?** OCR ran, but the mean word confidence is below 60 (`LOW_CONFIDENCE`), so the text may contain errors. It is charged like an `ok` image. Blurred photos, busy backgrounds and the wrong `ocrLanguages` are the usual causes.

**Can I read the output from code?** Yes. Use the dataset items endpoint and filter on `record_type`, or download the files from the run's key-value store.

**Something does not work.** Open an issue on the Actor's Issues tab with the run link and, if you can share it, a file that shows the problem. Issues are read on a best-effort basis; there is no guaranteed response time.

**Why was I charged for an image with no text?** OCR ran on it: the work was done, and the row says `NO_TEXT_FOUND`. If you are unsure whether a batch has text, try a few images first. Images that cannot be read at all (unsupported, too large, damaged) are never charged.

**Can I send PDFs?** No. Scanned or digital PDFs go to the [PDF to Markdown & RAG Chunks](https://apify.com/bongo-seakhoa/pdf-to-markdown-rag-chunks) Actor, which runs the same OCR on scanned pages and reads the text layer of digital ones.

**What does `estimate` mode cost?** None of this Actor's events, only Apify's start fee. It opens each file's header, counts the images and TIFF pages that would be read and shows `projected_cost_usd` per row. Because it reads only headers, a file damaged further in can be projected and then fail in `convert` mode with `CORRUPT_IMAGE`; failed images are never charged.

**How do I find the text of one TIFF page?** Each page has its own image row with `frame_index` (from 0); chunk rows carry the same `frame_index`.

### Privacy and data retention

The Actor reads only the URLs and key-value store records you give it. Your files are processed inside your run and are not sent anywhere else. The log contains counts, status and error codes, never file content or URLs. The Actor keeps nothing after the run ends: the outputs live in your run's dataset and key-value store under your Apify account, and Apify's storage retention applies to them.

### More Actors from the same developer

These Actors share one output format for chunks, so their results can go into the same index:

- [PDF to Markdown & RAG Chunks](https://apify.com/bongo-seakhoa/pdf-to-markdown-rag-chunks): PDFs, tables to CSV, offline OCR.

### About the sample and the tests

The bundled sample and every test file used to develop this Actor are synthetic: generated for the purpose and labelled synthetic (see `sample/PROVENANCE.md` in the source). No third-party files were used.

### Licences

The Actor is proprietary software by Bongo Seakhoa. It is built on open-source components under permissive licences (Tesseract OCR and its language data (Apache-2.0), Pillow (MIT-CMU), pytesseract (Apache-2.0), the Apify SDK (Apache-2.0) and httpx (BSD-3-Clause), among others). certifi (MPL-2.0) is included unmodified. Tesseract comes unmodified from Debian packages; the Debian base image also contains GPL and LGPL system programs and libraries, used unmodified as separate programs and libraries. The full list and licence texts are in the `THIRD_PARTY_NOTICES` file shipped with the Actor image.

# Actor input Schema

## `sources` (type: `array`):

Direct links to PNG, JPEG, TIFF, WebP, BMP or GIF files (http or https). The format is read from the file's first bytes, not its name. Redirects are followed and Dropbox '?dl=0' links are turned into downloads. PDFs are refused: use the PDF to Markdown & RAG Chunks Actor for those.

## `keyValueStoreId` (type: `string`):

Pick a key-value store that holds image files. Without record keys below, every record whose key has an image file extension (.png, .jpg, .tiff ...) or no extension at all (like scan-0001) is read, up to 1,000; the format is read from each file's first bytes. Records named like other files (.json, .txt ...) are left out and counted under ignored_keys in the SUMMARY record.

## `keyValueStoreKeys` (type: `array`):

Keys of image records in the store picked above. Leave empty to read every image record.

## `ocrLanguages` (type: `array`):

Languages in your images, at most 3. Choose only the ones you need: each extra language slows OCR down, and mixing scripts lowers accuracy.

## `layout` (type: `string`):

'auto' lets Tesseract find the text blocks (pages, documents). 'single_block' treats the image as one block of text (a cropped paragraph or label). 'sparse' looks for scattered text in no particular order (screenshots, forms, signs).

## `autoRotate` (type: `boolean`):

Detect pages turned by 90, 180 or 270 degrees and turn them upright before OCR. Skipped for images under about 300 pixels tall.

## `mode` (type: `string`):

'convert' runs OCR. 'estimate' only counts the images and TIFF frames that would be read and shows the projected price. It charges none of this Actor's events (Apify's standard Actor start fee still applies).

## `outputs` (type: `array`):

What to produce. Text and Markdown go into each image row (Markdown also into a .md file); words and lines are saved as JSON files with pixel boxes and confidence; chunks become their own rows.

## `chunkSize` (type: `integer`):

Maximum length of each chunk in characters (about 4 characters per token). Chunks break at headings, paragraphs and sentences.

## `chunkOverlap` (type: `integer`):

Characters repeated between consecutive chunks. At most half the chunk size.

## `maxPixelsMp` (type: `integer`):

Larger images are scaled down to this size before OCR, which keeps memory and time in check. Images over 60 megapixels are refused with IMAGE_TOO_LARGE.

## `maxFileSizeMb` (type: `integer`):

Larger files are not downloaded and are reported as failed (not charged). The limit is also capped at a quarter of the run's memory: 128 MB at 512 MB, 256 MB at the default 1 GB.

## `maxFramesPerFile` (type: `integer`):

Each page of a multi-page TIFF is read and charged as its own image, up to this many per file. Further pages are left out (warning FRAMES_TRUNCATED) and not charged. GIF and animated WebP files are read at their first frame only.

## `perImageTimeoutSecs` (type: `integer`):

An image (or TIFF frame) that takes longer fails with TIMEOUT and is not charged.

## Actor input object example

```json
{
  "sources": [],
  "keyValueStoreKeys": [],
  "ocrLanguages": [
    "eng"
  ],
  "layout": "auto",
  "autoRotate": true,
  "mode": "convert",
  "outputs": [
    "text",
    "markdown",
    "chunks"
  ],
  "chunkSize": 1500,
  "chunkOverlap": 150,
  "maxPixelsMp": 12,
  "maxFileSizeMb": 50,
  "maxFramesPerFile": 50,
  "perImageTimeoutSecs": 120
}
```

# Actor output Schema

## `results` (type: `string`):

One row per image or TIFF frame (record_type 'image') and one per RAG chunk ('chunk').

## `files` (type: `string`):

Full Markdown per image, word and line boxes as JSON when requested, and the run SUMMARY, in the run's key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("bongo-seakhoa/image-to-text-ocr-markdown").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("bongo-seakhoa/image-to-text-ocr-markdown").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call bongo-seakhoa/image-to-text-ocr-markdown --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bongo-seakhoa/image-to-text-ocr-markdown"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jySBAkYZE82jMRxxD/builds/9ea7m96db87upW0P0/openapi.json
