Template input design decides whether bulk rendering is boring or painful. Plan typed inputs for text, prices, media and optional badges up front, and hundreds of variants validate and render without breaking your layout.
Design the contract before the first render
A template is only as reliable as the inputs it exposes. In JsonCut, a template is a published, version-pinned project with a small typed input contract: you build and approve the design in Studio once, publish it, and from then on only the data moves (see Templates and bulk rendering). That contract is an interface. The spreadsheet column names, the API field names and the validation rules all derive from it — and renaming an input after your team has wired up a feed is a breaking change, exactly like renaming a field in an API.
Good template inputs share three properties: each value has exactly one type, the type matches how the value really changes, and the design survives both the shortest and the longest realistic value. Plan them from your data source before you publish, and bulk rendering stays a data problem instead of becoming a design emergency.
Start from the data, not from the design
Before adding a single variable, open the system that will feed the template — the product feed, the campaign spreadsheet, the CRM export. Whatever changes per row there is a candidate input; everything else should stay fixed in the design. A common first pass looks like this:
| Candidate | Changes per variant? | Input type | Example value |
|---|---|---|---|
| Headline | Yes | string | "Available now" |
| Price | Yes | number | 79.9 |
| Product image | Yes | image | jsoncut-media://… |
| Badge label | Sometimes | string | "Bestseller" |
| Show badge | Sometimes | boolean | true |
| Accent color | Rarely | color | #FF5A1F |
| Logo, fonts, layout | No | — keep fixed | — |
The last row is the important one. Every input you don't create is a value nobody can get wrong. Resist exposing things that only change between campaigns — publish a new template version for those instead. The same logic applies to image and video projects alike; if you are new to the pattern, the dynamic image generation guide covers the workflow from a design-first angle, and personalized video at scale does the same for video.
Give every value the right type
JsonCut templates use typed inputs, and the type is what makes unattended rendering safe: values are validated against the published contract before anything is queued. The supported types are string, number, boolean, color, image, video, audio, sanitized HTML and bounded flat string arrays (docs). Do not guess them — after publishing, the input discovery endpoint returns every field with its type, constraints, accepted MIME types and examples. That response is the reference your data file has to match.
| Type | Use it for | Typical failure when misused |
|---|---|---|
| string | Headlines, names, labels | Unbounded text overflows a fixed box |
| number | Prices, quantities, scores | "€79.90" or "79,90" is not a number |
| boolean | Toggles such as badge on/off | Empty string instead of false — ambiguous |
| color | Accent or background variants | Free-text hex field skips validation |
| image / video / audio | Swappable media | Wrong MIME type, oversized asset, guessed IDs |
| sanitized HTML | Pre-cleaned rich fragments | Pasting unreviewed markup |
| bounded flat string array | Tag lists, up to N lines | Nested structures, unbounded lists |
Design text so the layout stays safe
Text is where templates break most often, because the layout has to absorb every value the data throws at it:
- Decide a maximum length per string input, then design for the longest case. If the German headline can be 40 characters, the box, the font size and the line breaks must work at 40 characters — not at the 20-character English sample you designed with.
- Prefer one input per visual line over a single input that expects manual line breaks. Explicit inputs render predictably; embedded
\nconventions rot quickly. - Test with the extremes, not the average. Render the shortest and the longest realistic value before you publish, not after the first customer complains.
- Localization is data. Different languages, separate columns and inputs — never "shorter text please" as an instruction.
Treat prices as numbers, not decorated strings
A price is a number; the currency is design. Keep the raw value numeric (the API examples render 79.9 directly) and leave the currency symbol, decimals display and thousand separators to the layout as fixed elements, or to a separate, consciously formatted field. Baking "€ 79,90" into one input produces a string that fails number validation the first time someone exports a feed with dot decimals. Decide rounding behavior once, in the design — not per row.
Reference media, never embed it
Media inputs point to uploaded assets, they do not carry file bytes in the data row. Upload the reusable images, clips, audio and fonts first, then reference them — the documented pattern is a stable jsoncut-media:// reference in the values (see the quickstart). Three practical rules:
- Read the accepted MIME types from the published input contract instead of assuming them.
- Test with your largest realistic asset, not a convenient 200-pixel sample — the day a 4K product photo enters the feed is the day you want to learn about limits.
- Decide the aspect-ratio strategy (fit, crop, focal point) in the design, so odd-shaped uploads degrade gracefully instead of breaking the composition.
Optional content is a boolean
"Sometimes we show a badge" is a boolean, not an empty string. Model it as showBadge: true/false and let the renderer toggle the layer; pair it with a short badgeLabel string that carries its own maximum length. Conventions like "empty column means hide the badge" feel clever in a spreadsheet and fail silently at scale: they pass validation, they skew your per-variant QA, and nobody can tell a missing value from an intentional one. If a piece of content has a fallback (a default image, a standard label), make that explicit in the design instead of encoding it in empty cells.
Keep the contract stable after publishing
Templates are version-pinned, and every bulk batch is pinned to one immutable template version (docs). That is a feature: the approved design cannot shift under a running campaign. It also means the input contract deserves API-grade care:
- Add, don't rename. New optional inputs are safe; renamed IDs break every CSV header and integration that references them.
- Correct invalid rows as a new batch, pinned to the same explicit template version, so the approved design stays unchanged.
- Remember that CSV headers must match the template input IDs exactly — another reason to settle IDs before the spreadsheet goes out.
Prepare the bulk file while you design
The data file and the input contract are designed together, not sequentially. JSON and CSV batches are both validated row by row before queueing, with a cap of 500 rows per batch (docs, retrieved 2026-10-07) — larger runs become multiple batches. Invalid rows are reported with their index and a safe error without preventing valid rows from rendering, and row-level idempotency keys (the documented examples use keys like sku-1042-de) make retries safe: the same key never produces a duplicate output.
For CSV, the quoting rules that matter are standardized in RFC 4180:
| Situation | Rule | Example |
|---|---|---|
| Field contains a comma | Enclose the field in double quotes | "Available now, in black" |
| Field contains a double quote | Enclose it and double the quote | "Say ""new""" |
| Header row | First line, same number of fields as every record | headline,price,showBadge |
| Last record | Trailing line break optional | — |
A worked input plan: the product launch card
Here is a complete contract for a simple launch visual — five inputs, each with a type, a constraint and a test value. This is the artifact to review before publishing, ideally next to a render of both the shortest and the longest data row:
| Input ID | Type | Required | Constraint | Example |
|---|---|---|---|---|
headline | string | yes | ≤ 32 characters | Available now |
price | number | yes | 0–999999, up to 2 decimals | 79.9 |
productImage | image | yes | accepted MIME types per contract | jsoncut-media://… |
showBadge | boolean | no, default false | — | true |
badgeLabel | string | no | ≤ 12 characters, rendered only if showBadge | Bestseller |
And the matching CSV file — note the quoted comma and the untouched optional fields:
headline,price,showBadge,badgeLabel,productImage
"Available now, in black",79.9,true,Bestseller,jsoncut-media://media_01J...
Winter edition,59.9,false,,
A contract this small validates in seconds, renders in bulk, and still leaves the visual entirely to the design — which is exactly the division of labor templates are for.
FAQ
How many inputs should a template have? As few as the format needs. Every input adds a validation surface and a column someone has to fill; if a value does not change per variant, it belongs in the design, not in the data.
Can I add inputs after publishing? Yes — prefer adding optional inputs with safe defaults over renaming existing ones. Renaming breaks CSV headers and every integration that references the old IDs; new optional fields do not.
What happens when one row in a bulk batch is invalid? Only that row stops. Valid rows render, invalid rows are reported with their index and a safe error, and you resubmit the corrected rows as a new batch pinned to the same template version.
CSV or JSON for bulk rendering? Both are validated against the same published contract and capped at 500 rows per batch. JSON additionally supports batch-level defaults that rows can override — useful when 90% of a batch shares one value.
Sources
JsonCut documentation, "Typed templates and bulk rendering" — https://jsoncut.com/docs/templates/ (retrieved 2026-10-07)
RFC 4180, "Common Format and MIME Type for Comma-Separated Values (CSV) Files" — https://www.rfc-editor.org/info/rfc4180/ (retrieved 2026-10-07)