Integration Examples

Auth, basic usage, OG images, invoices, certificates — ready to copy in every language.

โฌก
Node.js
Works with fetch (Node 18+), axios, and any HTTP client
Add the API key header
Every request requires an X-API-Key header.
auth.js
const res = await fetch('https://renderpix.dev/v1/render', {
  method: 'POST',
  headers: {
    'X-API-Key': 'rpx_your_api_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ html: '<h1>Hello</h1>', width: 1200, height: 630 }),
});
Render HTML to PNG
POST any HTML string, receive a PNG binary. Works with fetch (Node 18+) or axios.
render-fetch.js
const fs = require('fs');

async function renderHtml(html, outputFile = 'output.png') {
  const res = await fetch('https://renderpix.dev/v1/render', {
    method: 'POST',
    headers: {
      'X-API-Key': 'rpx_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ html, width: 1200, height: 630, format: 'png' }),
  });

  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(`RenderPix error ${res.status}: ${err.message || res.statusText}`);
  }

  const buffer = Buffer.from(await res.arrayBuffer());
  fs.writeFileSync(outputFile, buffer);
}

renderHtml('<h1 style="font-family:sans-serif">Hello, RenderPix!</h1>');
render-axios.js
const axios = require('axios');
const fs = require('fs');

const response = await axios.post(
  'https://renderpix.dev/v1/render',
  { html: '<h1>Hello</h1>', width: 1200, height: 630, format: 'png' },
  {
    headers: { 'X-API-Key': 'rpx_your_api_key' },
    responseType: 'arraybuffer',
  }
);

fs.writeFileSync('output.png', response.data);
OG image generator
Generate a 1200ร—630 social card from title, description, and domain.
og-image.js
const fs = require('fs');

async function generateOgImage({ title, description, domain, outputFile = 'og.png' }) {
  const html = `<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
  * { margin:0; padding:0; box-sizing:border-box; }
  body { width:1200px; height:630px; overflow:hidden; padding:80px;
    font-family:-apple-system,sans-serif;
    background:linear-gradient(135deg,#0f172a,#1e293b);
    display:flex; align-items:center; }
  .card { display:flex; flex-direction:column; gap:24px; width:100%; }
  .domain { font-size:20px; color:#38bdf8; text-transform:uppercase; letter-spacing:2px; }
  h1 { font-size:72px; font-weight:800; color:#f1f5f9; line-height:1.1; }
  p  { font-size:28px; color:#94a3b8; }
</style></head>
<body><div class="card">
  <div class="domain">${domain}</div>
  <h1>${title}</h1>
  <p>${description}</p>
</div></body></html>`;

  const res = await fetch('https://renderpix.dev/v1/render', {
    method: 'POST',
    headers: { 'X-API-Key': 'rpx_your_api_key', 'Content-Type': 'application/json' },
    body: JSON.stringify({ html, width: 1200, height: 630, format: 'png' }),
  });

  if (!res.ok) throw new Error(`Render failed (${res.status})`);
  fs.writeFileSync(outputFile, Buffer.from(await res.arrayBuffer()));
  return outputFile;
}

generateOgImage({
  title: 'Build Faster with RenderPix',
  description: 'HTML to image in one API call. No puppeteer required.',
  domain: 'renderpix.dev',
}).then(f => console.log('Saved:', f));
Handle API errors gracefully
error-handling.js
async function renderSafe(html) {
  let res;
  try {
    res = await fetch('https://renderpix.dev/v1/render', {
      method: 'POST',
      headers: { 'X-API-Key': 'rpx_your_api_key', 'Content-Type': 'application/json' },
      body: JSON.stringify({ html, width: 1200, height: 630 }),
    });
  } catch (networkErr) {
    console.error('Network error:', networkErr.message);
    return null;
  }

  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    switch (res.status) {
      case 401: throw new Error('Invalid API key');
      case 429: throw new Error('Rate limit exceeded');
      case 422: throw new Error(`Invalid request: ${body.message}`);
      default:  throw new Error(`Render failed (${res.status}): ${body.message}`);
    }
  }

  return Buffer.from(await res.arrayBuffer());
}
๐Ÿ
Python
Uses the requests library โ€” works with Django, Flask, FastAPI
Add the API key header
auth.py
import requests

