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 Type | Use Case |
|---|---|
application/json | Inline templates (base64-encoded) or predefined template IDs with JSON data. |
multipart/form-data | Upload 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": falseto 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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
templateId | string | Conditional | — | ID of a predefined template from the cloudlayer.io template gallery. |
template | string | Conditional | — | Custom HTML template as a base64-encoded string. Supports Handlebars syntax. |
data | object | No | {} | Key-value pairs of data to inject into the template. Keys map to Handlebars placeholders (e.g., {{name}}). |
Image Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
imageType | string | "png" | Output format: "png", "jpg", or "webp". |
transparent | boolean | false | Render with a transparent background. Only works with "png" and "webp". The template must not set a background color on <html> or <body>. |
trim | boolean | false | Trim whitespace from all edges of the resulting image. |
Base Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
autoScroll | boolean | false | Scroll the page to trigger lazy-loaded content before capture. |
delay | number | 0 | Wait time in milliseconds after the page loads before capturing. |
filename | string | — | Set the Content-Disposition filename on the response. |
height | string | — | Set the capture area height with CSS units. |
width | string | — | Set the capture area width with CSS units. |
inline | boolean | false | Display the image inline in the browser instead of downloading. |
landscape | boolean | false | Render in landscape orientation. |
preferCSSPageSize | boolean | false | Use CSS @page size for dimensions. |
projectId | string | — | Associate with a project for dashboard organization. |
scale | number | 1 | Page rendering scale (0.1 to 2). |
timeout | number | 30000 | Maximum page load time in milliseconds. |
timeZone | string | — | Browser timezone (IANA name). |
viewPort | object | — | Browser viewport configuration. See HTML to PDF — viewPort. |
waitForSelector | object | — | Wait for a CSS selector before capturing. See HTML to PDF — waitForSelector. |
waitUntil | string | "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/heighton<body>) and theviewPortparameter. - Template syntax: Templates use Handlebars syntax. See Template to PDF — Template Syntax for conditionals, loops, and more.
- High-DPI images: Set
scale: 2orviewPort.deviceScaleFactor: 2for images that look crisp on retina displays. - Transparent images: Use
"png"or"webp"withtransparent: 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.