<- All posts

Usero Journal

How to Embed a Form on a Website (With a Working Snippet)

Will Smith··6 min read

The usual way to embed a form on a website is copying an iframe tag from somewhere and pasting it in. Then the box is either too short and clips the submit button, or too tall and leaves a gray gap under a two-field form, and it stays that color no matter what the rest of the page is doing.

I wanted to see what is actually wrong with a basic iframe embed and fix each part properly, not just wallpaper over it with a taller box.

The Three Things That Break

An iframe pointed at a form on someone else’s domain fails in the same three ways almost every time, and none of them are hard once you name them.

1. Fixed height

You set height="500", the form has four fields and fits in 380px, and now there is 120px of empty space under it. Add a fifth field, or a validation error, and 500px is suddenly too short and the form scrolls inside its own little box. Your page cannot measure the height of a cross-origin iframe’s contents, that is a security boundary and it is not going away, so the form has to report its own height.

2. Dark mode and your brand color

A form served from a different domain renders with whatever styling it shipped with. If your site is dark and the form is a white card, it reads as an ad, not a part of the page. Some tools let you pin a palette with a query param; if not, you are stuck with whatever the form defaults to.

3. Getting the resize message wired up right

Even once the form posts its height, your page has to be listening. Miss the listener, or match the message to the wrong iframe when you have more than one on the page, and you are back to a fixed box.

A Working Embed, End to End

Here is the pattern, both halves. The child page (the form itself) measures its content and posts the height whenever it changes:

// inside the form's own page, runs in the iframe
function reportHeight() {
  const height = Math.ceil(document.body.getBoundingClientRect().height)
  window.parent.postMessage({ type: 'form:resize', height }, '*')
}

// call it on load, and again whenever content changes
new ResizeObserver(reportHeight).observe(document.body)
reportHeight()

And the host page (your site, embedding the form) listens for that message and resizes the matching iframe:

<iframe
  id="my-form"
  src="https://example.com/forms/abc123?embed=1"
  title="Contact form"
  loading="lazy"
  style="width:100%;border:0;display:block;min-height:420px"
></iframe>
<script>
  window.addEventListener('message', function (event) {
    var msg = event.data
    if (!msg || msg.type !== 'form:resize') return
    var frame = document.getElementById('my-form')
    if (frame && frame.contentWindow === event.source) {
      frame.style.height = msg.height + 'px'
    }
  })
</script>

That is the whole mechanism: ResizeObserver on the form’s side, postMessage to cross the origin boundary, a listener on your side that matches the message to the right iframe by comparing event.source to contentWindow. No cookies, no CORS headers, nothing to configure on an allowlist. If the form you are embedding does not send that message itself, you cannot add it from the host page, you need the form’s own vendor to ship it.

The Version Usero Ships

Disclosure: I build Usero, so weigh that. Every Usero form has an Embed button next to Copy Public Link in the builder. It generates exactly the snippet above, with the resize wiring already done, plus two params for the two things a raw iframe cannot fix on its own:

  • theme=light or theme=dark pins the palette so the form matches your page instead of the visitor’s OS setting.
  • title=0 drops the form’s own heading, for pages that already have one.
<iframe
  src="https://usero.io/f/SLUG?embed=1"
  title="Contact form"
  data-usero-form
  loading="lazy"
  style="width:100%;border:0;display:block;min-height:420px"
></iframe>
<script>
  window.addEventListener('message', function (event) {
    var message = event.data
    if (!message || message.type !== 'usero:form:resize') return
    var frames = document.querySelectorAll('iframe[data-usero-form]')
    for (var i = 0; i < frames.length; i++) {
      if (frames[i].contentWindow === event.source) {
        frames[i].style.minHeight = '0'
        frames[i].style.height = message.height + 'px'
      }
    }
  })
</script>

The embedded view is marked noindex, so it never shows up in search competing with the form’s own public page, and every response lands in the same responses table whether it came from the direct link or the embed. Full setup steps are in the forms docs.

And the response is not the end of it. A form response in Usero is feedback like anything else, so it clusters with what comes in through the widget or GitHub issues, and a clustered request can open a pull request against your repo with a first pass at the fix. You review the diff and merge it yourself, nothing auto-merges. If your form is collecting bug reports or feature requests, that is the part a plain form builder never gets you to.

Related Reading

Frequently Asked Questions

Is an iframe the right way to embed a form on a website?

For a form built on someone else’s domain, yes. An iframe is the only option that does not require you to also rebuild the form’s validation, styling, and submission handling in your own codebase. The two problems worth solving are the fixed height (fix with a resize script) and dark mode (fix with a theme query param), covered below.

Why is my embedded form cut off or scrolling inside its own box?

The iframe was given a fixed height and the form is taller (or shorter) than that number. Browsers cannot see inside a cross-origin iframe to measure it for you, so the form itself has to measure its own height and post that number to the parent page with window.postMessage. Without that message, you are stuck picking one height and hoping.

My resize script is in the snippet but the iframe still will not resize. What is wrong?

Almost always the CMS stripped the <script> tag on paste. Rich-text editors and some page builders sanitize raw HTML and drop anything that looks like JavaScript. View the page source and check the script survived. If it did, the next suspect is a Content-Security-Policy: a frame-src directive that does not list the form’s origin blocks the iframe from loading at all.

Does embedding a form on my site cause a CORS error?

An iframe itself is not subject to CORS, that restriction applies to fetch and XHR calls made from your page’s JavaScript, not to loading a page inside a frame. The form submits itself, from inside its own frame, to its own origin, so there is nothing for your site’s CORS policy to block.

Can I embed a form on Webflow, WordPress, or Squarespace?

Yes, all three let you drop a raw HTML embed block. Webflow and Squarespace have a dedicated Embed element built for exactly this. WordPress needs a Custom HTML block, and if you are on the block editor, paste the iframe and script into that block rather than a paragraph block, which will escape the tags as text.

Continue reading

Build a feedback loop your team actually uses

Usero collects, clusters, and turns user feedback into shipped fixes.

Get started free