response = requests.post(
    'https://renderpix.dev/v1/render',
    headers={'X-API-Key': 'rpx_your_api_key'},
    json={'html': '<h1>Hello</h1>', 'width': 1200, 'height': 630},
)
Render HTML to PNG
render.py
import requests

def render_html(html: str, output_file: str = 'output.png') -> None:
    response = requests.post(
        'https://renderpix.dev/v1/render',
        headers={'X-API-Key': 'rpx_your_api_key'},
        json={'html': html, 'width': 1200, 'height': 630, 'format': 'png'},
    )
    response.raise_for_status()

    with open(output_file, 'wb') as f:
        f.write(response.content)

render_html('<h1 style="font-family:sans-serif">Hello, RenderPix!</h1>')
OG image generator
og_image.py
import requests

def generate_og_image(title: str, description: str, domain: str, output_file: str = 'og.png') -> str:
    html = f"""<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
  * {{ margin:0; padding:0; box-sizing:border-box; }}
  body {{ width:1200px; height:630px; padding:80px;
    font-family:-apple-system,sans-serif;
    background:linear-gradient(135deg,#0f172a,#1e293b);
    display:flex; align-items:center; }}
  .card {{ display:flex; flex-direction:column; gap:24px; }}
  .domain {{ font-size:20px; color:#38bdf8; text-transform:uppercase; }}
  h1 {{ font-size:72px; font-weight:800; color:#f1f5f9; line-height:1.1; }}
  p  {{ font-size:28px; color:#94a3b8; }}
</style></head>
<body><div class="card">
  <div class="domain">{domain}</div>
  <h1>{title}</h1><p>{description}</p>
</div></body></html>"""

    response = requests.post(
        'https://renderpix.dev/v1/render',
        headers={'X-API-Key': 'rpx_your_api_key'},
        json={'html': html, 'width': 1200, 'height': 630, 'format': 'png'},
    )
    response.raise_for_status()

    with open(output_file, 'wb') as f:
        f.write(response.content)
    return output_file

file = generate_og_image('Build Faster with RenderPix', 'HTML to image in one API call.', 'renderpix.dev')
print(f'OG image saved: {file}')
Handle API errors gracefully
error_handling.py
import requests
from requests.exceptions import ConnectionError, Timeout

def render_safe(html: str) -> bytes | None:
    try:
        response = requests.post(
            'https://renderpix.dev/v1/render',
            headers={'X-API-Key': 'rpx_your_api_key'},
            json={'html': html, 'width': 1200, 'height': 630},
            timeout=30,
        )
    except (ConnectionError, Timeout) as e:
        print(f'Network error: {e}')
        return None

    if response.status_code == 401:
        raise ValueError('Invalid API key')
    if response.status_code == 429:
        raise RuntimeError('Rate limit exceeded')
    if response.status_code == 422:
        raise ValueError(f"Invalid request: {response.json().get('message')}")

    response.raise_for_status()
    return response.content
๐Ÿ˜
PHP
Uses the built-in cURL extension โ€” works with Laravel, Symfony, WordPress
Add the API key header
auth.php
<?php
$ch = curl_init('https://renderpix.dev/v1/render');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: rpx_your_api_key',
    'Content-Type: application/json',
]);
Render HTML to PNG
render.php
<?php

function renderHtml(string $html, string $outputFile = 'output.png'): void
{
    $payload = json_encode(['html' => $html, 'width' => 1200, 'height' => 630, 'format' => 'png']);

    $ch = curl_init('https://renderpix.dev/v1/render');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $payload,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_HTTPHEADER     => [
            'X-API-Key: rpx_your_api_key',
            'Content-Type: application/json',
        ],
    ]);

    $body   = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($status !== 200) {
        $error = json_decode($body, true);
        throw new RuntimeException("RenderPix error {$status}: " . ($error['message'] ?? 'unknown'));
    }

    file_put_contents($outputFile, $body);
}

