Developer resources
The Makeform embed SDK lets you control embedded forms, popups, and sliders with JavaScript for free on every plan. Get your form embed from Share > Embed Form, then use the API methods below.
Makeform is a free AI form builder: describe what you want to collect and it builds the form for you, with unlimited forms and submissions on the free plan.
Including the SDK
Add the embed script to your page:
<script async src="https://www.makeform.ai/widgets/embed.js"></script>The script exposes the global MakeForm object. It can be placed in the <head> or before </body>. It initializes existing data-makeform-src, data-makeform-popup, data-makeform-slider, and auto-open configuration when the DOM is ready.
API methods
MakeForm.loadEmbeds()
Scans the DOM for elements with data-makeform-src and initializes them as embedded forms.
MakeForm.loadEmbeds();Call this after dynamically adding embed elements to the page (e.g., after SPA navigation).
MakeForm.loadPopups()
Scans for elements with data-makeform-popup and attaches click handlers.
MakeForm.loadPopups();MakeForm.loadSliders()
Scans for elements with data-makeform-slider and attaches click handlers.
MakeForm.loadSliders();MakeForm.loadAutoOpen()
Processes window.MakeFormConfig and window.MakeFormConfigs to set up auto-open triggers.
MakeForm.loadAutoOpen();MakeForm.openPopup(formId, options?)
Opens a popup modal programmatically.
MakeForm.openPopup("YOUR_FORM_ID", {
width: 500,
position: "bottom-right",
overlay: false,
initialBgColor: "#ffffff",
hiddenFields: { user_id: "123" },
dispatchEvents: true,
autoCloseMs: 3000,
onOpen: ({ formId }) => console.log("Opened:", formId),
onReady: ({ formId }) => console.log("Ready:", formId),
onSubmit: ({ formId, data }) => console.log("Submitted:", data),
onClose: ({ formId }) => console.log("Closed:", formId)
});MakeForm.closePopup()
Closes the currently open popup.
MakeForm.closePopup();MakeForm.openSlider(formId, options?)
Opens a slider panel programmatically. Accepts the same options as openPopup, plus a position option for slider side.
MakeForm.openSlider("YOUR_FORM_ID", {
width: 400,
position: "left",
onSubmit: ({ formId, data }) => {
console.log("Feedback received:", data);
}
});MakeForm.closeSlider()
Closes the currently open slider.
MakeForm.closeSlider();MakeForm.registerAutoOpen(config)
Registers a single auto-open configuration at runtime. Useful for dynamically adding forms after the SDK has loaded.
MakeForm.registerAutoOpen({
formId: "YOUR_FORM_ID",
popup: {
width: 500,
open: { trigger: "time", ms: 5000 }
}
});ModalOptions
Options object for openPopup() and openSlider():
interface ModalOptions {
type?: 'embed' | 'form'; // 'embed' uses /e/ route, 'form' uses /f/ route
embedUrl?: string; // Pre-built embed URL; preserves its origin
hiddenFields?: Record<string, string | number | boolean | null>;
width?: number; // Modal width in px (360–800)
position?: string; // Popup: 'center' | 'bottom-right'; Slider: 'left' | 'right'
overlay?: boolean; // Show dark backdrop (popup only)
initialBgColor?: string; // CSS color to prevent white flash
onOpen?: (payload: { formId: string }) => void;
onReady?: (payload: { formId: string }) => void;
onSubmit?: (payload: { formId: string; data: Record<string, any> }) => void;
onClose?: (payload: { formId: string }) => void;
dispatchEvents?: boolean; // Dispatch CustomEvents on window
autoCloseMs?: number | null; // Auto-close delay in ms (0–30000)
}| Option | Type | Description | Default |
|---|---|---|---|
type |
'embed' | 'form' |
Route type: embed = /e/, form = /f/ |
'embed' |
embedUrl |
string |
Pre-built embed URL. Useful when you need to preserve a generated URL or custom origin | — |
hiddenFields |
object |
Key-value pairs passed as URL parameters | — |
width |
number |
Modal width in pixels, clamped to 360–800 | Popup CSS default, slider 500 |
position |
string |
Popup: 'center' or 'bottom-right'. Slider: 'left' or 'right' |
Popup: 'center', Slider: 'right' |
overlay |
boolean |
Show dark backdrop behind popup. Center always shows overlay; bottom-right defaults to off | Popup center: true, bottom-right: false |
initialBgColor |
string |
Initial background color, if valid CSS color | — |
onOpen |
function |
Called when the modal opens | — |
onReady |
function |
Called when the form loads inside the modal | — |
onSubmit |
function |
Called on successful submission, receives form data | — |
onClose |
function |
Called when the modal closes | — |
dispatchEvents |
boolean |
Enable CustomEvent dispatching on window | false |
autoCloseMs |
number | null |
Auto-close delay after submit (0–30000ms) | null |
Auto-open configuration
window.MakeFormConfig
Configure a single auto-open form:
interface MakeFormConfig {
formId: string; // Form ID (8–15 alphanumeric chars + hyphens)
embedUrl?: string; // Optional pre-built embed URL
popup?: AutoOpenEntry; // Popup auto-open config
slider?: AutoOpenEntry; // Slider auto-open config
}
interface AutoOpenEntry {
width?: number; // Modal width (360–800)
position?: string; // Popup: 'center' | 'bottom-right'; Slider: 'left' | 'right'
overlay?: boolean; // Show dark backdrop (popup only)
showOnce?: boolean; // Show only once per visitor
doNotShowAfterSubmit?: boolean; // Don't show after submission
autoClose?: number; // Auto-close delay in ms (0–30000)
hiddenFields?: Record<string, string | number | boolean>;
dispatchEvents?: boolean; // Enable CustomEvents
bgColor?: string; // Initial background color
open?: { // Trigger config (omit for page load)
trigger: 'time' | 'exit' | 'scroll';
ms?: number; // For 'time': delay in ms (500–120000)
scrollPercent?: number; // For 'scroll': percentage (1–100)
};
}window.MakeFormConfigs
Array of configurations for multiple forms (max 20):
window.MakeFormConfigs = [
{
formId: "FORM_1",
popup: {
width: 500,
showOnce: true,
open: { trigger: "time", ms: 5000 }
}
},
{
formId: "FORM_2",
slider: {
width: 400,
doNotShowAfterSubmit: true,
open: { trigger: "scroll", scrollPercent: 75 }
}
}
];Framework examples
React / Next.js
'use client';
import { useEffect, useRef } from 'react';
import Script from 'next/script';
export default function EmbeddedForm({ formId }: { formId: string }) {
const containerRef = useRef<HTMLDivElement>(null);
const handleScriptLoad = () => {
if (typeof MakeForm !== 'undefined') {
MakeForm.loadEmbeds();
}
};
return (
<>
<Script
src="https://www.makeform.ai/widgets/embed.js"
onLoad={handleScriptLoad}
/>
<div ref={containerRef}>
<iframe
data-makeform-src={`https://www.makeform.ai/e/${formId}`}
data-makeform-auto-resize
data-makeform-events
loading="lazy"
style={{ width: '100%', height: '200px', border: 0 }}
title="Makeform form"
/>
</div>
</>
);
}Opening a popup programmatically in React:
'use client';
export default function PopupButton({ formId }: { formId: string }) {
const openForm = () => {
if (typeof MakeForm !== 'undefined') {
MakeForm.openPopup(formId, {
width: 500,
onSubmit: ({ data }) => {
console.log('Submitted:', data);
}
});
}
};
return <button onClick={openForm}>Open Form</button>;
}Vue
<template>
<div>
<iframe
:data-makeform-src="`https://www.makeform.ai/e/${formId}`"
data-makeform-auto-resize
data-makeform-events
loading="lazy"
:style="{ width: '100%', height: '200px', border: 0 }"
title="Makeform form"
/>
</div>
</template>
<script setup>
import { onMounted, defineProps } from 'vue';
const props = defineProps({ formId: String });
onMounted(() => {
const script = document.createElement('script');
script.src = 'https://www.makeform.ai/widgets/embed.js';
script.onload = () => {
if (typeof MakeForm !== 'undefined') {
MakeForm.loadEmbeds();
}
};
document.body.appendChild(script);
});
</script>Opening a popup in Vue:
<template>
<button @click="openForm">Open Form</button>
</template>
<script setup>
const props = defineProps({ formId: String });
const openForm = () => {
if (typeof MakeForm !== 'undefined') {
MakeForm.openPopup(props.formId, {
width: 500,
onSubmit: ({ data }) => console.log('Submitted:', data)
});
}
};
</script>Vanilla JS
<!DOCTYPE html>
<html>
<head>
<title>My Form</title>
</head>
<body>
<iframe
data-makeform-src="https://www.makeform.ai/e/YOUR_FORM_ID"
data-makeform-auto-resize
data-makeform-events
loading="lazy"
style="width: 100%; height: 200px; border: 0;"
title="Contact Form"
></iframe>
<button
data-makeform-popup="https://www.makeform.ai/e/YOUR_FORM_ID"
data-makeform-width="500"
data-makeform-events
>
Open Popup
</button>
<button
data-makeform-slider="https://www.makeform.ai/e/YOUR_FORM_ID"
data-makeform-width="400"
>
Open Slider
</button>
<script async src="https://www.makeform.ai/widgets/embed.js"></script>
</body>
</html>Programmatic popup with vanilla JS:
document.getElementById('my-button').addEventListener('click', () => {
MakeForm.openPopup('YOUR_FORM_ID', {
width: 500,
hiddenFields: { source: 'landing-page' },
onSubmit: ({ data }) => {
alert('Thank you for your submission!');
console.log(data);
}
});
});SPA considerations
In single-page applications, the SDK initializes on first page load but won't automatically detect new embed elements added during client-side navigation.
After adding new embeds dynamically, call the appropriate load method:
// After navigating to a page with an inline embed
MakeForm.loadEmbeds();
// After navigating to a page with popup triggers
MakeForm.loadPopups();
// After navigating to a page with slider triggers
MakeForm.loadSliders();
// After adding or changing window.MakeFormConfig / window.MakeFormConfigs
MakeForm.loadAutoOpen();React example — reload embeds on route change:
import { useEffect } from 'react';
import { usePathname } from 'next/navigation';
export function MakeFormLoader() {
const pathname = usePathname();
useEffect(() => {
if (typeof MakeForm !== 'undefined') {
MakeForm.loadEmbeds();
MakeForm.loadPopups();
MakeForm.loadSliders();
MakeForm.loadAutoOpen();
}
}, [pathname]);
return null;
}Event quick reference
For detailed event documentation, see Handle Form Events.
PostMessage events
| Event | Description |
|---|---|
MakeForm.Loaded |
Form iframe loaded |
MakeForm.SubmitSuccess |
Form submitted successfully |
MakeForm.SetHeight |
Content height changed (internal) |
MakeForm.LayoutReady |
First stable layout height is ready (internal) |
MakeForm.SetBackgroundColor |
Background color determined (internal) |
MakeForm.Submitted |
Payload-free submit signal for safe auto-close (internal) |
Custom DOM events
| Event | Detail | Fires when |
|---|---|---|
MakeForm:open |
{ formId } |
Popup/slider opens |
MakeForm:ready |
{ formId } |
Form iframe reports loaded |
MakeForm:submit |
{ formId, data } |
Form submitted |
MakeForm:close |
{ formId } |
Popup/slider closes |
URL parameters
| Parameter | Description |
|---|---|
mk-rm-bg=true |
Remove form background (transparent) |
mk-align-left=1 |
Align supported embedded form content to the left |
mf_locale={locale} |
Request a runtime locale for system copy and paid translation overlays |
__mf_emitEvents=1 |
Enable postMessage events on full page (/f/) route |
{fieldName}={value} |
Set hidden field values |
Troubleshooting
Form not loading
- Verify the form ID is correct and the form is published
- Check that
embed.jsis loaded (look for the script in the Network tab) - Look for errors in the browser console
- Ensure your content security policy allows iframes from
makeform.ai
Height not adjusting
- Add
data-makeform-auto-resizeto the iframe element - Use the
/e/{formId}route for inline embeds - The SDK uses
ResizeObserverto detect content changes automatically - If content is loaded asynchronously inside the form, height updates when the content renders
Events not firing
- For inline embeds: add
data-makeform-eventsto the iframe - For popups/sliders: add
data-makeform-eventsto the trigger or setdispatchEvents: true - For full page embeds: append
__mf_emitEvents=1to the URL - Listen for
MakeForm:*CustomEvents unless you specifically need rawpostMessagepayloads
Popup/slider not opening
- Ensure the form ID matches the pattern: 8-15 alphanumeric characters and hyphens
- Check that
embed.jshas loaded before callingMakeForm.openPopup() - On SPAs, call
MakeForm.loadPopups()after adding trigger elements - For auto-open snippets, call
MakeForm.loadAutoOpen()after changingwindow.MakeFormConfig
Related
- Embed Your Form — Overview of all embed types
- Hidden Fields — Pass data into forms via URL parameters
- Handle Form Events — Complete event documentation