DEV Community

Cover image for Stop Hardcoding HTML for Every Image — Use Template Variables Instead
Özgür S.
Özgür S.

Posted on • Originally published at renderpix.dev

Stop Hardcoding HTML for Every Image — Use Template Variables Instead

Most developers generate images like this:

const html = `
  <div style="...">
    <h1>${post.title}</h1>
    <p>${post.author} · ${post.date}</p>
  </div>
`;
Enter fullscreen mode Exit fullscreen mode

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'
  })
});
Enter fullscreen mode Exit fullscreen mode

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 of vars.title
  • {{author}} → value of vars.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.
Enter fullscreen mode Exit fullscreen mode

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)