renderHtml('<h1 style="font-family:sans-serif">Hello, RenderPix!</h1>');
OG image generator
og_image.php
<?php

function generateOgImage(string $title, string $description, string $domain): string
{
    $html = "<!DOCTYPE html><html><head><meta charset='UTF-8'>"
        . "<style>*{margin:0;padding:0;box-sizing:border-box}"
        . "body{width:1200px;height:630px;padding:80px;font-family:-apple-system,sans-serif;"
        . "background:linear-gradient(135deg,#0f172a,#1e293b);display:flex;align-items:center}"
        . ".card{display:flex;flex-direction:column;gap:24px}"
        . ".domain{font-size:20px;color:#38bdf8;text-transform:uppercase}"
        . "h1{font-size:72px;font-weight:800;color:#f1f5f9;line-height:1.1}"
        . "p{font-size:28px;color:#94a3b8}</style></head>"
        . "<body><div class='card'>"
        . "<div class='domain'>{$domain}</div>"
        . "<h1>{$title}</h1><p>{$description}</p>"
        . "</div></body></html>";

    $ch = curl_init('https://renderpix.dev/v1/render');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode(['html' => $html, 'width' => 1200, 'height' => 630]),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_HTTPHEADER     => ['X-API-Key: rpx_your_api_key', 'Content-Type: application/json'],
    ]);

    $body   = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($status !== 200) throw new RuntimeException("Render failed ({$status})");

    file_put_contents('og.png', $body);
    return 'og.png';
}

echo generateOgImage('Build Faster with RenderPix', 'HTML to image in one API call.', 'renderpix.dev');
Handle API errors gracefully
error_handling.php
<?php

function renderSafe(string $html): ?string
{
    $ch = curl_init('https://renderpix.dev/v1/render');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode(['html' => $html, 'width' => 1200, 'height' => 630]),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_HTTPHEADER     => ['X-API-Key: rpx_your_api_key', 'Content-Type: application/json'],
    ]);

    $body    = curl_exec($ch);
    $status  = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlErr = curl_error($ch);
    curl_close($ch);

    if ($curlErr) { error_log("Network error: {$curlErr}"); return null; }

    $error = json_decode($body, true) ?? [];

    return match ($status) {
        200     => $body,
        401     => throw new RuntimeException('Invalid API key'),
        429     => throw new RuntimeException('Rate limit exceeded'),
        422     => throw new InvalidArgumentException('Invalid request: ' . ($error['message'] ?? '')),
        default => throw new RuntimeException("Render failed ({$status})"),
    };
}
๐Ÿ’Ž
Ruby
Uses the standard library net/http โ€” works with Rails, Sinatra
Add the API key header
auth.rb
require 'net/http'
require 'json'

uri = URI('https://renderpix.dev/v1/render')
req = Net::HTTP::Post.new(uri.path)
req['X-API-Key']    = 'rpx_your_api_key'
req['Content-Type'] = 'application/json'
req.body = JSON.generate(html: '<h1>Hello</h1>', width: 1200, height: 630)
Render HTML to PNG
render.rb
require 'net/http'
require 'json'

def render_html(html, output_file: 'output.png')
  uri  = URI('https://renderpix.dev/v1/render')
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl      = true
  http.read_timeout = 30

  req = Net::HTTP::Post.new(uri.path)
  req['X-API-Key']    = 'rpx_your_api_key'
  req['Content-Type'] = 'application/json'
  req.body = JSON.generate(html: html, width: 1200, height: 630, format: 'png')

  res = http.request(req)

  unless res.code == '200'
    error = JSON.parse(res.body) rescue {}
    raise "RenderPix error #{res.code}: #{error['message'] || res.message}"
  end

  File.binwrite(output_file, res.body)
end

render_html('<h1 style="font-family:sans-serif">Hello, RenderPix!</h1>')
OG image generator
og_image.rb
require 'net/http'
require 'json'

