https://txtfetch.com/extract/image/
OCR that's just another curl request.
Scanned receipts, faxed contracts, photographed whiteboards. Tesseract OCR runs automatically, with no separate OCR pipeline to stand up.
the-problem
Scans and photos aren't 'documents' to most extraction stacks. They're a special case. Handling them usually means a separate OCR service, with its own SDK and its own error handling. It also means a branch in your ingestion code, to detect when a file needs OCR instead of ordinary parsing. Standing that up, and keeping it patched, is its own project.
one-request-solution
In txtfetch, OCR isn't a separate code path. It's just what happens when pixels arrive. POST a PNG, JPG, or TIFF (or a scanned PDF), and Tesseract OCR runs automatically behind the same /v1/extract endpoint. You get back the same { status, extracted_text } shape as any other format.
curl -X POST https://api.txtfetch.com/v1/extract \
-H "Authorization: Bearer $TXTFETCH_KEY" \
-F file=@scanned-invoice.pngimport os
import requests
with open("scanned-invoice.png", "rb") as f:
r = requests.post(
"https://api.txtfetch.com/v1/extract",
headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"},
files={"file": f},
)
print(r.json()["extracted_text"])import { readFile } from "node:fs/promises";
const file = new Blob([await readFile("scanned-invoice.png")]);
const form = new FormData();
form.append("file", file, "scanned-invoice.png");
const res = await fetch("https://api.txtfetch.com/v1/extract", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` },
body: form,
});
const { extracted_text } = await res.json();
console.log(extracted_text);package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
type extractResponse struct {
Status string `json:"status"`
ExtractedText string `json:"extracted_text"`
}
func main() {
f, err := os.Open("scanned-invoice.png")
if err != nil {
panic(err)
}
defer f.Close()
var body bytes.Buffer
writer := multipart.NewWriter(&body)
part, err := writer.CreateFormFile("file", "scanned-invoice.png")
if err != nil {
panic(err)
}
if _, err := io.Copy(part, f); err != nil {
panic(err)
}
writer.Close()
req, err := http.NewRequest("POST", "https://api.txtfetch.com/v1/extract", &body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY"))
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result extractResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
panic(err)
}
fmt.Println(result.ExtractedText)
}Or skip the download. Pass a url parameter and txtfetch fetches the document server-side:
curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/uploads/receipt-photo.jpg" \
-H "Authorization: Bearer $TXTFETCH_KEY"import os
import requests
r = requests.post(
"https://api.txtfetch.com/v1/extract",
headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"},
params={"url": "https://example.com/uploads/receipt-photo.jpg"},
)
print(r.json()["extracted_text"])const endpoint = new URL("https://api.txtfetch.com/v1/extract");
endpoint.searchParams.set("url", "https://example.com/uploads/receipt-photo.jpg");
const res = await fetch(endpoint, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` },
});
const { extracted_text } = await res.json();
console.log(extracted_text);package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
)
type extractResponse struct {
Status string `json:"status"`
ExtractedText string `json:"extracted_text"`
}
func main() {
endpoint, err := url.Parse("https://api.txtfetch.com/v1/extract")
if err != nil {
panic(err)
}
q := endpoint.Query()
q.Set("url", "https://example.com/uploads/receipt-photo.jpg")
endpoint.RawQuery = q.Encode()
req, err := http.NewRequest("POST", endpoint.String(), nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result extractResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
panic(err)
}
fmt.Println(result.ExtractedText)
}{
"status": "success",
"extracted_text": "..."
}what-comes-back
The corpus behind /diff has no recorded .png document yet, so we have nothing honest to show you here. Run one of your own instead. The free converter reads the file in your browser, and nothing is uploaded.
try-your-own
Drop your own .png file below. Your browser reads it. Nothing uploads, and txtfetch never sees it.
Your browser can't run OCR. Drop a file below and this panel checks it for a text layer instead. The API OCRs the pixels and returns real text.
Stays in your browser. Up to 25 MB.
What's not in this text:
Your browser read this file. No request left your browser, so txtfetch never received it. The API returns this same text as { status, extracted_text }.
See the real API response in the playground. Need many files, a folder, or a .zip? Use file-to-text instead.
formats-covered
.png.jpg.jpeg.tiff.tif.bmp.gif
faq
- How do I OCR a scanned document via API?
- POST the image as multipart form data to https://api.txtfetch.com/v1/extract. Tesseract OCR runs automatically. The response is { "status": "success", "extracted_text": "..." }, with no OCR-specific parameters needed.
- Which image formats are supported for OCR?
- PNG, JPG/JPEG, TIFF, BMP, and GIF are all routed through Tesseract OCR automatically, the same as scanned PDF pages with no text layer.
- Do I need to tell txtfetch that a file needs OCR?
- No. Format detection is automatic. Any file with no extractable text layer, image or PDF, is OCR'd without any extra flag or parameter.
go-further
- Read the .png guide →
- Multi-page TIFF faxes need a different read →
- Not sure a scan will OCR cleanly? Check it free, in your browser →
- Barcodes on your scans? The bars do not come back →
- Does txtfetch read handwriting? →
- API quickstart →
- How the pipeline works →
- Extract it from your language →
- Get an API key →
Images & OCR
Send a real .png through it.
One HTTP call returns the text. Read one in your browser first, for free.
Get an API key →