# Don't eyeball AI-generated product images. Test the text like CI.

> Source: <https://dev.to/buluo/dont-eyeball-ai-generated-product-images-test-the-text-like-ci-1con>
> Published: 2026-11-11 09:40:40+00:00

If you generate product artwork through an API, at some point a render ships with the price painted wrong, and the first person to notice is a customer. Visual "quality" reviews catch that maybe. Automation catches it always. This post is about the second option — plus a baseline measurement I ran to see where two popular image models actually stand on on-image text.

**The baseline first.** On Nov 11, 2026 I sent identical prompts to **GPT Image 2** (OpenAI's reasoning-first image model, Apr 2026) and **Nano Banana Pro** (Google's Gemini 3 Pro Image, GA May 2026) through Crazyrouter — `gpt-image-2` and `nano-banana-pro` on one account and one key, three e-commerce scenes at a time, one render per prompt, every flaw kept. Fourteen required strings total: headlines, discount badges, prices, a struck-through price, a dated banner, brand names, and one tiny spec line. The verdict: **14 of 14 correct on both models** — no typos, no garbled glyphs, and no invented "decorative" words on a label that explicitly banned them.

Here are the six renders. Read them like code review, not like a gallery:

**Flash-sale hero** — check the strikethrough placement and the banner:

**Hot-sauce label** — the scene that banned extra words; scan every edge for fake typography:

**Cold-brew detail card** — the tiny `NET WT 300ml / SERVINGS: 2` line is the real exam. One defect of the whole run lives in the Nano render: dotted artifacts on the bottom-right edge. Kept on purpose:

So if both models spell, what did the run actually measure? The integration details — and that's where "trust the prompt" breaks down.

**Assert the strings, don't admire the picture**

Treat a render like a build artifact. Each prompt declares required strings and forbidden strings; after generation, run OCR over the output and diff against the declaration. Fail the job on a miss. Both of my models passed a human-read version of this check, but human reads don't run at batch scale, and OCR-based assertion is cheap enough to gate every job. Bonus: the "no invented words" constraint from the label scene is exactly the kind of assertion that catches regression when a provider silently updates a model behind the same ID.

**Model IDs are contracts that change under you**

Model naming drifts fast — I confirmed both IDs and their exposed tiers in [Crazyrouter's model directory](https://crazyrouter.com/en/models) before the run, and you should too, on your run day. Availability changes do not announce themselves in your error logs until they do.

**What differs once spelling ties**

`IncompleteRead` mid-transfer on the Nano side — connection layer, retry fixed it. A content-policy refusal would not have been retryable. Your job runner should classify failures, not blanket-retry them.`asyncGenerateContent` → poll a task id).`parts`.
Both IDs are callable from one gateway with one key — [check availability before you build](https://crazyrouter.com/en/pricing?utm_source=devto&utm_medium=article&utm_campaign=offsite_article&utm_content=cr_a1ddb274b7cf_mid_text) — and switching models is one `model` parameter plus a different request body shape. Entry point:

```
https://api.crazyrouter.com/v1
```

**The pairing that actually works**

Draft in bulk with Nano Banana Pro (cheap at 20 seconds a layout), then promote winners to GPT Image 2 for finishing — texture, typography, or a surgical mask edit. Drafting and finishing are different jobs; using one model for both is how you pay GPT-tier latency for every rejected idea.

**Not covered, on purpose**

One render per prompt, English only, 1024×1024, a single day. CJK text, extreme small type, reference-image editing, 2K/4K output — all untested, so I'm not extending the 14/14 claim to them. Automate the assertion and the next model update answers the question for you.

*Disclosure per DEV's AI guidelines: this article was written with AI assistance. Every image and every number in it comes from real API runs performed on Nov 11, 2026, and the failed/artifact-bearing renders were kept as-is.*
