mcpField
U
unlayer-export

unlayer-export

github.com/unlayerDevelopment14131 installsUpdated 4w ago
Repository

About unlayer-export

A development skill covering how to export Unlayer designs into HTML, plain text, images, PDF, and ZIP files. It also explains saving design JSON so exported content can be edited later.

Key features

  1. 01HTML and plain-text export
  2. 02Image, PDF, and ZIP export options
  3. 03Design JSON save and load guidance
  4. 04HTML chunks for extracting content
  5. 05Debounced autosave patterns

Use cases

  1. 01Saving editable designs alongside exported HTML
  2. 02Creating plain-text email fallbacks
  3. 03Generating image previews or PDF documents

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/unlayer/unlayer-skills --skill unlayer-export

After installing, type/unlayer-exportin Claude Code to confirm it loaded.

Bundled filesreferences/design-json.md

Details

From the project README

Export Content

Overview

Unlayer supports multiple export formats. Some are client-side (free), others use the Cloud API (paid).

Which Export Method?

MethodOutputPaid?Use When
exportHtmlHTML + design JSONNoEmail sending, web publishing, saving designs
exportPlainTextPlain text + designNoSMS, accessibility fallback
exportImagePNG URL + designYesThumbnails, previews, social sharing
exportPdfPDF URL + designYesPrint-ready documents
exportZipZIP URL + designYesOffline 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

// SAVE — use exportHtml to get both design JSON and HTML
unlayer.exportHtml(async (data) => {
  await fetch('/api/templates', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      design: data.design,  // Save this — needed to edit later
      html: data.html,      // The rendered HTML output
    }),
  });
});

// LOAD — restore a saved design (must wait for editor:ready)
unlayer.addEventListener('editor:ready', async () => {
  const response = await fetch('/api/templates/123');
  const saved = await response.json();
  unlayer.loadDesign(saved.design);   // Pass the saved JSON object
});

// LOAD BLANK
unlayer.loadBlank({ backgroundColor: '#ffffff', contentWidth: '600px' });

// LOAD AN UNLAYER TEMPLATE
unlayer.loadTemplate(templateId);     // ID from Unlayer dashboard

Export HTML

unlayer.exportHtml((data) => {
  const { html, design, chunks } = data;

  // html     — Full HTML document (string)
  // design   — Design JSON (always save this!)
  // chunks   — { css, js, body, fonts, tags }
  //   body   — Just the content inside <body> (no wrapper)
  //   css    — Extracted CSS styles
  //   fonts  — Web fonts used in the design

  // Save both to your backend
  await fetch('/api/templates', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ design, html }),
  });
}, {
  // All options are optional
  cleanup: true,          // Remove editor markup (default: true)
  minify: false,          // Minify HTML output
  inlineStyles: false,    // Move CSS inline (for email clients)
  mergeTags: {},          // Replace merge tags with real values
  title: 'My Email',     // Set HTML <title>
});

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;
  // Use as email plain-text fallback
}, {
  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) => {
  // data.url    — PNG URL
  // data.design — Design JSON (always save this!)
  console.log('Image URL:', data.url);
}, {
  fullPage: false,           // true = entire page, false = viewport
  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,       // The saved design JSON object
    mergeTags: {},
  }),
});

const data = await response.json();
// data.url — image URL

Export PDF / ZIP (Paid — Cloud API)

// PDF
unlayer.exportPdf((data) => {
  // data.url    — PDF URL
  // data.design — Design JSON
}, { mergeTags: {} });

// ZIP
unlayer.exportZip((data) => {
  // data.url    — ZIP URL
  // data.design — Design JSON
}, { 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(() => {
    // Save design + HTML immediately
    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 }),
      });
    });

    // Generate thumbnail (slower, paid — debounce longer or do on manual save)
    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); // Longer debounce for image generation
});

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

MistakeFix
Only saving HTML, not design JSONAlways save both — all export methods return data.design
Calling export before editor:readyWait for the event first
Not configuring File Storage for image/PDF exportImage and PDF uploads go to your connected File Storage
Not debouncing auto-savedesign:updated fires on every keystroke — debounce 1-3 seconds
Ignoring chunks in exportHtmlUse chunks.body when you need just content without <!DOCTYPE> wrapper
Missing API key for image/PDF/ZIPCloud API key required — get from Dashboard > Project > Settings > API Keys

Troubleshooting

ProblemFix
exportImage returns errorCheck API key, check Cloud API plan, verify design isn't empty
Exported HTML looks different from editorUse cleanup: true (default), check custom CSS
design:updated fires too oftenAlways debounce — it fires on every property change
Loaded design shows blankCheck schemaVersion compatibility, validate JSON structure

Resources

Comments

Markdown supported