Free · No upload · Runs in your browser

Google Cloud Vision: send an image as Base64

Drop the image, copy the images.annotate body, send it. Cloud Vision takes the raw Base64 payload only — no data: prefix — in the image.content field. The tool below emits exactly that string.

100% client-side. The image never leaves your device.

Drop an image to build the annotate payload

or paste from your clipboard · everything stays in your browser

No image handy? Try a sample:

The images.annotate request body

The REST endpoint is POST https://vision.googleapis.com/v1/images:annotate, authenticated with an API key (?key=YOUR_API_KEY) or an OAuth bearer token. The body is a requests array; each entry pairs an image with the detections you want:

{
  "requests": [{
    "image": { "content": "iVBORw0KGgoAAAANS..." },
    "features": [
      { "type": "TEXT_DETECTION" },
      { "type": "LABEL_DETECTION", "maxResults": 5 }
    ]
  }]
}

Each features entry names one detection: TEXT_DETECTION / DOCUMENT_TEXT_DETECTION for OCR, LABEL_DETECTION for scene labels, FACE_DETECTION, OBJECT_LOCALIZATION, LOGO_DETECTION, SAFE_SEARCH_DETECTION, and so on. One image can carry several features in a single request.

Raw Base64 only — the prefix causes the error

The content field is a bytes field in the Image proto. JSON has no native bytes type, so the API uses Base64 as the transport encoding — which means the string you paste must be nothing but Base64. A data:image/png;base64, prefix is not valid bytes, and the request fails with a payload/encoding error instead of a helpful hint about the prefix.

This is the opposite of the OpenAI vision API, where the value must be a complete data URI. If you feed both APIs from the same pipeline, split the string at the first comma and keep the right half for Cloud Vision — or let the API payload builder emit both shapes from one encode.

Python example

Standard library plus requests — encode the file, post the body:

import base64
import requests

with open("receipt.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode("utf-8")

resp = requests.post(
    "https://vision.googleapis.com/v1/images:annotate",
    params={"key": API_KEY},
    json={
        "requests": [{
            "image": {"content": b64},
            "features": [{"type": "DOCUMENT_TEXT_DETECTION"}],
        }]
    },
)
annotation = resp.json()["responses"][0]
print(annotation.get("fullTextAnnotation", {}).get("text", ""))

The official google-cloud-vision client library wraps the same call — pass the bytes and it handles the Base64 transport for you. The prefix pitfall only bites when you build the JSON by hand.

Limits: 20 MB, 75 megapixels, and when to use a URI instead

Google's documentation caps image requests at 20 MB and 75 megapixels. Base64 works against you twice: the string is about a third larger than the file, and it all counts against the request body. For anything large, Google recommends a different route — put the file in a Cloud Storage bucket (or any reachable HTTPS URL) and pass "source": { "imageUri": "gs://bucket/receipt.png" } instead of content.

If both fields are present, content takes precedence and the API ignores the source — worth knowing when a config merge leaves both populated.

Batching several images

One call can carry multiple requests entries — the response mirrors them in order as a responses array. Two practical notes: inline Base64 for every image multiplies the body size, and a single malformed entry fails its own response rather than the whole batch, so check each element for an error key instead of assuming the array is uniform.

Where the encoded string usually breaks

  • A leftover prefix. Copying the full data URI from a browser devtools panel and pasting it into content — the data: head must go.
  • Wrapped lines. Some tools emit Base64 with line breaks; raw newlines are invalid inside a JSON string. This tool emits a single line.
  • A quoted-inside-quoted body. Assemble JSON with a serializer, not string concatenation, so the Base64 characters (+/=) land unescaped and intact.
  • Size creep. A 4 MB scan becomes a 5.3 MB string; two of them plus a verbose features list pushes the request over the cap. The compressor and the size calculator keep you honest.

Why encode in the browser

Documents run through OCR are exactly the material that should not be pasted into an upload-based converter: invoices, contracts, ID scans, internal reports. This page encodes with the browser's FileReader API — no upload step exists, which you can verify in the Network tab: converting fires zero requests.

Frequently asked questions

How do I send a Base64 image to Google Cloud Vision?

POST to images:annotate with a requests array; each entry carries the image under image.content as raw Base64 and names its detections in features.

Does Cloud Vision want the data: prefix or raw Base64?

Raw Base64 only — content is a bytes field, so a data: prefix is invalid there. OpenAI is the opposite: it wants the full data URI.

What are the image size limits?

20 MB per image request and 75 megapixels, per Google's documentation. Base64 adds about a third to the byte count; for large files use source.imageUri with a Cloud Storage or HTTPS URI.

What happens if I pass both content and source?

content wins — the Image proto documents that inline bytes take precedence and the source is ignored.

Can I annotate several images in one request?

Yes — multiple entries in the requests array, answered in order by responses. Every inline payload counts against the body size, and each entry can fail independently, so check for per-entry error keys.

Which feature types can I request?

OCR (TEXT_DETECTION, DOCUMENT_TEXT_DETECTION), LABEL_DETECTION, FACE_DETECTION, OBJECT_LOCALIZATION, LOGO_DETECTION, SAFE_SEARCH_DETECTION and more — one entry per feature in the array.