def generate_og_image(title:, description:, domain:, output_file: 'og.png')
  html = <<~HTML
    <!DOCTYPE html><html><head><meta charset="UTF-8">
    <style>
      * { margin:0; padding:0; box-sizing:border-box; }
      body { width:1200px; height:630px; padding:80px;
        font-family:-apple-system,sans-serif;
        background:linear-gradient(135deg,#0f172a,#1e293b);
        display:flex; align-items:center; }
      .card { display:flex; flex-direction:column; gap:24px; }
      .domain { font-size:20px; color:#38bdf8; text-transform:uppercase; }
      h1 { font-size:72px; font-weight:800; color:#f1f5f9; line-height:1.1; }
      p  { font-size:28px; color:#94a3b8; }
    </style></head>
    <body><div class="card">
      <div class="domain">#{domain}</div>
      <h1>#{title}</h1><p>#{description}</p>
    </div></body></html>
  HTML

  uri  = URI('https://renderpix.dev/v1/render')
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  req = Net::HTTP::Post.new(uri.path)
  req['X-API-Key']    = 'rpx_your_api_key'
  req['Content-Type'] = 'application/json'
  req.body = JSON.generate(html: html, width: 1200, height: 630, format: 'png')

  res = http.request(req)
  raise "Render failed (#{res.code})" unless res.code == '200'

  File.binwrite(output_file, res.body)
  output_file
end

file = generate_og_image(title: 'Build Faster', description: 'One API call.', domain: 'renderpix.dev')
puts "Saved: #{file}"
Handle API errors gracefully
error_handling.rb
def render_safe(html)
  uri  = URI('https://renderpix.dev/v1/render')
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl      = true
  http.open_timeout = 10
  http.read_timeout = 30

  req = Net::HTTP::Post.new(uri.path)
  req['X-API-Key']    = 'rpx_your_api_key'
  req['Content-Type'] = 'application/json'
  req.body = JSON.generate(html: html, width: 1200, height: 630)

  begin
    res = http.request(req)
  rescue Net::OpenTimeout, Net::ReadTimeout => e
    warn "Timeout: #{e.message}"; return nil
  rescue SocketError => e
    warn "Network error: #{e.message}"; return nil
  end

  error = JSON.parse(res.body) rescue {}

  case res.code
  when '200' then res.body
  when '401' then raise 'Invalid API key'
  when '429' then raise 'Rate limit exceeded'
  when '422' then raise "Invalid request: #{error['message']}"
  else raise "Render failed (#{res.code})"
  end
end
โšก
cURL
Shell scripts, CI/CD pipelines, GitHub Actions
Add the API key header
auth.sh
curl -X POST https://renderpix.dev/v1/render \
  -H "X-API-Key: rpx_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1>Hello</h1>","width":1200,"height":630}'
Render HTML to PNG
render.sh
curl -X POST https://renderpix.dev/v1/render \
  -H "X-API-Key: rpx_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1 style=\"font-family:sans-serif\">Hello, RenderPix!</h1>","width":1200,"height":630,"format":"png"}' \
  -o output.png
OG image generator
og-image.sh
#!/bin/bash
API_KEY="rpx_your_api_key"

HTML='<!DOCTYPE html><html><head><meta charset="UTF-8"><style>
* { margin:0; padding:0; box-sizing:border-box; }
body { width:1200px; height:630px; padding:80px; font-family:-apple-system,sans-serif;
  background:linear-gradient(135deg,#0f172a,#1e293b);
  display:flex; align-items:center; }
.card { display:flex; flex-direction:column; gap:24px; }
.domain { font-size:20px; color:#38bdf8; text-transform:uppercase; }
h1 { font-size:72px; font-weight:800; color:#f1f5f9; line-height:1.1; }
p  { font-size:28px; color:#94a3b8; }
</style></head><body>
<div class="card">
  <div class="domain">renderpix.dev</div>
  <h1>Build Faster with RenderPix</h1>
  <p>HTML to image in one API call.</p>
</div></body></html>'

jq -n --arg html "$HTML" '{html:$html,width:1200,height:630,format:"png"}' \
| curl -s -X POST https://renderpix.dev/v1/render \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d @- -o og.png

echo "OG image saved: og.png"
Check status codes in shell
error-handling.sh
#!/bin/bash
API_KEY="rpx_your_api_key"

STATUS=$(curl -s -X POST https://renderpix.dev/v1/render \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1>Hello</h1>","width":1200,"height":630}' \
  -o output.png \
  -w "%{http_code}")

case "$STATUS" in
  200) echo "Success โ€” saved to output.png" ;;
  401) echo "Error: Invalid API key"; exit 1 ;;
  429) echo "Error: Rate limit exceeded"; exit 1 ;;
  422) echo "Error: Invalid request โ€” $(cat output.png)"; exit 1 ;;
  *)   echo "Error: HTTP $STATUS โ€” $(cat output.png)"; exit 1 ;;
esac
๐Ÿ–ผ
OG Images
Generate 1200×630 social cards for blog posts, products, and more
Dynamic OG image from URL params
Express / Next.js pattern: receive title + domain as query params, render, return image with cache headers.
og-route.js
// Express โ€” GET /og?title=My+Post&domain=myblog.com
app.get('/og', async (req, res) => {
  const { title = 'Untitled', domain = '', description = '' } = req.query;

  const html = `<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
  * { margin:0; padding:0; box-sizing:border-box; }
  body { width:1200px; height:630px; padding:80px;
    font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
    background:linear-gradient(135deg,#0f172a 0%,#1e293b 100%);
    display:flex; align-items:center; }
  .card { display:flex; flex-direction:column; gap:20px; width:100%; }
  .domain { font-size:18px; font-weight:600; color:#38bdf8;
            text-transform:uppercase; letter-spacing:3px; }
  h1 { font-size:68px; font-weight:800; color:#f1f5f9;
       line-height:1.05; letter-spacing:-2px; }
  p  { font-size:26px; color:#94a3b8; }
</style></head>
<body><div class="card">
  <div class="domain">${domain}</div>
  <h1>${title}</h1>
  ${description ? `<p>${description}</p>` : ''}
</div></body></html>`;

  const r = await fetch('https://renderpix.dev/v1/render', {
    method: 'POST',
    headers: { 'X-API-Key': process.env.RENDERPIX_API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ html, width: 1200, height: 630, format: 'png' }),
  });

  if (!r.ok) return res.status(500).send('Render failed');

  res.set('Content-Type', 'image/png');
  res.set('Cache-Control', 'public, max-age=86400, stale-while-revalidate=3600');
  r.body.pipe(res);
});
Django view โ€” serve OG image on the fly
views.py
import requests
from django.http import HttpResponse

