Embed SDK

The FormNode Embed SDK is a single 5KB script that drops any FormNode form into any page — inline in the layout, as a modal popup, or as a slide-in panel. The iframe auto-resizes to the form's content, prefill flows in cleanly, and a small postMessage bridge lets the host page react to load, submit, and close events.

Get the embed URL

Open a form in the dashboard, click Share, then the Embedtab. Pick a mode (inline, popup, or slide-in) and copy the snippet — it's already filled in with your form's URL. The examples below show what those snippets look like.

Inline mode

Renders the form directly in your page layout. The iframe auto-resizes as the form grows (e.g., dynamic fields revealing nested options) so there's no internal scrollbar — the form just takes the height it needs.

<div data-formnode-form="https://app.formnode.io/organizations/{org-id}/form/{form-id}"
     data-mode="inline"></div>
<script src="https://app.formnode.io/embed.js"></script>

Best for landing pages, contact pages, in-context intake (e.g., a ticket form embedded inside your help-desk article).

Popup mode

Opens the form in a centered modal overlay when the trigger element is clicked. The trigger is whatever element carries the data-formnode-form attribute — typically a button.

<button data-formnode-form="https://app.formnode.io/organizations/{org-id}/form/{form-id}"
        data-mode="popup">
  Open intake form
</button>
<script src="https://app.formnode.io/embed.js"></script>

Closes on the Escape key, on backdrop click, or on submit. The backdrop is a translucent dark overlay; the modal width caps at 720px and stays scrollable on small screens.

Slide-in mode

Slides in from the right (or left, configurable) as a side panel, leaving the underlying page visible. Good for "request access" or "contact sales"-style CTAs where you don't want to cover the page's primary content.

<button data-formnode-form="https://app.formnode.io/organizations/{org-id}/form/{form-id}"
        data-mode="slide-in">
  Request access
</button>
<script src="https://app.formnode.io/embed.js"></script>

Prefill

Two ways to prefill fields when the form loads:

Via data attribute

Add data-prefill as a JSON object on the same element. Each key matches a field name (not label):

<div data-formnode-form="https://app.formnode.io/..."
     data-mode="inline"
     data-prefill='{"company":"Acme","tech_email":"jsmith@msp.example"}'></div>

Via URL parameters

Append ?field_name=value to the embed URL. This works the same way it does for direct-link forms — see Form builder & field types for the full pattern.

Imperative API

For dynamic mounting (single-page apps, modals you control yourself, forms gated behind auth state), use the global FormNode object the SDK exposes:

<script src="https://app.formnode.io/embed.js"></script>
<script>
  // Inline render into a target selector
  FormNode.inline('#intake-form', {
    url: 'https://app.formnode.io/organizations/{org-id}/form/{form-id}',
    prefill: { company: 'Acme', tech_email: 'jsmith@msp.example' },
  });

  // Popup, triggered by a button click
  FormNode.popup({
    url: 'https://app.formnode.io/organizations/{org-id}/form/{form-id}',
    trigger: '#open-form-btn',
  });

  // Slide-in panel from the right
  FormNode.slideIn({
    url: 'https://app.formnode.io/organizations/{org-id}/form/{form-id}',
    position: 'right',
  });
</script>

postMessage events

The embedded form posts events back to the host page so you can react to load, resize, submit, and close. Listen on window:

window.addEventListener('message', (event) => {
  if (event.origin !== 'https://app.formnode.io') return;
  if (!event.data || typeof event.data !== 'object') return;

  switch (event.data.type) {
    case 'formnode:ready':
      // Form has rendered and posted its initial height
      console.log('Form ready, height:', event.data.height);
      break;
    case 'formnode:resize':
      // The SDK already handles this; only listen if you want to react
      console.log('Form resized to', event.data.height);
      break;
    case 'formnode:page-change':
      // User moved to a different page in a multi-page form
      console.log('Page changed to', event.data.page);
      break;
    case 'formnode:submit':
      console.log('Submission ID:', event.data.submissionId);
      // Hide the embed, show a thank-you, fire your analytics, etc.
      break;
    case 'formnode:close':
      // Popup or slide-in was dismissed
      break;
  }
});

Always check the origin against https://app.formnode.io (or your custom domain) before trusting event.data. The SDK ignores messages from other origins automatically, but your own listener should too.

Using a custom domain

If you've configured a custom domain, replace app.formnode.io with your domain in both the form URL and the script URL — for example forms.yourcompany.com/embed.js. The browser sees a single origin, which avoids any third-party-cookie concerns.

Troubleshooting

Form loads but doesn't resize

The SDK uses postMessage to negotiate height. If your page has a strict Content Security Policy that blocks frame-src for app.formnode.io, the iframe never sets its height. Add app.formnode.io (or your custom domain) to frame-src in your CSP.

Prefill values don't appear

Prefill keys match the field name, not its label. If your field is labeled "Company name" and named company_name, you must prefill with company_name, not company or Company name.

Popup opens behind a different overlay

The SDK's modal and slide-in panel use z-index: 99999. If your site uses higher z-indexes for navigation or other modals, increase yours above 100000 so the embed sits on top.