Working with HTML
Converting HTML to PDFs and images gives you complete control over the output. You can use any valid HTML, CSS, JavaScript, Sass, and externally hosted resources like fonts, stylesheets, and images. As long as the base64-encoded payload is under 10MB, cloudlayer.io will accept and convert it.
HTML Encoding
HTML must be base64-encoded before being included in the JSON request body. This avoids issues with special characters (double quotes, angle brackets, etc.) that would otherwise break JSON parsing.
Original HTML:
<html>
<body>
<h1>Hello world!</h1>
</body>
</html>
Base64-encoded:
PGh0bWw+PGJvZHk+PGgxPkhlbGxvIHdvcmxkITwvaDE+PC9ib2R5PjwvaHRtbD4=
JSON payload:
{
"html": "PGh0bWw+PGJvZHk+PGgxPkhlbGxvIHdvcmxkITwvaDE+PC9ib2R5PjwvaHRtbD4="
}
Encoding HTML in Different Languages
JavaScript (Node.js / Browser)
// Browser
const encoded = btoa("<html><body><h1>Hello!</h1></body></html>");
// Node.js / Bun
const encoded = Buffer.from(
"<html><body><h1>Hello!</h1></body></html>"
).toString("base64");
Python
import base64
html = "<html><body><h1>Hello!</h1></body></html>"
encoded = base64.b64encode(html.encode("utf-8")).decode("utf-8")
C#
using System.Text;
var html = "<html><body><h1>Hello!</h1></body></html>";
var encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(html));
Ruby
require "base64"
html = "<html><body><h1>Hello!</h1></body></html>"
encoded = Base64.strict_encode64(html)
PHP
$html = "<html><body><h1>Hello!</h1></body></html>";
$encoded = base64_encode($html);
Go
import "encoding/base64"
html := "<html><body><h1>Hello!</h1></body></html>"
encoded := base64.StdEncoding.EncodeToString([]byte(html))
Java
import java.util.Base64;
String html = "<html><body><h1>Hello!</h1></body></html>";
String encoded = Base64.getEncoder().encodeToString(html.getBytes("UTF-8"));
Tip: If you are using VS Code, the vscode-base64 extension lets you encode and decode HTML interactively while developing.
Basic Examples
HTML to PDF
curl --request POST \
--url https://api.cloudlayer.io/v2/html/pdf \
--header 'Content-Type: application/json' \
--header 'x-api-key: <YOUR-API-KEY>' \
--data '{
"html": "PGh0bWw+PGJvZHk+PGgxPkhlbGxvIHdvcmxkITwvaDE+PC9ib2R5PjwvaHRtbD4=",
"async": false
}'
HTML to Image
curl --request POST \
--url https://api.cloudlayer.io/v2/html/image \
--header 'Content-Type: application/json' \
--header 'x-api-key: <YOUR-API-KEY>' \
--data '{
"html": "PGh0bWw+PGJvZHk+PGgxPkhlbGxvIHdvcmxkITwvaDE+PC9ib2R5PjwvaHRtbD4=",
"async": false
}'
With Viewport Options
{
"html": "PGh0bWw+PGJvZHk+PGgxPkhlbGxvIHdvcmxkITwvaDE+PC9ib2R5PjwvaHRtbD4=",
"viewPort": {
"width": 800,
"height": 600
}
}
Embedding Images
For fully self-contained HTML documents, you can embed images as data URIs instead of referencing external URLs.
Data URI Format
<img src="data:image/{format};base64,{base64-encoded-image-data}" />
Supported formats include png, jpeg, gif, svg+xml, and webp.
Example: Embedded Logo
<html>
<body style="margin: 10px; background-color: #4E279C;">
<div style="display: flex; align-items: center;">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA..."
width="36"
height="36"
/>
<div style="
margin-left: 10px;
font-size: 24px;
color: #fff;
font-weight: 500;
font-family: sans-serif;
">
cloudlayer.io
</div>
</div>
</body>
</html>
How to Generate Data URIs
JavaScript
const fs = require("fs");
const imageBuffer = fs.readFileSync("logo.png");
const base64 = imageBuffer.toString("base64");
const dataUri = `data:image/png;base64,${base64}`;
Python
import base64
with open("logo.png", "rb") as f:
base64_data = base64.b64encode(f.read()).decode("utf-8")
data_uri = f"data:image/png;base64,{base64_data}"
Note: Having a base64-encoded image embedded inside a base64-encoded HTML string is perfectly valid. The outer encoding is for the JSON transport; the inner encoding is part of the HTML specification.
Using External Stylesheets
Since cloudlayer.io fetches external resources during rendering, you can use any publicly accessible CSS framework, font library, or stylesheet.
Tailwind CSS
<html>
<head>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="p-8 bg-white">
<div class="max-w-md mx-auto bg-gray-50 rounded-lg shadow p-6">
<h1 class="text-2xl font-bold text-gray-900">Order Confirmation</h1>
<p class="text-gray-600 mt-2">Thank you for your purchase.</p>
</div>
</body>
</html>
Bootstrap
<html>
<head>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
</head>
<body>
<div class="container mt-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Report Summary</h5>
<p class="card-text">Generated on 2024-01-15</p>
</div>
</div>
</div>
</body>
</html>
Google Fonts
<html>
<head>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
rel="stylesheet"
/>
<style>
body { font-family: 'Inter', sans-serif; }
</style>
</head>
<body>
<h1 style="font-weight: 700;">Beautiful Typography</h1>
<p style="font-weight: 400;">Using Google Fonts in your documents.</p>
</body>
</html>
Complex Layouts
CSS Grid
<html>
<head>
<style>
.dashboard {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
padding: 24px;
}
.card {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 8px;
padding: 20px;
}
.card h3 {
margin: 0 0 8px 0;
color: #374151;
font-size: 14px;
}
.card .value {
font-size: 28px;
font-weight: 700;
color: #111827;
}
.full-width {
grid-column: 1 / -1;
}
</style>
</head>
<body>
<div class="dashboard">
<div class="card">
<h3>Total Revenue</h3>
<div class="value">$45,231</div>
</div>
<div class="card">
<h3>Orders</h3>
<div class="value">1,247</div>
</div>
<div class="card">
<h3>Customers</h3>
<div class="value">892</div>
</div>
<div class="card full-width">
<h3>Monthly Sales Chart</h3>
<!-- Chart content here -->
</div>
</div>
</body>
</html>
Flexbox
<html>
<head>
<style>
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 40px;
border-bottom: 2px solid #e5e7eb;
}
.logo { font-size: 24px; font-weight: 700; }
.meta { text-align: right; color: #6b7280; }
.two-column {
display: flex;
gap: 40px;
padding: 40px;
}
.two-column > div { flex: 1; }
</style>
</head>
<body>
<div class="header">
<div class="logo">Acme Inc.</div>
<div class="meta">
<div>Invoice #INV-001</div>
<div>January 15, 2024</div>
</div>
</div>
<div class="two-column">
<div>
<h3>From</h3>
<p>Acme Inc.</p>
<p>123 Business St.</p>
</div>
<div>
<h3>Bill To</h3>
<p>Jane Smith</p>
<p>456 Customer Ave.</p>
</div>
</div>
</body>
</html>
Practical Examples
Generating an Invoice PDF from HTML
A complete example that generates a styled invoice PDF using JavaScript.
const html = `
<html>
<head>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-white p-8 font-sans">
<div class="max-w-2xl mx-auto">
<div class="flex justify-between mb-8">
<div>
<h1 class="text-2xl font-bold">Acme Inc.</h1>
<p class="text-gray-600">123 Business Street</p>
<p class="text-gray-600">New York, NY 10001</p>
</div>
<div class="text-right">
<h2 class="text-xl font-semibold text-blue-600">INVOICE</h2>
<p>#INV-2024-001</p>
<p class="text-gray-600">January 15, 2024</p>
</div>
</div>
<table class="w-full mb-8">
<thead>
<tr class="border-b-2">
<th class="text-left py-2">Item</th>
<th class="text-right py-2">Qty</th>
<th class="text-right py-2">Price</th>
<th class="text-right py-2">Total</th>
</tr>
</thead>
<tbody>
<tr class="border-b">
<td class="py-3">Web Development</td>
<td class="text-right">40</td>
<td class="text-right">$150.00</td>
<td class="text-right">$6,000.00</td>
</tr>
<tr class="border-b">
<td class="py-3">UI Design</td>
<td class="text-right">20</td>
<td class="text-right">$120.00</td>
<td class="text-right">$2,400.00</td>
</tr>
</tbody>
</table>
<div class="flex justify-end">
<div class="w-64">
<div class="flex justify-between py-1">
<span>Subtotal</span>
<span>$8,400.00</span>
</div>
<div class="flex justify-between py-1">
<span>Tax (8%)</span>
<span>$672.00</span>
</div>
<div class="flex justify-between py-2 border-t-2 font-bold text-lg">
<span>Total</span>
<span>$9,072.00</span>
</div>
</div>
</div>
</div>
</body>
</html>
`;
const encoded = Buffer.from(html).toString("base64");
const response = await fetch("https://api.cloudlayer.io/v2/html/pdf", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": "<YOUR-API-KEY>",
},
body: JSON.stringify({
html: encoded,
format: "letter",
printBackground: true,
margin: {
top: "0.5in",
bottom: "0.5in",
left: "0.5in",
right: "0.5in",
},
async: false,
}),
});
const result = await response.json();
console.log("PDF URL:", result.assetUrl);
Creating a Social Media Image
Generate an Open Graph or social media card image from HTML.
import base64
import requests
html = """
<html>
<head>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@700;400&display=swap" rel="stylesheet">
<style>
body {
margin: 0;
width: 1200px;
height: 630px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: 'Inter', sans-serif;
}
.card {
text-align: center;
color: white;
padding: 60px;
}
h1 {
font-size: 48px;
font-weight: 700;
margin-bottom: 16px;
}
p {
font-size: 24px;
opacity: 0.9;
}
</style>
</head>
<body>
<div class="card">
<h1>Automate Your Document Generation</h1>
<p>PDFs, images, and more -- powered by cloudlayer.io</p>
</div>
</body>
</html>
"""
encoded = base64.b64encode(html.encode("utf-8")).decode("utf-8")
response = requests.post(
"https://api.cloudlayer.io/v2/html/image",
headers={
"Content-Type": "application/json",
"x-api-key": "<YOUR-API-KEY>",
},
json={
"html": encoded,
"viewPort": {
"width": 1200,
"height": 630,
},
"async": False,
},
)
result = response.json()
print("Image URL:", result["assetUrl"])
PDF-Specific Options
When converting HTML to PDF, you can control the output with these common options:
| Parameter | Type | Default | Description |
|---|---|---|---|
format | string | — | Paper format: letter, legal, a4, etc. |
landscape | boolean | false | Use landscape orientation |
printBackground | boolean | false | Include background colors and images |
margin | object | 0.4in | Page margins (top, bottom, left, right) |
pageRanges | string | all pages | Which pages to include (e.g., "1-3, 5") |
scale | number | 1 | Scale factor (0.1 to 2) |
preferCSSPageSize | boolean | false | Use CSS @page size instead of format |
Paper Formats
| Format | Dimensions |
|---|---|
letter | 8.5in x 11in |
legal | 8.5in x 14in |
tabloid | 11in x 17in |
ledger | 17in x 11in |
a0 | 33.1in x 46.8in |
a1 | 23.4in x 33.1in |
a2 | 16.54in x 23.4in |
a3 | 11.7in x 16.54in |
a4 | 8.27in x 11.7in |
a5 | 5.83in x 8.27in |
a6 | 4.13in x 5.83in |
Tips
- Always base64-encode your HTML before placing it in the JSON payload. Raw HTML in JSON leads to parsing errors.
- Use
printBackground: trueif your HTML uses background colors or images — Chrome’s PDF renderer omits backgrounds by default. - External resources are fetched at render time. Any publicly accessible image, font, or stylesheet URL will be loaded. Private or localhost URLs will not work.
- For large HTML documents, consider using the multipart form upload with the template endpoint instead of base64-encoding everything into a single JSON string.
- Test locally first. Open your HTML in a browser, use Ctrl+P (print), and verify it looks correct before sending it to the API.