Most developers generate images like this:
const html = `
<div style="...">
<h1>${post.title}</h1>
<p>${post.author} · ${post.date}</p>
</div>
`;
This works — until it doesn't.
- Special characters break the HTML (
&,<,>in titles) - The template grows and the string becomes harder to maintain
- Reusing the same template across environments gets messy
- No clear separation between design and data
A cleaner approach: template variables
Instead of interpolating values into HTML strings, pass them separately:
const response = await fetch('https://renderpix.dev/v1/render', {
method: 'POST',
headers: {
'X-API-Key': 'rpx_your_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
html: `
<div style="width:1200px;height:630px;background:#0f172a;
display:flex;flex-direction:column;justify-content:center;
padding:80px;font-family:sans-serif">
<div style="color:#22d3ee;font-size:18px">{{domain}}</div>
<div style="color:white;font-size:52px;font-weight:bold;line-height:1.2">
{{title}}
</div>
<div style="color:#94a3b8;font-size:20px;margin-top:24px">
{{author}} · {{date}}
</div>
</div>
`,
vars: {
title: post.title,
author: post.author,
date: post.publishedAt,
domain: 'myblog.com'
},
width: 1200,
height: 630,
format: 'png'
})
});
The HTML template stays clean. Values are injected at render time — no string interpolation, no escaping issues.
How it works
RenderPix does a find-and-replace before rendering the page:
-
{{title}}→ value ofvars.title -
{{author}}→ value ofvars.author - Missing key? The placeholder stays as-is — no errors thrown.
This means you can store your HTML template as a file, an environment variable, or a database field, and just swap the vars object per request.
The real power: combine with batch rendering
Template variables get interesting when you need multiple images at once.
One HTML template + N different vars objects = N unique images, one API request:
const OG_TEMPLATE = `
<div style="width:1200px;height:630px;background:#0f172a;
display:flex;flex-direction:column;justify-content:center;padding:80px">
<div style="color:#22d3ee;font-size:18px;margin-bottom:16px">{{domain}}</div>
<div style="color:white;font-size:52px;font-weight:bold;line-height:1.2">{{title}}</div>
<div style="color:#94a3b8;font-size:20px;margin-top:24px">{{author}} · {{date}}</div>
</div>
`;
const response = await fetch('https://renderpix.dev/v1/batch', {
method: 'POST',
headers: {
'X-API-Key': 'rpx_your_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
items: blogPosts.map(post => ({
html: OG_TEMPLATE,
vars: {
title: post.title,
author: post.author,
date: post.date,
domain: 'myblog.com'
},
width: 1200,
height: 630,
format: 'png'
}))
})
});
const { results } = await response.json();
// results[0].url, results[1].url, ...
// 50 unique OG images. One request.
Without template variables, this would be 50 different HTML strings to maintain. With them, it's one.
Use cases
This pattern works well anywhere you have a fixed design and variable data:
- OG images — one template per blog, dynamic per post
- Certificates — one template per course, dynamic per student
- Invoices — one template per company, dynamic per transaction
- Social cards — one brand template, different content daily
Available on all plans
Template variables work on free, starter, pro, and scale — no upgrade needed to try it.
If you want to test it: renderpix.dev gives you 100 free renders/month, no credit card required.
Top comments (0)