> Lettrove docs 1.x · https://docs.lettrove.com/docs/editor/exports

# Getting designs out

Everything your users make can leave Lettrove in seven forms, from your page (the design exactly as
on screen) or from your server (the design as last saved).

| You want | From the page | From your server (`@lettrove/node`) |
|---|---|---|
| The HTML to send or publish | `editor.exportHtml()` | `lettrove.designs.export(id, { user })` |
| The HTML in pieces, for your own page | `exportHtml()` → `chunks` | the same → `chunks` |
| Plain text | `editor.exportPlainText()` | `designs.export` → `text` |
| A PDF | `editor.exportPdf()` | `designs.export(id, { user, format: 'pdf' })` |
| A PNG picture | `editor.exportImage()` | `designs.export(id, { user, format: 'png' })` |
| A ZIP (HTML, text, images) | `editor.exportZip()` | `designs.export(id, { user, format: 'zip' })` |
| The design itself, to keep | `editor.getDesign()` | `lettrove.designs.get(id, { user })` |

Each mode offers what makes sense for it: an email all of them, a popup no PDF. Every export is
recorded, and the images it shows are marked as sent, so [they are never deleted](/docs/data/what-we-store).

## HTML: `exportHtml()`

```ts
const out = await editor.exportHtml({
  merge: { contact: { first_name: 'Ada' }, unsubscribeUrl: 'https://acme.com/u/123' }, // optional
  text: { links: true, images: true, preheader: false },                               // optional
});
```

| Field | |
|---|---|
| `html` | The whole HTML document, minified, ready to send or host |
| `chunks` | `{ body, css, js, fonts }` — the same HTML in pieces to place inside your own page ([Landing page](/docs/editor/modes/landing-page), [Popup](/docs/editor/modes/popup)) |
| `text` | The plain-text version |
| `subject`, `preheader` | An email's subject and preheader, merged the same way |
| `mergeTags` | Merge tags still in it, exactly as written — fill them before it goes to anyone |
| `warnings` | Anything an inbox would do to it that you should know, e.g. Gmail clipping past ~102 KB |
| `bytes` | The HTML's size |
| `mode` | `email`, `page`, `popup` or `document` |
| `designId`, `revision` | Which design, and the saved revision the screen was based on |
| `exportId` | This export's record, for your logs and for support |
| `rendererVersion` | The renderer that made it |
| `design` | The design document, to keep ([what you may rely on](/docs/api/design-document)) |

Without `merge`, every merge tag stays exactly as written — handy when your own email service fills
them. See [Merge tags](/docs/editor/merge-tags).

An image your user pasted straight into the design (not uploaded) is uploaded on the way out, so
the HTML only ever points at `https://` images: inboxes drop embedded ones.

## Plain text: `exportPlainText()`

```ts
const { text } = await editor.exportPlainText({
  links: true,     // write each link's address beside its label (default true); false keeps labels, drops buttons
  images: true,    // speak each image by its alt text (default true)
  preheader: false,// start with the preheader (default false)
  merge: { contact: { first_name: 'Ada' } }, // optional, as for exportHtml
});
```

Send it as the `text/plain` part beside the HTML: inboxes that do not show HTML show this, and spam
filters like to see both.

## Files: `exportPdf()`, `exportImage()`, `exportZip()`

```ts
const pdf = await editor.exportPdf();
const png = await editor.exportImage({ fullPage: true }); // false: the first screen only
const zip = await editor.exportZip();
```

Each resolves with the same shape:

```json
{
  "url": "https://…/q3-proposal.pdf",
  "filename": "q3-proposal.pdf",
  "format": "pdf",
  "bytes": 48213,
  "expiresAt": null,
  "warnings": [],
  "exportId": "01J9ZR…",
  "designId": "01J9ZQ3W8D2K7M5T1V4XG6HB0R",
  "revision": 7,
  "mode": "document",
  "design": { }
}
```

Fetch the file from `url`. `expiresAt` is `null` while the file is kept; **read it rather than
assume it**, since how long files are kept may change.

The `url` is long and unguessable, and works **without a key** for anyone who has it, as a link to a
file on a CDN does. Hand it only to whoever should have the file, or download the file to your own
storage and share that.

| Format | What is in it |
|---|---|
| PDF | A document on its own paper, with header, footer and page numbers. Any other design on A4. |
| PNG | The design drawn as a picture, the whole length (`fullPage: true`, the default) or the first screen |
| ZIP | `index.html`, the plain text, the images Lettrove hosts for it, and a short README. Images hosted elsewhere stay as links. |

All three take `merge` too.

## The design itself: `getDesign()`

```ts
const { designId, revision, design } = await editor.getDesign();
await myDb.saveCopy(designId, design); // keep it as it is
```

The design is yours to keep. Store it as it is and hand it back to render it on your server
(`lettrove.render({ doc: design })`) — see [Keeping your own copy](/docs/data/own-copy).

## From your server

```ts
import { Lettrove } from '@lettrove/node';
const lettrove = new Lettrove({ secretKey: process.env.LETTROVE_SECRET_KEY });

// HTML (and text, chunks, subject…) — the same fields as exportHtml
const email = await lettrove.designs.export(designId, { user: { id: userId }, merge: { contact } });

// A file
const pdf = await lettrove.designs.export(designId, { user: { id: userId }, format: 'pdf' });
const png = await lettrove.designs.export(designId, { user: { id: userId }, format: 'png', fullPage: false });
```

The server exports the design **as last saved**; the page exports it **as on screen**. For the same
saved design, both give the same HTML.

## In the editor: the Download menu

Your users can download the same files themselves from the **Download** menu in the editor's bar.
To hide it (because your product handles files), pass `features: { download: false }`; your code can
still export.
