How to Embed a Booking Form in HubSpot Without a Grey Box
To embed a booking form in HubSpot, open the page in the page editor, add a module that accepts raw HTML (a Custom HTML module, or a rich-text field set to source view), and paste the scheduler's iframe snippet into it. Two things commonly go wrong. First, many HubSpot themes render a booking widget through a module field with a fixed list of options — often HubSpot Meetings, Calendly and TypeForm only — so there is no obvious place to put anything else, and the answer is a separate HTML module rather than a fight with that dropdown. Second, HubSpot's rich text editor rewrites pasted markup on every save: it converts width="100%" to a fixed pixel value, and in some fields it strips <script> tags entirely. Both have workarounds, and neither produces an error message.
To embed a booking form in HubSpot, paste the iframe snippet into a Custom HTML module — not a rich-text field — and confirm the script tag survived by reopening source view after saving.
How to embed a booking form on a HubSpot page
- Copy the embed snippet from your scheduling tool — take the inline/iframe version, including any script that comes with it
- In HubSpot, open the page in the page editor (not Design Manager — that defines fields, the page editor fills them in)
- Find or add a module that accepts raw HTML: a Custom HTML module, or a rich-text field opened via Advanced → Source code
- Paste the whole snippet, iframe and script together, and save
- Re-open the source view and confirm the script survived — some fields strip it
- Preview at desktop and mobile widths, then publish
When your theme only offers Calendly: what to do instead
The dropdown in your hero or CTA module is not a HubSpot restriction — it is a list hardcoded into the theme by whoever built it. Agency-built themes commonly ship a "conversion type" field with four choices: HubSpot Form, HubSpot Meeting Calendar, Calendly, and TypeForm. That list lives in a .html module file in Design Manager. HubSpot does not control it and changing schedulers does not change it.
You have three ways out, cheapest first. Add a separate Custom HTML module immediately below (or above) the existing CTA module and put your embed there — the theme module stays untouched. Second, check whether the theme already includes a generic HTML module you have not spotted; many do, and it is easier to drag one onto the page than to fight the CTA field. Third, have a developer add a new option to the module's field definition in Design Manager. Before anyone edits the module in place, ask whether the agency still deploys that theme from source control — if they do, the next deploy overwrites local edits with no warning.
For a broader look at embedding a booking page that works cleanly across any CMS, the Cartoply docs cover both popup and inline iframe modes.
Why the form renders as a grey box with a gap underneath
Your iframe is loading the scheduler's full standalone page — complete with its own page background, outer padding, and a CSS minimum height set to 100vh (one full screen). Wrapped inside a card on your HubSpot page, that reads as a grey box with a large blank gap below the last field.
A scheduler built for embedding detects the framed context and drops that chrome. Cartoply's embed renders transparent, unpadded, and at content height — the host page supplies the card and the background. If your current scheduler does not do this, you have two options: style the iframe container to clip the worst of the padding, or ask the vendor whether an embed parameter (something like ?embed=true) strips the standalone page shell. Some do; many do not. This is worth checking before investing time in CSS workarounds. Read more about why this matters for ad tracking in our post on why embedded booking forms show conversions as direct traffic.
The two things HubSpot rewrites in your snippet
HubSpot's rich text editor normalises HTML on every save. It does two things that break embeds silently.
Width attributes. width="100%" gets rewritten to whatever pixel width the editor canvas was when you saved — 560px is the most common result. On a mobile screen, that overflows the container. Editing the tag back does not hold; HubSpot overwrites it again next save. The durable fix is to set the width from JavaScript instead, because HubSpot leaves script bodies alone. If you are writing your own embed, add a line that sets iframe.style.width = '100%' on load. Cartoply's snippet does this automatically.
Script tags. Some HubSpot module types strip <script> on save depending on the portal's content security settings. It happens without an error message. Always reopen source view after saving and check the script is still there. If it was stripped, move the script to Settings → Advanced → Footer HTML. The iframe and the script do not need to be adjacent; a resize listener in the footer can find and target an iframe anywhere on the page.
Checking it actually worked before you publish
Do not rely on the in-editor preview. HubSpot's editor preview sometimes renders iframes differently from the published page. Use the full preview (the "Preview" button → "Preview in new tab") and check three things.
First, load the page on a phone-width viewport and confirm the form is not overflowing horizontally. Second, click through the booking flow all the way to a confirmed appointment and verify a confirmation appears inside the iframe — not a redirect to an external page. Third, if you are running paid traffic to this page, confirm that a booking fires a conversion event in your analytics. Schedulers that implement conversion tracking for embeds properly fire inside the host page's session, so the booking shows under the original ad campaign in GA4 rather than as direct traffic. If you see the booking land as direct, the script either was stripped or the scheduler is not sending postMessage events the host page can catch. For a deeper look at how this connects to paid campaigns, see our guide on connecting Stripe to your booking workflow — the attribution considerations are the same whether you are collecting payment or just tracking a lead.
If you are weighing up whether to stay with HubSpot Meetings or switch, Cartoply vs HubSpot Meetings walks through the feature differences without the sales pitch.
Frequently asked questions
Why does my HubSpot theme only offer Calendly and HubSpot Meetings?
That list is written into the theme, not into HubSpot. Agency-built themes commonly ship a hero or CTA module with a "conversion type" field whose choices are hardcoded — typically HubSpot Form, HubSpot Meeting Calendar, Calendly, and TypeForm. It is not a HubSpot standard and not a statement about what HubSpot supports. Three ways out, cheapest first: add a separate Custom HTML module next to that module; check whether the theme already includes a generic HTML module; or have a developer add a custom-embed option to the module in Design Manager. If the agency still deploys that theme from source control, editing the module in place will be overwritten on the next deploy — worth asking before anyone touches it.
Why is there a grey box and a big empty gap around my embedded form?
The embedded page is rendering as a full standalone page inside the iframe — its own background, its own outer padding, and a minimum height of 100vh. Stacked inside a card on your HubSpot page, that reads as a grey box with dead space beneath the last field. A scheduler that supports embedding properly drops that chrome when it detects it is framed. Cartoply renders transparent, unpadded, and at content height in embed mode, so the host page supplies the framing. If your scheduler does not, the fallback is to style the container and accept some padding, or ask the vendor for an embed parameter that strips the standalone shell.
Why did HubSpot change the width of my iframe?
HubSpot's rich text editor normalizes pasted HTML on save and rewrites width="100%" to whatever pixel width the editor canvas happened to be — 560px is common. On a phone that overflows the container. Editing the tag back does not hold; it is rewritten again on the next save. The durable fix is to set the width from JavaScript rather than the tag attribute, because HubSpot leaves script bodies alone. Cartoply's snippet handles this automatically. If you are hand-rolling an embed, add a line that sets the iframe's style.width to 100% on load.
HubSpot stripped the script out of my embed code. What now?
Some HubSpot fields allow <script> tags and some do not — it depends on the module type and portal settings. Always reopen source view after saving to check rather than assuming. If the script was stripped, put the iframe in the module and the script in Settings → Advanced → Footer HTML. They do not need to be adjacent; a resize listener in the footer can find and target an iframe anywhere on the page. A well-built snippet degrades gracefully in the meantime: the frame holds its starting height and shows an inner scrollbar rather than breaking the layout.
Why doesn't my embedded booking form resize as the visitor moves through it?
An iframe cannot measure its own content — the page inside has to post a message to the page outside declaring its height, and the outside page has to listen for it. If your snippet is just an <iframe> tag with a fixed height attribute, that conversation is not happening and the height is frozen. That matters because a calendar step and a details form can differ by several hundred pixels, so one screen always looks wrong. Also check the domain: if the scheduler's URL redirects (for example, from a bare domain to www), a postMessage listener comparing origins strictly will silently reject every resize message — and every conversion event along with it.
An embed that sizes itself and keeps your ad attribution.
14-day free trial — no credit card required. $7/seat/month after that.
Start free trial →Get field service tips in your inbox
Scheduling, dispatch, and territory strategy for home service teams. No spam, unsubscribe anytime.
By subscribing you agree to receive emails from Cartoply. Unsubscribe anytime. See our Privacy Policy.