X image ad specs: 1:1 or 1.91:1, 800px wide, 3 MB, from Sume
X website image cards take 1:1 or 1.91:1, at least 800px wide and 3 MB. Render 2:1 on Sume, crop to 1.91:1 with Pillow, and check size before upload.

According to X's Creatives documentation, website and app-download image cards support 1:1 and 1.91:1, with a minimum width of 800px, a 3 MB file cap, and .bmp, .jpeg or .png files. Sume's Image API has 1:1 natively. For 1.91:1, request 2:1 and crop about 4.5% off the height.
Spec and the Sume route
| Spec | Value | Sume route |
|---|---|---|
| Ratios, website card | 1:1 and 1.91:1 | 1:1 native; 1.91:1 by cropping a 2:1 render |
| Minimum width | 800px | Check the returned image width |
| Maximum file size | 3 MB | Choose jpeg and check the file |
| File types | .bmp, .jpeg, .png | output_format jpeg or png |
Render 2:1 then crop and check
The script stops on a 202, asserts the width, saves a JPEG, and prints the byte size against the 3 MB cap. Use a model whose catalog lists 2:1; Ideogram 4.5 does.
import io, os, requests
from PIL import Image
API = "https://api.sume.com"
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
body = {"model": "ideogram/ideogram-v4.5", "aspect_ratio": "2:1", "quality": "low",
"output_format": "jpeg", "prompt": "Wide product banner, plain light background"}
r = requests.post(f"{API}/v1/images", headers=H, json=body, timeout=60)
r.raise_for_status()
if r.status_code == 202:
raise SystemExit("job still running")
img = Image.open(io.BytesIO(requests.get(r.json()["data"][0]["url"], timeout=60).content)).convert("RGB")
w, h = img.size
new_h = round(w / 1.91)
top = (h - new_h) // 2
out = img.crop((0, top, w, top + new_h))
assert out.width >= 800, f"width {out.width} is under 800"
out.save("x-card.jpg", quality=90)
print(out.size, os.path.getsize("x-card.jpg") <= 3_000_000)Notes
- The page does not say whether 3 MB means 3,000,000 or 3,145,728 bytes; the script uses the smaller one, 3,000,000 bytes, to be safe.
- Crop trims the top and bottom, so keep text away from those edges.
Sources
Related posts
More in Use cases
- X lead generation form: name up to 255 characters, purpose 1000
X's Ads API lead generation docs cap a form name at 1 to 255 characters and its purpose at 1 to 1000. Validate copy variants before you create the form.
- X lead generation form fields: work email, job title, company
X's lead generation docs list contact and user-information fields, including WORK_EMAIL, JOB_TITLE and COMPANY_NAME. Pick fields to match each ad variant.
- X post media mix: 4 photos, 1 GIF or 1 video, and 0.5 s video minimum
An X post can carry up to 4 photos, or 1 animated GIF, or 1 video, and video must be at least 0.5 seconds. Pick the right Sume export for each case.
- Yoga studio class promo clip: Kling 3 for 8 seconds, audio or silent
An 8-second class promo clip with kling-3 on Sume costs $1.12 silent and $1.68 with audio; vertical 9:16 at 720p or 1080p is the same rate.
Written by Sume