Embed overview
Add a floating agent to an existing website with a secure, framework-independent loader.
Add a floating agent to an existing website with a secure, framework-independent loader.
How the embed works#
embed.js adds one fixed launcher to the host document. It can preload the hidden iframe from https://makeagent.fast to evaluate page triggers before the first click; the visitor opens the full chat from the launcher or a trigger. Host CSS cannot restyle the chat. Changes to the host page run only through registered, owner-approved page-action handlers.
The loader is public and does not use an API key. Access is controlled by the agent's Show it on my website switch and the exact parent-origin allowlist (Allowed website addresses). The site slug is an identifier, not a secret.
Prerequisites#
Before copying code:
- Create and test an agent in the dashboard.
- Use the agent’s generated snippet; turning on its separate Agent link is not required.
- On the agent's Agent page, open Put it live → Website widget. If the widget is not on yet, choose Enable embed; then confirm Show it on my website is on.
- Under Allowed website addresses, add every parent origin that will render the launcher.
- Select Save embed settings, then copy the generated snippet.
An origin contains only the scheme, hostname, and optional port. It never contains a path. These are four different origins and must be added separately when you use them:
https://example.com
https://www.example.com
https://staging.example.com
http://localhost:3000Do not enter https://example.com/pricing, *.example.com, or a trailing wildcard. If production redirects from the bare domain to www, allowlist the origin that remains in the browser address bar after the redirect.
Install the loader#
Place one script before the closing </body> tag, or use the browser-only lifecycle recommended by your framework guide.
The Website widget sheet (Agent page → Put it live) copies this shape (site slug, position, optional label, and the ?v= cache-buster). Keep async. Keep the ?v= query from the snippet so hosts do not pin a stale loader.
<script
src="https://makeagent.fast/embed.js?v=20261022-open"
data-agent="YOUR_SITE_SLUG"
data-position="right"
async
></script>Only data-agent is required. Optional attributes the loader actually reads:
<script
src="https://makeagent.fast/embed.js?v=20261022-open"
data-agent="YOUR_SITE_SLUG"
data-position="right"
data-label="Ask us"
data-accent="#6d5ce7"
data-locale="en"
data-theme="light"
async
></script>Do not put a MAF API key, provider key, connector token, visitor identity, or private customer data in any data-* attribute. Do not invent attributes such as data-api-key, data-z-index, data-offset, or data-delay. data-maf-bootstrapped is set by the loader.
Configure attributes#
Read from the embed.js tag only. The iframe accepts hex accents only.
| Attribute | Accepted value | Default | Effect |
|---|---|---|---|
data-agent | Agent site slug | Required | Selects the site and agent. Missing → console warn, no launcher |
data-position | bottom-left, bottom-right, top-left, top-right (left / right still mean the bottom corners) | right (bottom-right) | Anything else is treated as bottom-right |
data-label | Plain text | Icon only | Visible launcher text and accessible name. Escape ", <. The dashboard UI caps at 40 characters |
data-accent | #RGB or #RRGGBB | Saved site appearance | Host override for the launcher; non-hex values are ignored in the iframe |
data-locale | en, ko, uz, or ru | Agent primary language | Agent's opening language on this host page, chosen from its enabled languages |
data-theme | light or dark | Host background, else OS | Other values are ignored |
data-auto-form-error | true | Off | Opt in to form-error trigger events; reports form ID, never field values |
data-analytics | off (also false, 0, no) | On | Use when your visitor has not consented to analytics: the chat frame loads no page analytics and sends no view beacon. Chat itself still works |
The generated root also uses data-maf-open internally to track whether the chat is open. It is not a script-tag setting or a public command to open the widget. See Follow-ups for trigger behavior.
Without data-theme, the loader samples the host background and then falls back to the visitor's OS preference. It also passes the host font family to the frame and fetches the latest launcher appearance. A failed appearance request does not block the launcher; it keeps the safe default style. Display changes in the dashboard refresh this fetch without a site republish.
Runtime behavior#
- Load the script once per document. Repeating the same slug is idempotent and still produces one
maf-embed-root-YOUR_SITE_SLUGroot. - Different agents may coexist on one document. The loader marks each processed script with
data-maf-bootstrappedso an async fallback initializes every distinctdata-agenttag exactly once. - The iframe can preload for page triggers. It stays hidden until a trigger appears or the visitor opens chat; sessions that already used a trigger keep the lazy-open path. Microphone, autoplay and clipboard-write remain subject to the browser's iframe permission model.
- In a client-side routed app, mount the loader in the highest layout that should own it so route changes do not reload the conversation.
- Removing only the script element does not remove an already-created launcher. For route-specific teardown, also remove the matching
maf-embed-root-...element. Reload the script after teardown to mount it again. - The frame and loader exchange namespaced lifecycle, identity, trigger and page-action messages. The loader rejects messages that do not come from the Make Agent Fast origin and current site slug.
Verify the installation#
Test the published page, not only a website-builder editor preview:
- Open the deployed URL in a private window and confirm its exact origin is allowlisted.
- Confirm
https://makeagent.fast/embed.js?v=20261022-openreturns200in the Network panel. - Confirm a single element with
data-maf-embed="YOUR_SITE_SLUG"exists. - Open the launcher and confirm the iframe request to
/embed/YOUR_SITE_SLUGsucceeds. - Send a realistic question and confirm it appears in Conversations.
- Test a narrow mobile viewport and, if enabled, microphone permission.
Diagnose a missing launcher#
| Symptom | Likely cause | Fix |
|---|---|---|
Console warns missing data-agent | The slug attribute is absent or on a different script | Put data-agent on the embed.js tag |
embed.js is blocked | CSP or a consent manager rejected the script | Allow the script origin or load it after the required consent |
| Launcher appears but the frame refuses to load | Embedding is off or parent origin differs | Recheck Show it on my website and Allowed website addresses in the dashboard |
| Works on localhost but not production | Only the development origin is allowlisted | Add the exact deployed HTTPS origin |
| Two different agents appear | The document loads two different slugs | Keep only the intended site slug |
| Chat opens but voice does not | Browser permission or Permissions Policy blocks microphone | Follow Security and CSP |
Choose an installation guide#
Use HTML and JavaScript for a normal script tag. For React, Vue, SvelteKit, Astro, WordPress, Shopify, Webflow, Framer, Wix, Squarespace, or Ghost, choose the matching guide in the sidebar. Platforms that do not allow arbitrary JavaScript, such as many Notion and Linktree surfaces, can link to the agent’s Agent link — one public chat page at the agent's own address, turned on in the final onboarding step (Test on your phone) and on the Agent page's Display tab. A customer website with the embed is another option.
For coding agents#
Installing this on a customer site with Claude Code, Cursor, or Codex? Copy skills/embed-agent/SKILL.md from the Make Agent Fast repository into .cursor/skills/embed-agent/ or .claude/skills/embed-agent/. That file is the install recipe (attributes, CSP, placement). This page remains the human guide.