Ideogram 4.0 was trained on one caption format, and it is not prose: structured JSON captions, exclusively. Natural language still works, but a JSON object following that schema reaches things prose cannot — exact colour control, bounding-box layout, per-element text placement, and compositions that hold across runs.

Why Ideogram 4.0 wants JSON

Two official pages answer the same question at different confidence levels. The product documentation is reassuring: natural language prompts still work well, and Magic Prompt expands a plain description into a structured caption. The open-weights repository is blunter — passing plain-text prompts directly to the model will not work and will likely trigger a safety warning. That is a difference of entry point, not a contradiction: the hosted product runs the expansion, raw weights do not.

Job at handDocumented approach
Quick exploration, loose ideasNatural language
Posters, branded graphics, design workJSON
Exact text placement, brand paletteJSON
Repeatable layouts across many runsJSON
Photorealistic scenes, placement not criticalNatural language

Magic Prompt writes the JSON

Three Magic Prompt configurations ship with the open-weights package: ideogram-4-v1 on Ideogram’s hosted API, plus claude-opus-v1 and claude-sonnet-v1 on OpenRouter. The hosted one is default, server-side and free, needing only an Ideogram API key. One caveat matters: the shipped Magic Prompt is not the one production ideogram.ai uses, so its output differs.

The three top-level fields

A caption has three top-level fields, and exactly one is required.

{
  "high_level_description": "A medium-shot photograph of a barista pouring latte art in a cosy cafe.",
  "style_description": {
    "aesthetics": "warm, calm, editorial",
    "lighting": "soft window light from the left, gentle falloff",
    "photo": "50mm, f/2, shallow depth of field",
    "medium": "photograph"
  },
  "compositional_deconstruction": {
    "background": "A wooden counter with a polished espresso machine behind it.",
    "elements": [
      {
        "type": "obj",
        "desc": "A ceramic cup held in both hands, latte art holding a clean rosetta."
      }
    ]
  }
}

high_level_description

One or two sentences summarising the whole image. Strongly recommended, not required — it is the sentence you would keep if you could keep only one.

style_description

Optional as a block, strict inside. It carries exactly one of photo or art_style (illustration, painting, 3D render, graphic design), never both. When the block is present, aesthetics, lighting and medium are required too, and color_palette is the only field you may drop. medium takes values such as photograph, 3d_render and graphic_design.

compositional_deconstruction

Required. It holds background first and elements second, both mandatory. Every element is either an object ("obj") or a text element ("text"), the only two types the documentation defines. Objects carry a desc; text elements add a text string with the literal characters to render.

Bounding boxes and colour palettes

A bounding box is four integers, [y_min, x_min, y_max, x_max], on a normalised 0–1000 grid with the origin at the top-left corner. [0, 0, 500, 1000] claims the top half of the frame; [250, 250, 750, 750] sits roughly centred. Omit it and the model places the element freely.

{
  "type": "text",
  "bbox": [30, 50, 140, 950],
  "text": "FARMERS MARKET",
  "desc": "Large all-caps sans-serif headline in warm cream, spanning the top of the poster.",
  "color_palette": ["#F5F0E8"]
}

Colours work at two scales: up to 16 uppercase #RRGGBB values for the whole image in style_description.color_palette, and up to 5 per element. Lowercase and shorthand are both rejected. Put the background colour in the palette if the overall tone matters, and include a highlight with a shadow so the lighting has something to work with.

Two worked examples you can paste

Both prompts use only documented fields and follow the key order the model was trained on. The first is a designed poster, every element placed by hand. The second is a photograph where nothing is placed at all.

A code editor window filled with rows of coloured bracket shapes, beside a large poster preview tile

Example 1 — designed poster, placement by hand. Note the art_style key order: aesthetics, lighting, medium, art_style, color_palette.