def og_image(request):
    title  = request.GET.get('title', 'Untitled')
    domain = request.GET.get('domain', '')

    html = f"""<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
  * {{ margin:0; padding:0; box-sizing:border-box; }}
  body {{ width:1200px; height:630px; padding:80px;
    font-family:-apple-system,sans-serif;
    background:linear-gradient(135deg,#0f172a,#1e293b);
    display:flex; align-items:center; }}
  .card {{ display:flex; flex-direction:column; gap:20px; }}
  .domain {{ font-size:18px; font-weight:600; color:#38bdf8; text-transform:uppercase; }}
  h1 {{ font-size:68px; font-weight:800; color:#f1f5f9; line-height:1.05; }}
</style></head>
<body><div class="card">
  <div class="domain">{domain}</div>
  <h1>{title}</h1>
</div></body></html>"""

    r = requests.post(
        'https://renderpix.dev/v1/render',
        headers={{'X-API-Key': settings.RENDERPIX_API_KEY}},
        json={{'html': html, 'width': 1200, 'height': 630}},
        timeout=30,
    )
    r.raise_for_status()
    return HttpResponse(r.content, content_type='image/png',
                        headers={{'Cache-Control': 'public, max-age=86400'}})
One-liner for CI/CD
generate-og.sh
#!/bin/bash
# Run in CI after deploy to refresh the OG image

