Get the FREE Ultimate OpenClaw Setup Guide →

unlayer-export

Flagged

{"isSafe":false,"isSuspicious":true,"riskLevel":"medium","findings":[{"category":"other","severity":"medium","description":"Credential leakage risk: The Cloud API usage example shows constructing an Authorization header from an API key in client-side code (Authorization: 'Basic ' + Buffer.from('YOUR_API_KEY:').toString('base64')). If this snippet is used in frontend, the key could be exposed. Recommend moving such calls server-side or using restricted, short-lived credentials/tokens and not embedding secrets in client code.","evidence":"Authorization: 'Basic ' + Buffer.from('YOUR_API_KEY:').toString('base64')"},{"category":"other","severity":"medium","description":"Potential XSS/HTML injection risk: Exported HTML and design JSON can include user-provided HTML. Rendering this content on a page without proper sanitization/escaping could introduce XSS. Recommend sanitizing/safely escaping HTML on output and validating/sanitizing content before rendering.","evidence":"html: data.html and design JSON may contain user-provided HTML content (see Export HTML flow)"}],"summary":"The content is largely about how to export and save Unlayer designs. No malicious commands or payloads are present. However, two risk areas exist: (1) API keys shown in client-side examples could be exposed if used in frontend code, and (2) exporting HTML/design content could lead to XSS if the HTML is rendered without proper sanitization. Mitigations include avoiding embedding secrets in frontend code, using server-side API calls or restricted tokens, and sanitizing HTML before rendering."}

npx machina-cli add skill unlayer/unlayer-skills/unlayer-export --openclaw
Files (1)
SKILL.md
8.1 KB

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

Source

git clone https://github.com/unlayer/unlayer-skills/blob/main/unlayer-export/SKILL.mdView on GitHub

Overview

Unlayer-export handles HTML, plain text, images, PDFs, and ZIP exports from the Unlayer editor. Some formats run in the browser for free; others use the Cloud API and require a paid plan. Always save the design JSON alongside any export to preserve the ability to edit later.

How This Skill Works

Use dedicated export methods (exportHtml, exportPlainText, exportImage, exportPdf, exportZip) to generate the desired output. Each method returns an object containing the design JSON (data.design) and a format-specific payload (e.g., html, url, or body). For paid formats, server-side Cloud API calls require an API key; client-side exports provide free options.

When to Use It

  • You need HTML + design for email sending or web publishing (exportHtml).
  • You need a plain text version for SMS or accessibility fallbacks (exportPlainText).
  • You need a PNG thumbnail or social preview (exportImage).
  • You need a print-ready document (exportPdf).
  • You need an offline package of assets (exportZip).

Quick Start

  1. Step 1: Choose an export method (e.g., exportHtml) based on your goal.
  2. Step 2: Call the API and save both data.html (or data.url) and data.design to your backend.
  3. Step 3: When reloading, ensure the editor is ready and call unlayer.loadDesign(saved.design) to restore your work.

Best Practices

  • Always save the design JSON alongside any export; all export methods return data.design.
  • Choose the export type that matches your use case: HTML for emails/web, Plain Text for SMS, Image for previews, PDF for print, ZIP for offline bundles.
  • When exporting HTML, tune output with cleanup, minify, and inlineStyles as needed for your recipient.
  • Use data.chunks when you need just the body content or extracted CSS/fonts for embedding.
  • Secure CLOUD API keys and monitor quotas for paid export methods.

Example Use Cases

  • Newsletter email: exportHtml and persist both generated HTML and the design JSON to your templates service.
  • SMS fallback: exportPlainText to send plain text alongside your design.
  • Social preview: exportImage to generate a PNG URL for thumbnails and sharing.
  • Print-ready doc: exportPdf to obtain a PDF URL plus the design JSON for edits.
  • Offline bundle: exportZip to deliver a package of assets and the design JSON.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers