Turn photos, pictures, scans, and screenshots into clean, searchable text in one API call. OCR in more than 100 languages, with a confidence score on every block of text when you need to check the result. Read about 3,300 images a month on the free plan.
PNG, JPEG, TIFF, BMP, GIF, WebP, SVG, HEIC, TGA, and EPS go to the same endpoint as PDFs and Word, Excel, and PowerPoint files. The API detects the file type from the content.
In spatial JSON, every block of text comes with its position on the page and a confidence score, so uncertain results can go to review.
Structure mode reads clean images for 1.5 credits per page (a single image is one page). Step up to understand (9) or agentic (18) only for forms, handwriting, and degraded scans.
Three steps
Read text from an image in a single call to Nutrient’s Data Extraction API, starting from the image file itself.
Create a free account for a Data Extraction API key. The free plan includes 5,000 credits each month, which is about 3,300 images in structure mode.
An image has no text layer, so it needs OCR. Structure mode reads clean photos and scans for 1.5 credits per page, and a single image is one page.
The text in the image comes back as one string in output.markdown.
This example reads the text from an image with the Data Extraction API.
image.jpg and run the sample from the same folder. The text comes back in output.markdown; the JavaScript, Java, C#, and PHP samples write it to result.md. The Python sample prints it, and the shell samples print the full JSON response.structure mode. For forms, tables, and printed handwriting, set mode to understand. For cursive handwriting and degraded scans, set it to agentic, which adds AI visual reasoning."options":{"language":"german"} to the instructions."output":{"format":"spatial"}. The elements come back in output.elements.curl -X POST https://api.nutrient.io/extraction/parse \ -H "Authorization: Bearer your_api_key_goes_here" \ -F "file=@image.jpg" \ -F 'instructions={"mode":"structure","output":{"format":"markdown"}}'curl -X POST https://api.nutrient.io/extraction/parse ^ -H "Authorization: Bearer your_api_key_goes_here" ^ -F "file=@image.jpg" ^ -F "instructions={\"mode\":\"structure\",\"output\":{\"format\":\"markdown\"}}"package com.example.nutrient;
import java.io.File;import java.io.IOException;import java.nio.file.Files;import java.nio.file.Paths;
import org.json.JSONObject;
import okhttp3.MediaType;import okhttp3.MultipartBody;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.RequestBody;import okhttp3.Response;
public final class NutrientParseExample { public static void main(final String[] args) throws IOException { final RequestBody body = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart( "file", "image.jpg", RequestBody.create( MediaType.parse("image/jpeg"), new File("image.jpg") ) ) .addFormDataPart( "instructions", new JSONObject() .put("mode", "structure") .put("output", new JSONObject() .put("format", "markdown") ).toString() ) .build();
final Request request = new Request.Builder() .url("https://api.nutrient.io/extraction/parse") .method("POST", body) .addHeader("Authorization", "Bearer your_api_key_goes_here") .build();
final OkHttpClient client = new OkHttpClient().newBuilder().build(); final Response response = client.newCall(request).execute();
if (response.isSuccessful()) { // The response is JSON. The Markdown is in output.markdown. final JSONObject payload = new JSONObject(response.body().string()); final String markdown = payload .getJSONObject("output") .getString("markdown");
Files.writeString(Paths.get("result.md"), markdown); } else { throw new IOException(response.body().string()); } }}using System;using System.IO;using System.Text.Json;using RestSharp;
namespace NutrientParseDemo{ class Program { static void Main(string[] args) { var client = new RestClient("https://api.nutrient.io/extraction/parse");
var request = new RestRequest(Method.POST) .AddHeader("Authorization", "Bearer your_api_key_goes_here") .AddFile("file", "image.jpg") .AddParameter( "instructions", "{\"mode\":\"structure\",\"output\":{\"format\":\"markdown\"}}" );
var response = client.Execute(request);
if (response.IsSuccessful) { // The response is JSON. The Markdown is in output.markdown. using var document = JsonDocument.Parse(response.Content); var markdown = document.RootElement .GetProperty("output") .GetProperty("markdown") .GetString();
File.WriteAllText("result.md", markdown); } else { Console.Write(response.Content); } } }}// This code requires Node.js. Do not run this code directly in a web browser.import fs from "node:fs";
const form = new FormData();form.append("file", await fs.openAsBlob("image.jpg"), "image.jpg");form.append( "instructions", JSON.stringify({ mode: "structure", output: { format: "markdown" } }),);
const response = await fetch("https://api.nutrient.io/extraction/parse", { method: "POST", headers: { Authorization: "Bearer your_api_key_goes_here" }, body: form,});if (!response.ok) throw new Error(await response.text());
const result = await response.json();fs.writeFileSync("result.md", result.output.markdown);import requests
response = requests.post( "https://api.nutrient.io/extraction/parse", headers={"Authorization": "Bearer your_api_key_goes_here"}, files={"file": open("image.jpg", "rb")}, data={ "instructions": '{"mode":"structure","output":{"format":"markdown"}}' },)response.raise_for_status()
result = response.json()print(result["output"]["markdown"])<?php
$curl = curl_init();
curl_setopt_array($curl, array( CURLOPT_URL => 'https://api.nutrient.io/extraction/parse', CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_POSTFIELDS => array( 'instructions' => '{"mode":"structure","output":{"format":"markdown"}}', 'file' => new CURLFILE('image.jpg') ), CURLOPT_HTTPHEADER => array( 'Authorization: Bearer your_api_key_goes_here' ),));
$response = curl_exec($curl);$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($status !== 200) { throw new Exception($response);}
// The response is JSON. The Markdown is in output.markdown.$payload = json_decode($response, true);
file_put_contents('result.md', $payload['output']['markdown']);Example output
An excerpt from a real response for a screenshot of release notes with fictitious names. Structure mode, 1.5 credits.
{ "output": { "markdown": "Example App 4.2 release notes\n\n\nFaster sync. Projects now open twice as fast on large accounts.\n\n\nOffline mode. Edits made without a connection upload automatically when the device reconnects.\n\n\nDark theme. Turn it on under Settings, then Appearance.\n\n\nFixed. Exported reports no longer drop the last page.\n\n\nReleased 14 October 2026. All names are fictitious.\n" }}OCR built in
Images have no text layer, so each of these processing modes reads them with OCR.
Clean photos, screenshots, and simple scans. 1.5 credits per page (a single image is one page).
Forms, tables, multicolumn layouts, and printed handwriting. 9 credits per page.
Adds AI visual reasoning for cursive handwriting, faxes, and degraded scans. 18 credits per page.
Use cases
Read merchant, date, and total lines from photos of receipts. For named fields with citations, see receipt data extraction.
Turn scanned or photographed forms into text, with understand mode for printed handwriting and checkboxes.
Read brand names, ingredients, and codes printed on product photos and package labels.
Make screenshots in support tickets, chats, and documentation searchable.
Use agentic mode for cursive handwriting on notes, letters, and annotated pages.
Most common next steps
Use the following:
Get started:
Platform resources:
Nutrient is SOC 2 Type 2 audited annually. See the security documentation and privacy documentation for details on data handling.
All API communication uses HTTPS with TLS encryption. Unencrypted HTTP requests are rejected.
Nutrient’s image-to-text converter API reads the text in an image with OCR and returns it in a single call. To describe charts and pictures instead of reading their text, agentic mode adds a generated description to each chart and picture element in spatial JSON. The API returns the text from photos, scans, and screenshots as Markdown. Alternatively, it returns spatial JSON with a bounding box and confidence score for each block of text. Unlike self-hosted OCR libraries such as Tesseract, Nutrient’s Data Extraction API runs as a hosted API, so there’s no OCR engine to install or maintain.
Nutrient’s Data Extraction API takes the image in one POST /extraction/parse request, with mode set to structure and output.format set to markdown. The text comes back in output.markdown.
Nutrient’s Data Extraction API accepts PNG, JPEG, TIFF, BMP, GIF, WebP, SVG, HEIC, TGA, and EPS, plus PDFs and Office files. It detects the type from the file content. See the supported file types.
Yes, Nutrient’s Data Extraction API free plan includes 5,000 credits each month, with no credit card required. Structure mode costs 1.5 credits per page, and a single image is one page, so that’s about 3,300 images a month on the free plan. See Data Extraction API pricing.
Nutrient recommends structure mode for clean photos and screenshots. Use understand mode for forms, tables, and printed handwriting, and agentic mode for cursive handwriting and degraded scans.
Nutrient’s Data Extraction API applies one rate limit per organization, shared by all its requests: It’s currently 100 requests per minute. A request over the limit returns 429 Too many requests; retry with exponential backoff. See the errors guide.
Yes, Nutrient’s Data Extraction API takes one file per request, so a batch is a loop over files. The document extraction pipeline tutorial shows a batch loop in Python.
Nutrient’s image-to-text API works from any language that makes HTTP requests. Nutrient provides examples for JavaScript, Python, Java, C#, and PHP, plus REST and a Postman collection.
Create an account to get your Data Extraction API key and start making API calls.