HTML='<html><body style="margin:0;width:1200px;height:630px;overflow:hidden;
  background:linear-gradient(135deg,#0f172a,#1e293b);
  font-family:-apple-system,sans-serif;display:flex;align-items:center;padding:80px">
  <div style="display:flex;flex-direction:column;gap:16px">
    <div style="font-size:18px;color:#38bdf8;text-transform:uppercase;letter-spacing:3px">myblog.com</div>
    <h1 style="font-size:68px;font-weight:800;color:#f1f5f9;line-height:1.05;letter-spacing:-2px">My Latest Post</h1>
    <p style="font-size:26px;color:#94a3b8">A short description goes here.</p>
  </div>
</body></html>'

jq -n --arg html "$HTML" '{html:$html,width:1200,height:630,format:"png"}' \
| curl -s -X POST https://renderpix.dev/v1/render \
  -H "X-API-Key: $RENDERPIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- -o public/og.png

echo "OG image saved: public/og.png"
๐Ÿ“„
Invoices
Generate pixel-perfect invoice images from HTML templates โ€” ready for PDF conversion or email
Invoice image from order data
Pass order data into an HTML template and render it as a PNG. Width 900px works well for A4-ratio invoices.
generate-invoice.js
const fs = require('fs');

async function generateInvoice({ invoiceNo, date, customer, items, total }) {
  const rows = items.map(i => `
    <tr>
      <td>${i.description}</td>
      <td style="text-align:right">${i.qty}</td>
      <td style="text-align:right">$${i.unit.toFixed(2)}</td>
      <td style="text-align:right">$${(i.qty * i.unit).toFixed(2)}</td>
    </tr>`).join('');

  const html = `<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
  * { margin:0; padding:0; box-sizing:border-box; }
  body { width:900px; font-family:-apple-system,'Segoe UI',sans-serif;
    background:#fff; padding:60px; color:#1e293b; }
  .header { display:flex; justify-content:space-between; align-items:flex-start;
    margin-bottom:48px; padding-bottom:24px; border-bottom:2px solid #e2e8f0; }
  .brand { font-size:28px; font-weight:800; color:#0f172a; }
  .brand span { color:#22d3ee; }
  .meta { text-align:right; font-size:13px; color:#64748b; line-height:1.8; }
  .meta strong { color:#0f172a; font-size:15px; }
  table { width:100%; border-collapse:collapse; font-size:14px; }
  th { padding:10px 12px; background:#f8fafc; text-align:left; font-weight:600;
    font-size:12px; text-transform:uppercase; letter-spacing:0.5px; color:#64748b; }
  th:not(:first-child) { text-align:right; }
  td { padding:12px; border-bottom:1px solid #f1f5f9; }
  .total-row td { font-size:16px; font-weight:700; border-bottom:none; padding-top:20px; }
</style></head>
<body>
  <div class="header">
    <div class="brand">My<span>Company</span></div>
    <div class="meta">
      <strong>Invoice ${invoiceNo}</strong><br>
      Date: ${date}<br>Bill to: ${customer}
    </div>
  </div>
  <table>
    <thead><tr>
      <th>Description</th><th>Qty</th><th>Unit price</th><th>Amount</th>
    </tr></thead>
    <tbody>${rows}</tbody>
    <tfoot><tr class="total-row">
      <td colspan="3" style="text-align:right">Total</td>
      <td style="text-align:right">$${total.toFixed(2)}</td>
    </tr></tfoot>
  </table>
</body></html>`;

  const res = await fetch('https://renderpix.dev/v1/render', {
    method: 'POST',
    headers: { 'X-API-Key': process.env.RENDERPIX_API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ html, width: 900, height: 700, format: 'png' }),
  });

  if (!res.ok) throw new Error(`Render failed (${res.status})`);
  const buffer = Buffer.from(await res.arrayBuffer());
  fs.writeFileSync(`invoice-${invoiceNo}.png`, buffer);
  return `invoice-${invoiceNo}.png`;
}

generateInvoice({
  invoiceNo: 'INV-0042',
  date: 'April 17, 2026',
  customer: 'Acme Corp',
  items: [
    { description: 'Pro Plan (April)', qty: 1, unit: 29 },
    { description: 'Extra renders',    qty: 2, unit: 9  },
  ],
  total: 47,
}).then(f => console.log('Invoice saved:', f));
Batch invoice generation
batch_invoices.py
import requests

def render_invoice(invoice_no: str, customer: str, amount: float) -> bytes:
    html = f"""<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
  * {{ margin:0; padding:0; box-sizing:border-box; }}
  body {{ width:900px; font-family:-apple-system,sans-serif;
    background:#fff; padding:60px; color:#1e293b; }}
  .header {{ display:flex; justify-content:space-between;
    margin-bottom:48px; padding-bottom:24px; border-bottom:2px solid #e2e8f0; }}
  .brand {{ font-size:28px; font-weight:800; }}
  .brand span {{ color:#22d3ee; }}
  .info {{ text-align:right; font-size:14px; color:#64748b; line-height:1.8; }}
  .amount {{ font-size:48px; font-weight:800; color:#0f172a; margin-top:40px; }}
  .label {{ font-size:13px; color:#94a3b8; text-transform:uppercase; letter-spacing:1px; }}
</style></head>
<body>
  <div class="header">
    <div class="brand">My<span>Company</span></div>
    <div class="info">Invoice {invoice_no}<br>Bill to: {customer}</div>
  </div>
  <div class="label">Amount due</div>
  <div class="amount">${amount:,.2f}</div>
</body></html>"""

    r = requests.post(
        'https://renderpix.dev/v1/render',
        headers={'X-API-Key': 'rpx_your_api_key'},
        json={'html': html, 'width': 900, 'height': 400, 'format': 'png'},
        timeout=30,
    )
    r.raise_for_status()
    return r.content

# Batch render
orders = [
    ('INV-001', 'Alice Corp',   129.00),
    ('INV-002', 'Bob Ltd',       47.50),
    ('INV-003', 'Carol Inc',    299.99),
]

for inv_no, customer, amount in orders:
    image = render_invoice(inv_no, customer, amount)
    with open(f'{inv_no}.png', 'wb') as f:
        f.write(image)
    print(f'Saved {inv_no}.png')
๐Ÿ†
Certificates
Generate personalized completion certificates, badges, and awards
Course completion certificate
Generate a unique certificate per user โ€” no image editing tools, no Photoshop templates.
generate-cert.js
const fs = require('fs');

async function generateCertificate({ recipientName, courseName, completionDate, certId }) {
  const html = `<!DOCTYPE html><html><head><meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,700;1,400&family=Inter:wght@400;600&display=swap" rel="stylesheet">
<style>
  * { margin:0; padding:0; box-sizing:border-box; }
  body { width:1200px; height:850px; overflow:hidden;
    background:linear-gradient(135deg,#0f172a 0%,#1e1b4b 100%);
    display:flex; align-items:center; justify-content:center; }
  .cert { width:1040px; border:2px solid rgba(167,139,250,0.4);
    border-radius:24px; padding:72px 80px; text-align:center;
    background:rgba(15,23,42,0.8); }
  .badge { display:inline-block; margin-bottom:32px; padding:6px 20px;
    border-radius:20px; font-family:'Inter',sans-serif; font-size:11px;
    font-weight:600; color:#a78bfa; letter-spacing:2px; text-transform:uppercase;
    border:1px solid rgba(167,139,250,0.3); background:rgba(139,92,246,0.1); }
  .title { font-family:'Playfair Display',serif; font-size:20px; font-style:italic;
    color:#94a3b8; margin-bottom:12px; }
  .name { font-family:'Playfair Display',serif; font-size:64px; font-weight:700;
    color:#f1f5f9; letter-spacing:-1px; margin-bottom:24px; }
  .desc { font-family:'Inter',sans-serif; font-size:16px; color:#64748b; margin-bottom:8px; }
  .course { font-family:'Inter',sans-serif; font-size:22px; font-weight:600;
    color:#c4b5fd; margin-bottom:48px; }
  .footer { display:flex; justify-content:space-between; padding-top:40px;
    border-top:1px solid rgba(255,255,255,0.06);
    font-family:'Inter',sans-serif; font-size:12px; color:#475569; }
</style></head>
<body><div class="cert">
  <div class="badge">✦ Certificate of Completion</div>
  <div class="title">This certifies that</div>
  <div class="name">${recipientName}</div>
  <div class="desc">has successfully completed</div>
  <div class="course">${courseName}</div>
  <div class="footer">
    <span>Course Director</span>
    <span>${completionDate}</span>
    <span>ID: ${certId}</span>
  </div>
</div></body></html>`;

  const res = await fetch('https://renderpix.dev/v1/render', {
    method: 'POST',
    headers: { 'X-API-Key': process.env.RENDERPIX_API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ html, width: 1200, height: 850, format: 'png' }),
  });

  if (!res.ok) throw new Error(`Render failed (${res.status})`);
  const buffer = Buffer.from(await res.arrayBuffer());
  fs.writeFileSync(`cert-${certId}.png`, buffer);
  return `cert-${certId}.png`;
}

generateCertificate({
  recipientName:  'Jane Smith',
  courseName:     'Advanced JavaScript & Node.js',
  completionDate: 'April 17, 2026',
  certId:         'CERT-2026-0142',
}).then(f => console.log('Certificate saved:', f));
Batch certificate generation
batch_certs.py
import requests

def render_certificate(name: str, course: str, date: str, cert_id: str) -> bytes:
    html = f"""<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
  * {{ margin:0; padding:0; box-sizing:border-box; }}
  body {{ width:1200px; height:850px; overflow:hidden;
    font-family:-apple-system,sans-serif;
    background:linear-gradient(135deg,#0f172a,#1e1b4b);
    display:flex; align-items:center; justify-content:center; }}
  .cert {{ width:1040px; border:2px solid rgba(167,139,250,.4);
    border-radius:24px; padding:72px 80px; text-align:center;
    background:rgba(15,23,42,.8); }}
  .badge {{ display:inline-block; margin-bottom:32px; padding:6px 20px;
    border-radius:20px; font-size:11px; font-weight:600; color:#a78bfa;
    letter-spacing:2px; text-transform:uppercase;
    border:1px solid rgba(167,139,250,.3); }}
  .label {{ font-size:18px; color:#94a3b8; margin-bottom:12px; }}
  .name  {{ font-size:60px; font-weight:700; color:#f1f5f9;
    letter-spacing:-1px; margin-bottom:24px; }}
  .course {{ font-size:22px; font-weight:600; color:#c4b5fd; margin-bottom:48px; }}
  .meta {{ font-size:12px; color:#475569; }}
</style></head>
<body><div class="cert">
  <div class="badge">Certificate of Completion</div>
  <div class="label">This certifies that</div>
  <div class="name">{name}</div>
  <div class="course">{course}</div>
  <div class="meta">{date} · {cert_id}</div>
</div></body></html>"""

    r = requests.post(
        'https://renderpix.dev/v1/render',
        headers={'X-API-Key': 'rpx_your_api_key'},
        json={'html': html, 'width': 1200, 'height': 850, 'format': 'png'},
        timeout=30,
    )
    r.raise_for_status()
    return r.content

# Batch render for course graduates
graduates = [
    ('Alice Johnson',  'CERT-001'),
    ('Bob Williams',   'CERT-002'),
    ('Carol Martinez', 'CERT-003'),
]

for name, cert_id in graduates:
    image = render_certificate(
        name=name, course='Advanced Python Development',
        date='April 17, 2026', cert_id=cert_id,
    )
    with open(f'{cert_id}.png', 'wb') as f:
        f.write(image)
    print(f'Saved {cert_id}.png')