| name | unlayer-export |
| description | Exports content from the Unlayer editor โ HTML, PDF, image, plain text, saving and loading design JSON, auto-save patterns, server-side Cloud API export. |
Export Content
Overview
Unlayer supports multiple export formats. Some are client-side (free), others use the Cloud API (paid).
Which Export Method?
| Method | Output | Paid? | Use When |
|---|
exportHtml | HTML + design JSON | No | Email sending, web publishing, saving designs |
exportPlainText | Plain text + design | No | SMS, accessibility fallback |
exportImage | PNG URL + design | Yes | Thumbnails, previews, social sharing |
exportPdf | PDF URL + design | Yes | Print-ready documents |
exportZip | ZIP URL + design | Yes | Offline download packages |
Critical: Always save the design JSON alongside any export. All export methods return data.design โ save it so users can edit later.
Save & Load Designs
unlayer.exportHtml(async (data) => {
await fetch('/api/templates', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
design: data.design,
html: data.html,
}),
});
});
unlayer.addEventListener('editor:ready', async () => {
const response = await fetch('/api/templates/123');
const saved = await response.json();
unlayer.loadDesign(saved.design);
});
unlayer.loadBlank({ backgroundColor: '#ffffff', contentWidth: '600px' });
unlayer.loadTemplate(templateId);
Export HTML
unlayer.exportHtml((data) => {
const { html, design, chunks } = data;
await fetch('/api/templates', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ design, html }),
});
}, {
cleanup: true,
minify: false,
inlineStyles: false,
mergeTags: {},
title: 'My Email',
});
Using chunks โ when you need just the body content (no <!DOCTYPE> wrapper):
unlayer.exportHtml((data) => {
const { body, css, fonts } = data.chunks;
const myHtml = `<style>${css}</style>${fonts}${body}`;
});
Export Plain Text
unlayer.exportPlainText((data) => {
const { text, design } = data;
}, {
ignorePreheader: false,
ignoreLinks: false,
ignoreImages: false,
mergeTags: {},
});
Export Image (Paid โ Cloud API)
Generates a PNG screenshot of the design. The image uploads to your connected File Storage.
Client-side:
unlayer.exportImage((data) => {
console.log('Image URL:', data.url);
}, {
fullPage: false,
mergeTags: {},
});
Server-side via Cloud API (get API key from Dashboard > Project > Settings > API Keys):
const response = await fetch('https://api.unlayer.com/v2/export/image', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Basic ' + Buffer.from('YOUR_API_KEY:').toString('base64'),
},
body: JSON.stringify({
displayMode: 'email',
design: designJSON,
mergeTags: {},
}),
});
const data = await response.json();
Export PDF / ZIP (Paid โ Cloud API)
unlayer.exportPdf((data) => {
}, { mergeTags: {} });
unlayer.exportZip((data) => {
}, { mergeTags: {} });
Auto-Save Pattern
Design + HTML (recommended):
let saveTimeout;
unlayer.addEventListener('design:updated', () => {
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
unlayer.exportHtml(async (data) => {
await fetch('/api/templates/123', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ design: data.design, html: data.html }),
});
});
}, 1000);
});
Design + HTML + Thumbnail (full):
let saveTimeout;
unlayer.addEventListener('design:updated', () => {
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
unlayer.exportHtml(async (data) => {
await fetch('/api/templates/123', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ design: data.design, html: data.html }),
});
});
unlayer.exportImage(async (data) => {
if (!data.url) return;
await fetch('/api/templates/123/thumbnail', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ thumbnailUrl: data.url }),
});
}, { fullPage: false });
}, 3000);
});
Design JSON Quick Reference
The design JSON has this structure (see references/design-json.md for full TypeScript types):
JSONTemplate
โโโ counters โ Internal counters
โโโ schemaVersion โ Schema version number
โโโ body
โโโ rows[] โ Each row contains columns
โ โโโ cells[] โ Column ratios: [1,1] = 50/50
โ โโโ columns[]
โ โโโ contents[] โ Content items (text, image, button...)
โโโ headers[] โ Same as rows (with headersAndFooters feature)
โโโ footers[] โ Same as rows
โโโ values โ Body-level styles (backgroundColor, contentWidth, fontFamily)
Content types: text, heading, button, image, divider, social, html, video, menu, timer.
Common Mistakes
| Mistake | Fix |
|---|
| Only saving HTML, not design JSON | Always save both โ all export methods return data.design |
Calling export before editor:ready | Wait for the event first |
| Not configuring File Storage for image/PDF export | Image and PDF uploads go to your connected File Storage |
| Not debouncing auto-save | design:updated fires on every keystroke โ debounce 1-3 seconds |
Ignoring chunks in exportHtml | Use chunks.body when you need just content without <!DOCTYPE> wrapper |
| Missing API key for image/PDF/ZIP | Cloud API key required โ get from Dashboard > Project > Settings > API Keys |
Troubleshooting
| Problem | Fix |
|---|
exportImage returns error | Check API key, check Cloud API plan, verify design isn't empty |
| Exported HTML looks different from editor | Use cleanup: true (default), check custom CSS |
design:updated fires too often | Always debounce โ it fires on every property change |
| Loaded design shows blank | Check schemaVersion compatibility, validate JSON structure |
Resources