Templates & Personalization
How to render the same composition with different text, images, video, and audio per request using the isDynamic + replacements system.
A "template" in Renderly is a composition where some overlays are marked as variables. At render time you pass a replacements object and the marked overlays swap their content. One template = thousands of personalized outputs.
The two pieces
Personalization rests on two coordinated fields on an overlay:
isDynamic: true— flags the overlay as a variable. Without this, the overlay is static and replacements don't touch it.name: "<key>"— the lookup key that links this overlay to a value inreplacements.
At render time the server walks every overlay; if isDynamic is true, it looks up name in replacements and swaps the appropriate field:
| Overlay type | Field replaced |
|---|---|
text, shape | content |
video, image, sound | src |
There is no {{ variable }} syntax inside content strings. The unit of replacement is a whole overlay, identified by its name.
A complete template
{
"replacements": {
"propertyAddress": "123 Main St",
"agentPhoto": "https://example.com/agent-default.jpg",
"backgroundVideo": "https://example.com/bg-default.mp4"
},
"overlays": [
{
"id": 0, "type": "video",
"name": "backgroundVideo", "isDynamic": true,
"src": "https://example.com/bg-default.mp4",
"from": 0, "durationInFrames": 180,
"row": 0, "top": 0, "left": 0, "width": 1080, "height": 1920,
"styles": { "objectFit": "cover" }
},
{
"id": 1, "type": "text",
"name": "propertyAddress", "isDynamic": true,
"content": "123 Main St",
"from": 10, "durationInFrames": 170,
"row": 1, "top": 200, "left": 60, "width": 960, "height": 200,
"styles": { "fontSize": "4rem", "color": "#FFF", "textAlign": "center" }
},
{
"id": 2, "type": "image",
"name": "agentPhoto", "isDynamic": true,
"src": "https://example.com/agent-default.jpg",
"from": 30, "durationInFrames": 150,
"row": 2, "top": 1500, "left": 390, "width": 300, "height": 300,
"styles": { "borderRadius": "50%", "objectFit": "cover" }
},
{
"id": 3, "type": "text",
"content": "Listed by Renderly Realty",
"from": 0, "durationInFrames": 180,
"row": 3, "top": 1850, "left": 60, "width": 960, "height": 50,
"styles": { "fontSize": "1rem", "color": "#FFF", "textAlign": "center" }
}
],
"durationInFrames": 180, "fps": 30,
"width": 1080, "height": 1920
}In this example, overlays 0–2 are variables; overlay 3 is a static watermark that every rendered video keeps unchanged.
Two important things about the replacements block:
- It lives at the top level of the composition (next to
overlays), not inside any overlay. - The values you put in it are defaults — they're used when the caller doesn't pass an override. This is what makes templates self-rendering for preview purposes.
Rendering a template
You can store a template centrally and call it by ID, or you can pass the whole composition inline and override its variables.
Template stored by Renderly
If the composition lives in our public template gallery, send templateId:
curl -X POST https://renderly.video/api/v1/renders \
-H "Authorization: Bearer rnd_..." \
-H "Content-Type: application/json" \
-d '{
"templateId": "tpl_real_estate_v1",
"replacements": {
"propertyAddress": "456 Ocean Drive",
"agentPhoto": "https://your-cdn.example.com/agents/jane.jpg",
"backgroundVideo": "https://your-cdn.example.com/listings/456-ocean.mp4"
}
}'The server loads tpl_real_estate_v1's composition, applies your replacements, and queues the render.
Your own project
If the composition is a project you built in the editor, send projectId instead. Same payload shape — replacements still match by overlay name:
curl -X POST https://renderly.video/api/v1/renders \
-H "Authorization: Bearer rnd_..." \
-H "Content-Type: application/json" \
-d '{
"projectId": "proj_my_listing_template",
"replacements": {
"propertyAddress": "456 Ocean Drive",
"agentPhoto": "https://your-cdn.example.com/agents/jane.jpg"
}
}'See Rendering — three modes for the full picture.
Resolution / duration overrides
Both templateId and projectId calls accept top-level overrides:
{
"templateId": "tpl_real_estate_v1",
"replacements": { /* ... */ },
"width": 1080,
"height": 1080,
"fps": 30,
"durationInFrames": 300
}Use this to render a 9:16 template at 1:1 for Instagram without forking the template, or to crop its length down.
Discovering a template's variables
Two ways:
- Public templates —
GET /templatesreturns every public template with itsvariables[]array. Each entry hasname,defaultValue, andtype. - Your own project — open it in the editor and look at the Variables panel, which lists every overlay flagged
isDynamic.
Flat-key shortcut for no-code platforms
Tools like Make, Zapier, or Pipedream often can't easily nest a replacements object inside JSON. To support them, Renderly treats any unknown top-level key as a replacement:
{
"templateId": "tpl_real_estate_v1",
"propertyAddress": "456 Ocean Drive",
"agentPhoto": "https://your-cdn.example.com/agents/jane.jpg"
}Internally these get merged into replacements. If a key appears both flat and inside replacements, the explicit replacements value wins.
Patterns for keeping templates clean
- Pick stable names —
headline,backgroundVideo,ctaText. These are user-facing keys. - Always include defaults — store sensible default values in the
replacementsobject so the template renders standalone (great for previews). - Lock down static elements — leave
isDynamicunset on watermarks, logos, and branded chrome you don't want callers overriding. - Group related variables — when one logical thing needs two fields (e.g. an avatar URL and a name caption), use related names like
agentPhoto/agentNameso consumers can spot the pairing.
Where to next
- Overlays reference — every overlay type and its fields
- Rendering — modes, polling, credit cost
- API reference: POST /renders — the full endpoint spec