API

Template to Image

Generate an image (PNG, JPG, or WebP) from a template with dynamic data. Use predefined templates from the cloudlayer.io gallery or provide your own custom HTML template with Handlebars syntax.

Endpoint

POST /v1/template/image

All requests are processed synchronously. The response body is the raw image file.

POST /v2/template/image

Requests default to asynchronous processing (async: true, storage: true). Add "async": false to receive the raw image directly. See Sync vs. Async for details.

Supports two content types:

Content TypeUse Case
application/jsonInline templates (base64-encoded) or predefined template IDs with JSON data.
multipart/form-dataUpload template files directly alongside JSON data.

Quick Start: Predefined Template

cURL

curl -X POST "https://api.cloudlayer.io/v1/template/image" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "social-card",
    "data": {
      "title": "Introducing Our New API",
      "subtitle": "Generate images programmatically",
      "author": "cloudlayer.io"
    },
    "imageType": "png"
  }' \
  --output social-card.png

JavaScript (fetch)

const response = await fetch("https://api.cloudlayer.io/v1/template/image", {
  method: "POST",
  headers: {
    "X-API-Key": "your-api-key-here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    templateId: "social-card",
    data: {
      title: "Introducing Our New API",
      subtitle: "Generate images programmatically",
      author: "cloudlayer.io",
    },
    imageType: "png",
  }),
});

const image = await response.arrayBuffer();

Python (requests)

import requests

response = requests.post(
    "https://api.cloudlayer.io/v1/template/image",
    headers={
        "X-API-Key": "your-api-key-here",
        "Content-Type": "application/json",
    },
    json={
        "templateId": "social-card",
        "data": {
            "title": "Introducing Our New API",
            "subtitle": "Generate images programmatically",
            "author": "cloudlayer.io",
        },
        "imageType": "png",
    },
)

with open("social-card.png", "wb") as f:
    f.write(response.content)

cURL

curl -X POST "https://api.cloudlayer.io/v2/template/image" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "social-card",
    "data": {
      "title": "Introducing Our New API",
      "subtitle": "Generate images programmatically",
      "author": "cloudlayer.io"
    },
    "imageType": "png",
    "async": false
  }' \
  --output social-card.png

JavaScript (fetch)

const response = await fetch("https://api.cloudlayer.io/v2/template/image", {
  method: "POST",
  headers: {
    "X-API-Key": "your-api-key-here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    templateId: "social-card",
    data: {
      title: "Introducing Our New API",
      subtitle: "Generate images programmatically",
      author: "cloudlayer.io",
    },
    imageType: "png",
    async: false,
  }),
});

const image = await response.arrayBuffer();

Python (requests)

import requests

response = requests.post(
    "https://api.cloudlayer.io/v2/template/image",
    headers={
        "X-API-Key": "your-api-key-here",
        "Content-Type": "application/json",
    },
    json={
        "templateId": "social-card",
        "data": {
            "title": "Introducing Our New API",
            "subtitle": "Generate images programmatically",
            "author": "cloudlayer.io",
        },
        "imageType": "png",
        "async": False,
    },
)

with open("social-card.png", "wb") as f:
    f.write(response.content)

Tip: Omit "async": false to use the default async mode. The API will return a JSON response with the job ID immediately, and the generated image will be stored and accessible via the Assets endpoint.


Quick Start: Custom Template

cURL

TEMPLATE=$(cat <<'HTML'
<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0; padding: 0;
      width: 1200px; height: 630px;
      display: flex; align-items: center; justify-content: center;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      font-family: Arial, sans-serif;
      color: white;
    }
    .card { text-align: center; padding: 60px; }
    h1 { font-size: 52px; margin-bottom: 12px; }
    p { font-size: 24px; opacity: 0.9; }
  </style>
</head>
<body>
  <div class="card">
    <h1>{{title}}</h1>
    <p>{{description}}</p>
  </div>
</body>
</html>
HTML
)

TEMPLATE_BASE64=$(echo "$TEMPLATE" | base64 -w 0)

curl -X POST "https://api.cloudlayer.io/v2/template/image" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d "{
    \"template\": \"$TEMPLATE_BASE64\",
    \"data\": {
      \"title\": \"Hello World\",
      \"description\": \"Generated with cloudlayer.io\"
    },
    \"imageType\": \"png\"
  }" \
  --output card.png

JavaScript (fetch)

const template = `<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0; padding: 0;
      width: 1200px; height: 630px;
      display: flex; align-items: center; justify-content: center;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      font-family: Arial, sans-serif;
      color: white;
    }
    .card { text-align: center; padding: 60px; }
    h1 { font-size: 52px; margin-bottom: 12px; }
    p { font-size: 24px; opacity: 0.9; }
  </style>
</head>
<body>
  <div class="card">
    <h1>{{title}}</h1>
    <p>{{description}}</p>
  </div>
</body>
</html>`;

const response = await fetch("https://api.cloudlayer.io/v2/template/image", {
  method: "POST",
  headers: {
    "X-API-Key": "your-api-key-here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    template: btoa(template),
    data: {
      title: "Hello World",
      description: "Generated with cloudlayer.io",
    },
    imageType: "png",
  }),
});

const image = await response.arrayBuffer();

Python (requests)

import base64
import requests

template = """<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0; padding: 0;
      width: 1200px; height: 630px;
      display: flex; align-items: center; justify-content: center;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      font-family: Arial, sans-serif;
      color: white;
    }
    .card { text-align: center; padding: 60px; }
    h1 { font-size: 52px; margin-bottom: 12px; }
    p { font-size: 24px; opacity: 0.9; }
  </style>
</head>
<body>
  <div class="card">
    <h1>{{title}}</h1>
    <p>{{description}}</p>
  </div>
</body>
</html>"""

