Embed Widget
Add a waitlist signup form to any website with one line of code.
MakeEmWait provides two embed variants: embed.js (styled, with Shadow DOM) and embed-plain.js (unstyled, no Shadow DOM). Both render a fully functional signup form wherever the script tag is placed.
Quick Start
Add this script tag anywhere on your page:
<script src="https://makeemwait.com/assets/js/embed.js"
data-waitlist-id="YOUR_WAITLIST_ID"></script>
The widget renders a complete signup form right where the script tag is placed.
Configuration
Customize the widget with data- attributes on the script tag:
| Attribute | Required | Default | Description |
|---|---|---|---|
data-waitlist-id |
Yes | — | Your waitlist ID (UUID, e.g., a1b2c3d4-e5f6-7890-abcd-ef1234567890) |
data-theme |
No | "dark" |
"dark", "light", "glass" (dark with blur effect), or "auto" (follows system preference) |
data-variant |
No | "full" |
Widget layout variant: "full" (default), "docked", or "mini" |
data-api-url |
No | https://makeemwait.com/api/v1 |
Override the API base URL |
data-compact |
No | — | Set to "true" for compact single-row layout |
Example with Light Theme
<script src="https://makeemwait.com/assets/js/embed.js"
data-waitlist-id="a1b2c3d4"
data-theme="light"></script>
Themes
The data-theme attribute controls the widget’s color scheme:
dark(default) — dark background with light text, suited for dark-themed siteslight— white background with dark text, suited for light-themed sitesglass— dark semi-transparent background with a 16px blur effect and a subtle indigo glow. Looks best when placed over an image or gradient background.auto— follows the visitor’s system color scheme preference via theprefers-color-schememedia query. Displays the light theme when the system is in light mode, and the dark theme when the system is in dark mode. This is the best choice when your site also adapts to the system preference.
Compact Mode
Set data-compact="true" to display the email input and submit button on the same row (side-by-side). This creates a more space-efficient layout that works well in tight spaces like headers, sidebars, and inline call-to-action sections. When the waitlist has name fields enabled, they appear below the compact row.
<script src="https://makeemwait.com/assets/js/embed.js"
data-waitlist-id="a1b2c3d4"
data-compact="true"></script>
You can combine compact mode with any theme:
<script src="https://makeemwait.com/assets/js/embed.js"
data-waitlist-id="a1b2c3d4"
data-theme="auto"
data-compact="true"></script>
How It Works
The embed widget:
- Creates a Shadow DOM container at the script tag’s location
- Fetches your waitlist config (headline, subheadline, field settings, custom questions)
- Renders the signup form with all your configured settings
- Handles submissions directly to the MakeEmWait API
- Shows the success state with position number after signup
Shadow DOM Isolation
The widget uses Shadow DOM (attachShadow({ mode: "open" })) to encapsulate all styles and markup. This means:
- Your site’s CSS cannot break the widget’s appearance
- The widget’s styles cannot leak into your page
- It works reliably on any site regardless of CSS framework
Features
The embed widget automatically supports:
- Email field (always shown)
- Name fields (shown based on your waitlist settings)
- Phone field — rendered based on the waitlist’s
phone_fieldsetting (hidden,optional, orrequired) - Custom questions — renders custom questions from the waitlist config, including text inputs, dropdowns, and checkboxes
- Consent checkbox — when
require_consentis enabled, shows an unchecked checkbox with your consent text. The submit button is disabled until the checkbox is checked. Supports markdown-style links in the consent text. - Social proof — when
show_social_proofis enabled (default), displays a message like “Hundreds are already in line” above the form based on the current signup count - Closed waitlist — when the waitlist status is
"closed", displays a “This waitlist is currently closed” message instead of the form - UTM passthrough — reads UTM parameters from the parent page URL and includes them with the signup
- Referral tracking — reads the
refparameter from the parent page URL and passes it asreferred_by_tokenin the signup request, so referrals from shared links are tracked automatically - Custom redirect URL — if the waitlist has a redirect URL configured, the widget redirects to it after signup with
position,referral_token, andtotal_signupsas query parameters
- Success state — shows “You’re on the list!” with position number, referral link, and social sharing buttons (when no custom redirect URL is set)
- Social sharing — after signup, the success state shows sharing buttons for X/Twitter, LinkedIn, and a copy-link button with pre-filled share text
- Returning visitor detection — returning visitors who previously signed up on this waitlist automatically see a “Welcome back!” screen with their current position and referral link instead of the signup form. A “Not you? Sign up” link lets them switch back to the form.
- Error handling — displays inline error messages
- Branding — shows “Powered by MakeEmWait” (hidden if branding is disabled)
- Responsive — adjusts to the container width with a max-width of 400px
Returning Visitor Detection
When someone signs up through embed.js, their email is saved in the browser’s localStorage under the key mew_embed_{waitlistId}. On subsequent visits, the widget detects the stored email and shows a “Welcome back!” screen instead of the signup form. The welcome-back screen displays:
- Their current position in line (fetched live from the API)
- Their referral link
- Social sharing buttons (X/Twitter, LinkedIn, Copy Link)
- A “Not you? Sign up” link that clears the stored email and shows the form again
This only applies to embed.js. The embed-plain.js variant does not store signup data or detect returning visitors.
Social Sharing
On successful signup (and on the welcome-back screen), embed.js displays sharing buttons for:
- X (Twitter) — opens a tweet composer with a pre-filled message and the referral link
- LinkedIn — opens the LinkedIn share dialog with the referral link
- Copy Link — copies the referral link to the clipboard with a “Copied!” confirmation
The share text includes the waitlist name when available (for example, “I just joined the Acme waitlist! Join too:”).
This only applies to embed.js. The embed-plain.js variant does not include social sharing buttons.
UTM Passthrough
The widget automatically reads UTM parameters from the parent page’s URL. If your page URL is:
https://yoursite.com/landing?utm_source=twitter&utm_campaign=launch
Those UTM values are included with every signup from the widget, so you can track which campaigns drive signups.
Cross-Origin Behavior
The widget works from any origin without CORS issues. All public API endpoints (/public/*) return Access-Control-Allow-Origin: *, so you can embed the script on any domain — your marketing site, a Webflow landing page, a Notion page, or anywhere else that allows custom script tags.
Placement Tips
- Place the script tag where you want the form to appear in the page flow
- The widget has a max-width of 400px and centers within its container
- It works inside columns, modals, sidebars, or any other layout
- Multiple widgets on the same page are supported (use different waitlist IDs)
Widget Style Customization
Beyond the built-in themes, you can fully customize the embed widget’s appearance using the widget_style object in your waitlist settings. Custom styles are applied within the Shadow DOM, so they override the theme defaults without affecting your host page.
API: PATCH /waitlists/{waitlist_id}
{
"settings": {
"widget_style": {
"background_color": "#1A1A2E",
"text_color": "#E0E0E0",
"button_color": "#6366F1",
"button_text_color": "#FFFFFF",
"accent_color": "#818CF8",
"input_background_color": "#16213E",
"border_color": "#334155",
"border_radius": 12,
"font_family": "Inter",
"logo_url": "https://example.com/logo.png"
}
}
}
Available Style Properties
| Property | Type | Description |
|---|---|---|
background_color |
hex color (e.g., #1A1A2E) |
Widget background color |
text_color |
hex color | Primary text color (labels, headings) |
button_color |
hex color | Submit button background color |
button_text_color |
hex color | Submit button text color |
accent_color |
hex color | Accent color for focus states and highlights |
input_background_color |
hex color | Background color for input fields |
border_color |
hex color | Border color for inputs and the widget container |
border_radius |
number (0-24) | Border radius in pixels for the widget container, inputs, and button |
font_family |
string | One of: Inter, Roboto, Open Sans, Lato, Montserrat, Poppins, Source Sans Pro, Nunito, Raleway, system-ui |
logo_url |
HTTPS URL or null |
URL of a logo image displayed in the widget. Must start with https://. |
All color values must be valid hex colors in the format #XXXXXX. The border_radius is a number (not a CSS string) between 0 and 24.
Custom styles are merged with the selected theme. Properties you set override the theme defaults; properties you omit use the theme’s values. This means you can start from a theme and tweak individual properties.
Example: Branded Widget
{
"settings": {
"widget_style": {
"button_color": "#FF6B00",
"button_text_color": "#FFFFFF",
"border_radius": 24
}
}
}
This keeps the rest of the dark theme defaults but gives the widget an orange button with rounder corners.
embed.js variant only. The unstyled embed-plain.js has no built-in styles, so you control everything with your own CSS.
Unstyled Variant: embed-plain.js
For full control over the form’s appearance, use embed-plain.js. It renders plain HTML with no Shadow DOM and no injected CSS. You provide all the styling yourself.
Quick Start
<script src="https://makeemwait.com/assets/js/embed-plain.js"
data-waitlist-id="YOUR_WAITLIST_ID"></script>
Configuration
embed-plain.js supports only two attributes:
| Attribute | Required | Default | Description |
|---|---|---|---|
data-waitlist-id |
Yes | — | Your waitlist ID (UUID, e.g., a1b2c3d4-e5f6-7890-abcd-ef1234567890) |
data-api-url |
No | https://makeemwait.com/api/v1 |
Override the API base URL |
There is no data-theme or data-compact attribute. Since there are no injected styles, themes are not applicable — you write all the CSS yourself.
How It Differs from embed.js
| Feature | embed.js | embed-plain.js |
|---|---|---|
| Shadow DOM | Yes | No |
| Injected CSS | Yes (built-in themes) | No (you provide all CSS) |
| Theme support | dark, light, glass, auto |
None |
| Compact mode | Yes (data-compact) |
No |
| Returning visitor detection | Yes (localStorage) | No |
| Social sharing buttons | Yes (X, LinkedIn, Copy Link) | No |
| Social proof text | Yes | No |
| Closed waitlist message | No dedicated message | No |
| Consent checkbox | Yes | No |
| Style isolation | Full (Shadow DOM) | None (host page CSS applies) |
| Custom questions | Yes | Yes |
| UTM passthrough | Yes | Yes |
| Referral tracking | Yes | Yes |
| Honeypot bot protection | Yes | Yes |
| Custom redirect URL | Yes | Yes |
| Branding (“Powered by”) | Yes | Yes |
No Shadow DOM
Because embed-plain.js does not use Shadow DOM, styles from the host page will apply to the widget’s elements. This is intentional — it lets the form inherit your site’s typography, colors, spacing, and overall design. It also means you need to style the form yourself, or it will appear as unstyled browser-default HTML.
Element IDs
All element IDs are suffixed with the waitlist ID to avoid conflicts when multiple forms exist on the same page. For example, if your waitlist ID is abc123:
mew-email-abc123mew-first-abc123mew-last-abc123mew-phone-abc123mew-submit-abc123mew-error-abc123mew-success-abc123mew-branding-abc123
CSS Classes Reference
These are the class names rendered by embed-plain.js. Use them in your CSS to style the form.
| Class | Element | Description |
|---|---|---|
.mew-embed |
<div> |
Outer container wrapping the entire widget |
.mew-form-section |
<div> |
Wrapper around the form (hidden on success) |
.mew-form |
<form> |
The form element itself |
.mew-field |
<div> |
Wrapper around each individual field (label + input pair) |
.mew-label |
<label> |
Field labels (Email, First name, Last name, Phone, custom question labels) |
.mew-input |
<input> |
Text, email, and tel input fields |
.mew-select |
<select> |
Dropdown select fields (for dropdown-type custom questions) |
.mew-name-row |
<div> |
Wrapper around the first name and last name fields. Contains two .mew-field children. Style with flexbox or grid for side-by-side layout. |
.mew-checkbox-field |
<div> |
Wrapper around checkbox-type custom questions (contains a checkbox input and label) |
.mew-checkbox |
<input> |
Checkbox inputs for checkbox-type custom questions |
.mew-submit |
<button> |
The submit button |
.mew-error |
<div> |
Error message container (hidden by default, shown when submission fails) |
.mew-success |
<div> |
Success state wrapper (hidden by default, shown after successful signup) |
.mew-branding |
<div> |
“Powered by MakeEmWait” link (hidden on Advanced+ with branding disabled) |
Example Styling
Here is a minimal example that styles the plain embed to match a clean, light form design:
<style>
.mew-embed {
max-width: 400px;
font-family: system-ui, sans-serif;
}
.mew-field {
margin-bottom: 0.75rem;
}
.mew-label {
display: block;
font-size: 0.875rem;
font-weight: 500;
margin-bottom: 0.25rem;
}
.mew-input, .mew-select {
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid #d1d5db;
border-radius: 6px;
font-size: 0.9rem;
box-sizing: border-box;
}
.mew-input:focus, .mew-select:focus {
outline: none;
border-color: #6366f1;
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);
}
.mew-name-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.75rem;
}
.mew-checkbox-field {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.mew-submit {
width: 100%;
padding: 0.625rem;
background: #6366f1;
color: #fff;
border: none;
border-radius: 6px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
}
.mew-submit:hover {
background: #818cf8;
}
.mew-submit:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.mew-error {
color: #ef4444;
font-size: 0.8rem;
margin-top: 0.5rem;
}
.mew-success {
text-align: center;
padding: 1rem 0;
}
.mew-branding {
text-align: center;
font-size: 0.7rem;
margin-top: 0.75rem;
}
.mew-branding a {
color: #9ca3af;
text-decoration: none;
}
</style>
<script src="https://makeemwait.com/assets/js/embed-plain.js"
data-waitlist-id="a1b2c3d4"></script>
Related
- HTML / Vanilla JS Integration — custom API integration beyond the embed widget
- React Integration — using the embed widget or API in React apps
- Signup Form — how signups work, validation, and duplicate behavior
- Creating Waitlists — configure what fields and options appear on the form