Form Embed

Use the code snippet to add the form to your website. Alternatively, you can share the direct link with your customer.

If you've read through the comparisons here and believe embedding a PandaDoc Form is best, let's get it done!

📘

Still using the previous embed?

If your integration loads forms from https://eform.pandadoc.com, use the archived Form Embed (legacy) snippets.

📘

Useful links

PandaDoc forms

Help center

Embed Form Code Snippet

Full form embed

<div id='form-container-YOUR_FORM_ID'></div>
<script type="text/javascript">
    (function () {
        function buildIframeSrc(baseUrl, data) {
            var url = new URL(baseUrl, window.location.href);
            if (data) {
                Object.keys(data).forEach(function (key) {
                    url.searchParams.set(key, JSON.stringify(data[key]));
                });
            }
            return url.toString();
        }
        var config = {
            nodeId: 'form-container-YOUR_FORM_ID',
            width: '100%',
            height: '700px',
            url: 'https://form.pandadoc.com/form/YOUR_FORM_HASH?mode=embedded',
            data: {
                recipients: {
                    'Form Signer': {
                        Email: '[email protected]',
                        FirstName: 'Jane',
                        LastName: 'Doe'
                    }
                },
                metadata: {
                    source: 'iframe-test'
                },
                variables: {
                    'Form signer.FirstName': 'Jane'
                },
                fields: {
                    TextField1: 'Prefilled value',
                    Checkbox1: true,
                    Date1: '2026-09-18'
                }
            },
            events: {
                loaded: function (data) {
                    console.log('[PandaDoc] Form loaded', data);
                },
                started: function (data) {
                    console.log('[PandaDoc] Form submitted', data);
                },
                completed: function (data) {
                    console.log('[PandaDoc] Document signing completed', data);
                },
                redirect_requested: function (data) {
                    console.log('[PandaDoc] Redirect requested', data);
                    if (typeof data.redirectUrl === 'string' && data.redirectUrl) {
                        window.location.assign(data.redirectUrl);
                    }
                },
                exception: function (data) {
                    console.error('[PandaDoc] Form exception', data);
                }
            }
        };
        var iframe = document.createElement('iframe');
        iframe.frameBorder = 0;
        iframe.src = buildIframeSrc(config.url, config.data);
        if (config.nodeId) {
            var node = document.getElementById(config.nodeId);
            node.style.height = config.height;
            node.style.width = config.width;
            iframe.height = '100%';
            iframe.width = '100%';
            node.append(iframe);
        } else {
            iframe.height = config.height;
            iframe.width = config.width;
            document.body.append(iframe);
        }
        var eventMethod = window.addEventListener ? 'addEventListener' : 'attachEvent';
        var messageEvent = eventMethod === 'attachEvent' ? 'onmessage' : 'message';
        window[eventMethod](messageEvent, function (e) {
            if (e && e.data && config && iframe && e.source === iframe.contentWindow) {
                try {
                    var message = JSON.parse(e.data);
                    if (message && message.event) {
                        var event = message.event.replace('embed.form.', '');
                        var callback = config.events ? config.events[event] : null;
                        if (callback) {
                            callback(message.data);
                        }
                    }
                } catch (e) {}
            }
        }, false);
    })();
</script>

Simple form embed

<div id='form-container-YOUR_FORM_ID'></div>
<script type="text/javascript">
    (function () {
        function buildIframeSrc(baseUrl, data) {
            var url = new URL(baseUrl, window.location.href);
            if (data) {
                Object.keys(data).forEach(function (key) {
                    url.searchParams.set(key, JSON.stringify(data[key]));
                });
            }
            return url.toString();
        }
        var config = {
            nodeId: 'form-container-YOUR_FORM_ID',
            width: '100%',
            height: '700px',
            url: 'https://form.pandadoc.com/form/YOUR_FORM_HASH',
            events: {
                loaded: function () {},
                started: function (data) {},
                completed: function (data) {},
                exception: function (data) {}
            },
            data: {},
        };
        var iframe = document.createElement('iframe');
        iframe.frameBorder = 0;
        iframe.src = buildIframeSrc(config.url, config.data);
        if (config.nodeId) {
            var node = document.getElementById(config.nodeId);
            node.style.height = config.height;
            node.style.width = config.width;
            iframe.height = '100%';
            iframe.width = '100%';
            node.append(iframe);
        } else {
            iframe.height = config.height;
            iframe.width = config.width;
            document.body.append(iframe);
        }
        var eventMethod = window.addEventListener ? 'addEventListener' : 'attachEvent';
        var messageEvent = eventMethod === 'attachEvent' ? 'onmessage' : 'message';
        window[eventMethod](messageEvent, function (e) {
            if (e && e.data && config && iframe && e.source === iframe.contentWindow) {
                try {
                    var message = JSON.parse(e.data);
                    if (message && message.event) {
                        var event = message.event.replace('embed.form.', '');
                        var callback = config.events ? config.events[event] : null;
                        if (callback) {
                            callback(message.data);
                        }
                    }
                } catch (e) {}
            }
        }, false);
    })();
</script>

Embed Form Config

* denotes a required parameter.

AttributeDescription
text * nodeIdid of the HTML element to which the form will be appended
text * widthThe width of an element JavaScript embed will be rendered
text * heightThe height of an element JavaScript embed will be rendered
text * urlURL of the form that will be rendered
eventsCapture events from an embedded form. You can subscribe to loaded, started, completed, exception, and redirect_requested
dataPre-fill recipients data, metadata, variables, and fields

Pre-fill values using JavaScript config

It is possible to pre-fill recipients data, metadata, variables, and fields.

recipients — pre-fill data in the authorization form. All role tokens are supported.

data: {
  recipients: {
    'Form Signer': {
      Email: '[email protected]',
      FirstName: 'John',
      LastName: 'Doe',
    }
  }
}

metadata — set metadata for the document generated from the form. Max limit is 10 key-value pairs.

data: {
  metadata: {
    test_metadata_key: 'test value',
  }
}

variables — set values for variables in the document. All variables (predefined and custom) are supported except Document.Value.

data: {
  variables: {
    'Form signer.FirstName': 'John',
    custom_variable: 'custom variable value',
  }
}

fields — set values for fields in the document. Text field, Checkbox, Date, and Dropdown fields are supported.

data: {
  fields: {
    TextField1: 'TextField1 value',
    Dropdown1: 'Dropdown selected value',
    Checkbox1: true,
    Date1: '2021-02-21T00:00:00.000Z'
  }
}
📘

Working with Date fields

Specify date formatting in PandaDoc template date field settings. Pass your date field value in the following ways:

fields: {
    Date1: '2021-02-21T00:00:00.000Z', // ISO 8601 date and time
    Date2: '2021-02-21', // ISO 8601 date, added with the UTC timezone
    Date3: '02/21/2021' // date, added with the UTC timezone
}

Pre-fill values using direct web-link

It is possible to pre-fill recipients data, metadata, variables, and fields without embedding the form, by adding the data as a URL parameter:

&KEY=VALUE

where
KEY is metadata, recipients, variables, or fields
and
VALUE is URL-encoded data that matches the JavaScript config.

Example

https://form.pandadoc.com/form/YOUR_FORM_HASH?variables=%7B%22test_field_id%22%3A%22test%20value%22%7D

is similar to this code in config:

data: {
  variables: {
    test_field_id: 'test value',
  }
}

To pre-fill recipient information in the form, all role tokens are supported.

Example

https://form.pandadoc.com/form/YOUR_FORM_HASH?recipients=%7B%22Client%22:%7B%22Email%22:%[email protected]%22,%22FirstName%22:%22Panda%22,%22LastName%22:%22Test%22%7D%7D

is similar to this code in config:

data: {
  recipients: {
    'Client': {
      Email: '[email protected]',
      FirstName: 'Panda',
      LastName: 'Test',
    }
  }
}

All possible role variables:

FirstName
LastName
Email
Company
Phone
Country
State
StreetAddress
City
PostalCode
Title

Handling events

It is possible to capture events from an embedded form. You can subscribe to these events:

loaded — the form is loaded and a user is asked to enter contact details (recipient names and emails).

started — a user has entered contact details for all recipients and pressed Review document to create a document from the form.

{
  recipients: [{
    first_name: 'John',
    last_name: 'Doe',
    email: '[email protected]'
  }],
}

completed — a user filled in the assigned fields and finalized the document.

{
  document, // public document
}

exception — an error occurred while a recipient tries to finish their part.

{
  uuid, // document uuid
}

redirect_requested — handle redirect requests.

When a template or form is configured to redirect after submission, the embedded form sends a redirect_requested event to the parent page. Subscribe to this event and redirect the visitor using the URL provided in the event payload.

events: {
  redirect_requested: function (data) {
    if (typeof data.redirectUrl === 'string' && data.redirectUrl) {
      window.location.assign(data.redirectUrl);
    }
  }
}

redirect_requested payload:

{
  redirectUrl: 'https://example.com/thank-you'
}

redirectUrl is the destination configured for the form. Validate that it is a non-empty string before navigating. The website that embeds the form handles the redirect. You can navigate the current page, open the link in a new tab, or perform another action.

Reload form after submission

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

<div id='form-container-YOUR_FORM_ID'></div>
<script type="text/javascript">
    (function () {
        var config = {
            nodeId: 'form-container-YOUR_FORM_ID',
            width: '100%',
            height: '700px',
            url: 'https://form.pandadoc.com/form/YOUR_FORM_HASH',
            events: {
                loaded: function () {},
                started: function (data) {},
                completed: function (data) {
                    // Reload the page one second after the form is completed.
                    setTimeout(function () {
                        window.location.reload();
                    }, 1000);
                },
                exception: function (data) {}
            },
            data: {},
        };
        const dataQueryString = config.data ? Object.keys(config.data)
            .map(function (key) {
                return '&' + key + '=' + encodeURIComponent(JSON.stringify(config.data[key]));
            })
            .join('') : '';
        var iframe = document.createElement('iframe');
        iframe.frameBorder = 0;
        iframe.src = config.url + dataQueryString;
        if (config.nodeId) {
            var node = document.getElementById(config.nodeId);
            node.style.height = config.height;
            node.style.width = config.width;
            iframe.height = '100%';
            iframe.width = '100%';
            node.append(iframe);
        } else {
            iframe.height = config.height;
            iframe.width = config.width;
            document.body.append(iframe);
        }
        var eventMethod = window.addEventListener ? 'addEventListener' : 'attachEvent';
        var messageEvent = eventMethod === 'attachEvent' ? 'onmessage' : 'message';
        window[eventMethod](messageEvent, function (e) {
            if (e && e.data && config && iframe && e.source === iframe.contentWindow) {
                try {
                    var message = JSON.parse(e.data);
                    if (message && message.event) {
                        var event = message.event.replace('embed.form.', '');
                        var callback = config.events ? config.events[event] : null;
                        if (callback) {
                            callback(message.data);
                        }
                    }
                } catch (e) {
                    console.log(e);
                }
            }
        }, false);
    })();
</script>
</body>
</html>

Did this page help you?