response = requests.post(
    "https://api.cloudlayer.io/v2/template/image",
    headers={
        "X-API-Key": "your-api-key-here",
        "Content-Type": "application/json",
    },
    json={
        "template": base64.b64encode(template.encode()).decode(),
        "data": {
            "title": "Hello World",
            "description": "Generated with cloudlayer.io",
        },
        "imageType": "png",
    },
)

with open("card.png", "wb") as f:
    f.write(response.content)

Parameters

Template Parameters

You must provide either templateId or template, but not both.

ParameterTypeRequiredDefaultDescription
templateIdstringConditionalID of a predefined template from the cloudlayer.io template gallery.
templatestringConditionalCustom HTML template as a base64-encoded string. Supports Handlebars syntax.
dataobjectNo{}Key-value pairs of data to inject into the template. Keys map to Handlebars placeholders (e.g., {{name}}).

Image Parameters

ParameterTypeDefaultDescription
imageTypestring"png"Output format: "png", "jpg", or "webp".
transparentbooleanfalseRender with a transparent background. Only works with "png" and "webp". The template must not set a background color on <html> or <body>.
trimbooleanfalseTrim whitespace from all edges of the resulting image.

Base Parameters

ParameterTypeDefaultDescription
autoScrollbooleanfalseScroll the page to trigger lazy-loaded content before capture.
delaynumber0Wait time in milliseconds after the page loads before capturing.
filenamestringSet the Content-Disposition filename on the response.
heightstringSet the capture area height with CSS units.
widthstringSet the capture area width with CSS units.
inlinebooleanfalseDisplay the image inline in the browser instead of downloading.
landscapebooleanfalseRender in landscape orientation.
preferCSSPageSizebooleanfalseUse CSS @page size for dimensions.
projectIdstringAssociate with a project for dashboard organization.
scalenumber1Page rendering scale (0.1 to 2).
timeoutnumber30000Maximum page load time in milliseconds.
timeZonestringBrowser timezone (IANA name).
viewPortobjectBrowser viewport configuration. See HTML to PDF — viewPort.
waitForSelectorobjectWait for a CSS selector before capturing. See HTML to PDF — waitForSelector.
waitUntilstring"networkidle2"Navigation completion strategy.

Use Cases

Open Graph (OG) Images

Generate dynamic social sharing images for blog posts, product pages, and marketing campaigns:

const response = await fetch("https://api.cloudlayer.io/v2/template/image", {
  method: "POST",
  headers: {
    "X-API-Key": "your-api-key-here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    templateId: "og-image-blog",
    data: {
      title: "10 Tips for Better API Design",
      author: "Jane Smith",
      authorAvatar: "https://example.com/avatars/jane.jpg",
      readTime: "5 min read",
      category: "Engineering",
    },
    imageType: "png",
    viewPort: { width: 1200, height: 630 },
  }),
});

Email Banners

Generate personalized email header images:

{
  "templateId": "email-banner",
  "data": {
    "recipientName": "Jane",
    "promoCode": "SAVE20",
    "expiryDate": "March 31, 2024"
  },
  "imageType": "png",
  "viewPort": {
    "width": 600,
    "height": 200
  }
}

Certificate Generation

Generate certificates with dynamic recipient data:

{
  "templateId": "certificate-completion",
  "data": {
    "recipientName": "Jane Smith",
    "courseName": "Advanced JavaScript",
    "completionDate": "January 15, 2024",
    "instructorName": "John Doe",
    "certificateId": "CERT-2024-0042"
  },
  "imageType": "png",
  "viewPort": {
    "width": 1100,
    "height": 850
  },
  "scale": 2
}

Product Labels and Badges

Generate dynamic product labels:

{
  "template": "...",
  "data": {
    "productName": "Organic Green Tea",
    "weight": "250g",
    "price": "$12.99",
    "barcode": "1234567890"
  },
  "imageType": "png",
  "trim": true,
  "transparent": true
}

Multipart Upload

Upload template files directly instead of base64-encoding:

cURL

curl -X POST "https://api.cloudlayer.io/v2/template/image" \
  -H "X-API-Key: your-api-key-here" \
  -F "template=@./social-card-template.html" \
  -F 'data={"title":"Hello World","description":"Dynamic image generation"}'

Python (requests)

import json
import requests

with open("social-card-template.html", "rb") as f:
    template_file = f.read()

response = requests.post(
    "https://api.cloudlayer.io/v2/template/image",
    headers={"X-API-Key": "your-api-key-here"},
    files={"template": ("template.html", template_file, "text/html")},
    data={
        "data": json.dumps({"title": "Hello World", "description": "Dynamic image generation"}),
    },
)

with open("social-card.png", "wb") as f:
    f.write(response.content)

Tips

  • Fixed dimensions: For consistent image output (e.g., OG images), set explicit dimensions in both the template CSS (width/height on <body>) and the viewPort parameter.
  • Template syntax: Templates use Handlebars syntax. See Template to PDF — Template Syntax for conditionals, loops, and more.
  • High-DPI images: Set scale: 2 or viewPort.deviceScaleFactor: 2 for images that look crisp on retina displays.
  • Transparent images: Use "png" or "webp" with transparent: true. Do not set any background color in your template CSS.
  • Batch generation: To generate many images from the same template with different data, make parallel API calls. Consider using async mode for large batches to avoid timeout issues.