City-localised ad backdrops: one product photo, many cities

Run one product ad in ten cities by changing only the backdrop. A Sume image API loop with a fixed product prompt, per-city results and a cost log, with checks.

4 min readSume
All posts

A product launched across ten cities can show ten skylines behind it: the same bottle, backpack or sneaker, different street. Doing it with a photographer is ten shoots. Doing it with Sume's Image API is a loop.

The rule that keeps it clean: the product sentence never changes, and only the city line does.

The loop

Keep the city list in code, and save the response with the city name. Each request carries the same reference and the same product sentence.

import os, requests

H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
CITIES = ["Seoul at dusk", "Lisbon on a tiled street", "Chicago by the river"]
KEEP = "Keep this exact product: shape, colour and logo unchanged."
for city in CITIES:
    r = requests.post("https://api.sume.com/v1/images", headers=H, timeout=90, json={
        "model": "openai/gpt-image-2.5",
        "prompt": f"Photograph the product in front of {city}. {KEEP}",
        "input_references": [{"type": "image_url",
            "image_url": {"url": "https://example.com/product.jpg"}}],
        "aspect_ratio": "4:5",
    })
    r.raise_for_status()
    print(city, r.json()["data"][0]["url"], r.json().get("usage"))

Checks for local backdrops

  • Signs and storefronts do not show real brand names or legible text that you did not choose.
  • People in the background are generic and unidentifiable.
  • The product is the same size and colour in all cities.
  • Local details are correct enough: a Lisbon tile street should not look like Tokyo.

From stills to video

The same idea extends to video through an edit prompt, covered in the ad multiplier post. For stills, the main number to track is the cost per city, which usage.cost gives on every response.

Before you run a catalog

Run one SKU end to end first. POST /v1/images returns the images directly when it finishes within 30 seconds; past that it returns a 202 envelope with status_url and result_url, which the jobs and results guide explains. Handle that branch before you loop over a catalog, and write each result's URL and usage.cost to a file keyed by SKU, so a failed run restarts where it stopped and nothing is paid for twice.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume