Usero Journal
How to Embed a Form on a Website (With a Working Snippet)
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=lightortheme=darkpins the palette so the form matches your page instead of the visitor’s OS setting.title=0drops 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
- How to Build a Product Feedback Form (and What to Do With the Answers)Read
- How to Add a Feedback Widget to a React App (Build vs Buy)Read
- What Is a Feedback Widget? (And How They Work)Read
- Best User Feedback Tools (2026 Comparison)Read
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
How Sleekplan’s Satisfaction Module Works: They Were Right and We Were Wrong
A hands-on teardown of Sleekplan’s NPS and CSAT module from inside a live workspace: an analytics page that opens on a trend chart, a nine-preset range picker, a plain-English sentence under every chart, the qualitative band word next to the score, and the timing controls that are the best-engineered part of it. Plus the survey score over time we built the same night, with merged AI-authored pull requests drawn on the line.
8 min read
How Canny’s Changelog Works: It Knows Who Asked, and It Never Tells Them
A hands-on teardown of Canny’s changelog from inside a live free-plan workspace: the three-pane editor with a live preview, the linked-posts typeahead that carries vote counts, the publish confirm with no notify option, the Pro-gated subscriber list, and the passive banner the requester has to go looking for. Plus the requester notifications, recipient preview, markdown fix and RSS feed we built the same night.
8 min read
How Featurebase In-App Surveys Work: The Screen We Copied, and the One We Did Not
A hands-on teardown of Featurebase in-app surveys from inside a live workspace: two survey systems in one product, a template gallery where every card is a live render, benchmark lines on the templates, the Featurebase Posts poll type, and what the Free plan stops you doing. Plus how we built Usero surveys on Forms so answers land in the feedback inbox and can become a pull request.
8 min read
Build a feedback loop your team actually uses
Usero collects, clusters, and turns user feedback into shipped fixes.
Get started free