EmbedPDF

Saving

doc.download() returns the whole PDF, with every change you made, as bytes:

const bytes = await doc.download();

Save in the browser#

Wrap the bytes in a Blob and let the browser download it:

const bytes = await doc.download();
 
const url = URL.createObjectURL(new Blob([bytes], { type: 'application/pdf' }));
const link = document.createElement('a');
link.href = url;
link.download = 'contract-signed.pdf';
link.click();
URL.revokeObjectURL(url);

To send the file to your server instead, put the same Blob in a FormData or pass the bytes to fetch() as the body.

Save in Node#

import { writeFile } from 'node:fs/promises';
 
await writeFile('out.pdf', await doc.download());

For large files, downloadToFile() writes the PDF straight to disk, without the bytes passing through JavaScript:

await doc.downloadToFile('out.pdf');

It takes the same mode option as download(), and works in Node only.

Incremental or rewrite#

mode chooses how the file is written:

const bytes = await doc.download({ mode: 'rewrite' });
ModeWhat you get
'incremental' (default)The file as it was opened, byte for byte, with your changes added at the end.
'rewrite'A new file with only the document as it is now. Earlier versions are gone.

Pick by what the file is for:

  • Signed documents: incremental. A signature covers the bytes as they were signed. An incremental save leaves those bytes alone, so the signatures stay valid. A rewrite would break every one of them, so a signed document refuses it with ProtectedDocument.
  • After a redaction, or after deleting something sensitive: rewrite. An incremental file still holds the version from before your changes, and PDF tools can recover it. Only a rewrite leaves the removed content out. See Redaction.
  • The smallest file: rewrite. It also leaves out anything nothing refers to anymore.
  • Everything else: incremental. It’s the default, it’s fast, and it never changes the parts of the file you didn’t touch.

Where your changes are#

The engine keeps the file as you opened it, and never changes it. Your changes live beside it, in memory, until you download. When you close the document without downloading, they’re gone.

Permissions#

Downloading needs the doc.download permission. Without it, download() fails with Forbidden, so check before you show a download button:

if (doc.security.allows('doc.download')) {
  showDownloadButton();
}

Good to know#

An unchanged document#

When nothing changed since you opened the document, an incremental download returns the exact bytes you opened. The same holds when you changed something and then changed it back, such as an annotation added and deleted again. That keeps a signed document exactly as it was signed.

Password-protected files#

A file that had a password when you opened it still has it after you save, in both modes.

Saving only the changes#

doc.downloadLayer() returns only what you changed, as a small file you can store next to the original and open with it later. See Layers.

Cancelling a download#

download() returns a promise you can cancel with .abort(), like every call. See Errors & cancelling.

Was this page helpful?

Your feedback goes directly to the documentation team.