{
  "high_level_description": "A bold screen-printed poster for a Saturday farmers market, titled Harvest Row, listing the location and opening time.",
  "style_description": {
    "aesthetics": "warm, hand-made, mid-century screen print",
    "lighting": "flat even light, no dramatic shadow",
    "medium": "graphic_design",
    "art_style": "two-colour screen print, visible paper grain, heavy geometric letterforms",
    "color_palette": ["#1B3A2F", "#E9DFC7", "#C4622D", "#F5F0E8"]
  },
  "compositional_deconstruction": {
    "background": "A single sheet of warm off-white cartridge paper with a fine fibre texture.",
    "elements": [
      {
        "type": "text",
        "bbox": [40, 60, 170, 940],
        "text": "HARVEST ROW",
        "desc": "Very large condensed sans-serif capitals in deep green, spanning the top of the sheet."
      },
      {
        "type": "obj",
        "bbox": [200, 120, 720, 880],
        "desc": "A simplified illustration of five market stalls under striped awnings, drawn in flat shapes with no outline."
      },
      {
        "type": "text",
        "bbox": [740, 60, 830, 940],
        "text": "SATURDAY 8AM - 1PM",
        "desc": "Medium spaced capitals in burnt orange, centred below the illustration."
      },
      {
        "type": "text",
        "bbox": [860, 60, 950, 940],
        "text": "OLD MILL YARD",
        "desc": "Small light capitals in the same deep green, near the bottom edge."
      }
    ]
  }
}

Every number earns its place. The headline owns the top 17 percent, so no illustration can crowd it. The stalls run from 200 to 720 vertically, leaving a text band beneath that descenders cannot enter. The lower two text elements sit in separate slices, which stops them colliding when the wording changes.

Example 2 — photograph, placement left to the model. The photo key order applies: aesthetics, lighting, photo, medium, color_palette.

{
  "high_level_description": "A close product photograph of a matte black pour-over coffee set on a dark stone surface.",
  "style_description": {
    "aesthetics": "restrained, premium, low-key",
    "lighting": "single soft light from the upper right, deep falloff into shadow",
    "photo": "85mm, f/2.8, product still life, gentle film grain",
    "medium": "photograph",
    "color_palette": ["#141414", "#2B2B2B", "#8C8377", "#D9D2C5"]
  },
  "compositional_deconstruction": {
    "background": "A dark honed stone surface with a soft vertical shadow behind the set, fading into near black.",
    "elements": [
      {
        "type": "obj",
        "desc": "A matte black ceramic dripper on a matching glass carafe, both centred, with a thin steam wisp above the cone."
      },
      {
        "type": "obj",
        "desc": "A small scattering of roasted coffee beans on the stone in the lower left, softly out of focus."
      }
    ]
  }
}

Dropping the boxes is a deliberate trade: you give up guaranteed position and get a composition with more natural light and depth, because nothing is fighting a hard rectangle.

Why key order is not decoration

The model was trained on captions with a consistent key order, so keeping it improves results, and the pipeline checks. A CaptionVerifier runs on every prompt and warns about unknown keys, missing required keys and out-of-order keys. Inside style_description two orders apply: aesthetics, lighting, photo, medium, color_palette for photos, and aesthetics, lighting, medium, art_style, color_palette for everything else, with color_palette last either way. Elements follow their own order too.

One serialisation detail bites Python users. Dump with separators=(",", ":") and ensure_ascii=False, because the verifier warns when it finds \uXXXX escapes with no literal non-ASCII characters. The Ideogram 4.0 prompt guide has a plain-text prompt to compare against, and the typography page covers lettering.

Where JSON stops paying off

The documented advice is narrower than the enthusiasm around it. Quick exploration and photographic scenes where placement is not critical are both listed as natural-language work. Reach for JSON when a layout has to survive a hundred runs with one word swapped.

Three things the documentation does not settle, and where no third-party figure should be substituted:

  • Element count. No fixed cap on elements per caption. Keep dense typographic layouts to a handful, because placement reliability is the limit, not the schema.
  • Overlapping boxes. No z-order rule is stated for elements whose boxes overlap.
  • Quality gain. Key order is said to improve quality, with no measured figure.

Two practical facts close the loop. The API takes json_prompt as an object, disables magic prompt whenever it is supplied, and treats it as mutually exclusive with text_prompt, as the endpoint reference records. Inside the product, using JSON turns Magic Prompt off automatically.

Frequently asked questions

Do I have to write the JSON myself? No. Magic Prompt expands plain text into a structured caption and is the recommended starting point for casual work. Write JSON by hand when layout, palette and text position have to be reproducible.

Can a caption use both photo and art_style? No. Exactly one, and the choice changes the required key order in that block.

What does a missing bbox do? It hands placement back to the model. The element still renders; it simply is not pinned to a rectangle, which is often better for photographic work.

Are there element types beyond "obj" and "text"? Not in the documentation. Pages listing types such as logo or panel describe their own wrapper. The getting-started guide covers the browser workflow if you would rather see the model run first.

Write the three top-level fields, keep the key order for the style block you chose, add boxes only where position has to hold.