When you want to edit images with Gemini, the input image workflow is how you hand a reference picture to the model alongside your text prompt and get a modified picture back. The current surface for this is the Interactions API with the gemini-3.1-flash-image model: input is a list of typed content blocks, the response is base64 image data, and follow-up edits are chained through previous_interaction_id. This walkthrough covers the Python version of that workflow, the Gemini API environment variables you need, the Gemini image API aspect ratio and image size knobs, and the places where the documented surface still leaves gaps for implementers.
The shape of an input-image request
An image editing request is just a normal Interactions call whose input array mixes typed blocks. A text block carries the instruction and an image block carries the reference picture. The image block has three required fields per Google's image generation documentation:
type— the literal string"image"data— the picture encoded as a base64 stringmime_type— for example"image/png"or"image/jpeg"
The model returns interaction.output_image with a data field that is itself base64, so the round trip is symmetric: read bytes, base64-encode for input, base64-decode for output. The Gemini image API ships SDK examples in Python, JavaScript, Java, and raw REST, and all four follow this same block-list shape, which is what makes the input image workflow portable across languages.
A runnable Python example for editing
The Gemini image API example in the official docs reads a local file, base64-encodes it inside the input list, and decodes the returned image straight to disk. The structure is:
from google import genai
import base64
client = genai.Client()
with open("/path/to/cat_image.png", "rb") as f:
image_bytes = f.read()
interaction = client.interactions.create(
model="gemini-3.1-flash-image",
input=[
{"type": "text", "text": "Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme"},
{"type": "image", "data": base64.b64encode(image_bytes).decode("utf-8"), "mime_type": "image/png"},
],
)
with open("generated_image.png", "wb") as f:
f.write(base64.b64decode(interaction.output_image.data))
Three things are worth noting because they are common Gemini image API errors sources:
- The image goes in as a base64 string, not a raw byte buffer. The
b64encode(...).decode("utf-8")step is what flips the type frombytestostr; the official example uses this exact pattern. - The
mime_typemust match the bytes you sent. Passingimage/pngwith JPEG bytes (or vice versa) is an easy way to get a rejected request. - Always read
interaction.output_imagedefensively. The JavaScript example in the docs only writes the file inside anif (generatedImage)guard, which is the safe pattern even though the Python snippet shown in the guide writes unconditionally.
If you want the REST equivalent with the same field names, the official guide shows the request body as a JSON array with type, mime_type, and data keys, posted to https://generativelanguage.googleapis.com/v1beta/interactions with the API key in an x-goog-api-key header.
Chaining edits with previous_interaction_id
The recommended way to iterate on an image is multi-turn. The first call generates the picture, every later call references it through previous_interaction_id and supplies a new instruction. The model treats the chained call as a follow-up to the previous one rather than a fresh start, which keeps visual elements stable across rounds.
interaction_2 = client.interactions.create(
model="gemini-3.1-flash-image",
input="Update this infographic to be in Spanish. Do not change any other elements of the image.",
previous_interaction_id=interaction.id,
response_format={
"type": "image",
"mime_type": "image/jpeg",
"aspect_ratio": "16:9",
"image_size": "2K",
},
)
This pattern is what the official Gemini image generation page recommends over regenerating from scratch on each iteration, because it preserves character, palette, and layout and only changes what your new instruction targets. The Gemini image editing API is therefore best thought of as a conversation with a canvas, not a one-shot text-to-image endpoint.
Controlling output: aspect ratio and image size
Output shape is not negotiated by the prompt. It is set explicitly through response_format, which currently supports four fields in the documented examples:
type— set to"image"mime_type— output format such as"image/png"or"image/jpeg"aspect_ratio— a string such as"16:9"image_size— a string such as"2K"
The exact list of valid Gemini image API aspect ratio strings and image_size values beyond the "16:9" and "2K" shown in the official examples is not enumerated in the fetched source, so check the live doc before relying on a specific value.
Environment variables and local setup
The Python client requires a Gemini API key. The Nano Banana local client guide spells this out step by step:
export GEMINI_API_KEY="your-key-here"
The full local workflow is:
- Grab a key from Google AI Studio and store it in
GEMINI_API_KEY. - Create a Python virtual environment with
python -m venv venvand activate it. - Install the SDK with
pip install -U google-genai. - Run the input-image example above against
gemini-3.1-flash-image.
A practical clarification the same guide makes explicit, and worth repeating here: even though your script runs on your machine, the core model is closed source and runs on Google's current Gemini image infrastructure. Running the Gemini image API Python client locally does not make the model local or offline — your computer is acting as a controller, not a host. The same guide also flags that the API surface changes over time, so re-check the maintained Nano Banana Python tutorial and Google's image generation documentation before relying on specific field names or code shapes.
If you genuinely need offline image editing, the Nano Banana quickstart points at open alternatives such as HunyuanImage 3.0 and Qwen-Image-Edit-2511, with the trade-off noted in the guide that they usually require a stronger GPU and more setup than the cloud client.
Known gaps in the public docs
A few details that beginners usually need are not pinned down in the fetched snippets, and the official page itself is the source of truth rather than third-party tutorials:
- The full enumeration of supported
mime_typevalues beyondimage/pngandimage/jpegis delegated to the Image understanding page rather than spelled out on the image generation page. The guide explicitly tells you to check that page for "multiple images, larger payloads, and supported MIME types." - Valid values for
aspect_ratioandimage_sizeoutside the"16:9"and"2K"example are not listed in the fetched content. Do not invent values; pull them from the live doc.
Where to go next
For a hands-on walkthrough that mirrors the snippets above and tracks the current Gemini image API Python surface, follow the Nano Banana local Python client walkthrough. If you are choosing between cloud and open models, the Nano Banana quickstart guide compares the closed Gemini API with offline options like HunyuanImage 3.0 and Qwen-Image-Edit-2511. And if you hit a Gemini image API error that the official page does not document, the Nano Banana FAQ collects the most common failures from real install attempts, including API key issues and MIME-type mismatches that line up with the base64 pitfall called out earlier.