Skip to page content
Docs
Make Agent Fast documentation

Vue and Nuxt

Mount the public loader once in a browser-only Vue component or Nuxt plugin.

At a glance

Mount the public loader once in a browser-only Vue component or Nuxt plugin.

Embed install pathLoader on your site talks to the hosted agent runtime
Your websiteHTML / appLoader scriptembed.jsWidget UIChat / voiceAgent

Prepare the embed#

Publish the site, enable embedding, and add the exact origin for local, preview, and production deployments. Decide whether the agent belongs to the whole application or only selected route components.

Nuxt site-wide plugin#

Create a .client.ts plugin so no DOM code runs during server rendering. Nuxt loads it once in the browser, which keeps the launcher and conversation stable across client navigation.

// plugins/make-agent-fast.client.ts
const slug = "YOUR_SITE_SLUG";

export default defineNuxtPlugin(() => {
  if (document.getElementById(`maf-embed-root-${slug}`)) return;

  const script = document.createElement("script");
  script.id = "maf-agent";
  script.src = "https://makeagent.fast/embed.js";
  script.dataset.agent = slug;
  script.dataset.position = "right";
  script.dataset.label = "Ask us";
  script.async = true;
  document.body.appendChild(script);
});

Do not put a secret in runtimeConfig.public; only the public site slug and visual settings belong in the browser. Real MAF API/provider keys stay in private server runtime configuration.

The site-wide plugin intentionally has no unmount cleanup: it belongs to the Nuxt application lifetime. During hot-module replacement in development, a prior root can remain until a full reload; the root guard prevents a second launcher. Verify final behavior with a clean production build rather than repeatedly editing the plugin in one long-lived tab.

Route-scoped Vue component#

For selected routes, mount in onMounted and remove both the script and generated root in onBeforeUnmount.

<script setup lang="ts">
import { onBeforeUnmount, onMounted } from "vue";

const slug = "YOUR_SITE_SLUG";
let script: HTMLScriptElement | null = null;

onMounted(() => {
  if (document.getElementById(`maf-embed-root-${slug}`)) return;
  script = document.createElement("script");
  script.id = "maf-agent";
  script.src = "https://makeagent.fast/embed.js";
  script.dataset.agent = slug;
  script.async = true;
  document.body.appendChild(script);
});

onBeforeUnmount(() => {
  script?.remove();
  document.getElementById(`maf-embed-root-${slug}`)?.remove();
});
</script>

Use one component owner. Multiple components with different slugs intentionally create multiple agents, which is rarely desirable.

If a Vue application switches authenticated tenants without a full page load, treat that as an explicit teardown/remount. Remove the old slug's root, validate the new tenant's public slug on trusted application state, then append a new script. Changing script.dataset.agent after the loader ran does not retarget the existing iframe.

Host security headers still apply to Nuxt/Vue output. Add the loader/frame origin to CSP and permit microphone only when voice is enabled; a client-only plugin cannot override a response-level browser policy.

Verify SSR and routing#

  1. Run the production Nuxt/Vue build and confirm no document is not defined error.
  2. Direct-load a route with the embed and confirm one root.
  3. Navigate client-side and confirm site-wide versus route-scoped behavior.
  4. Inspect embed.js, iframe, CSP, and exact origin.
  5. Send a message and test mobile/microphone behavior.

Troubleshooting#

SymptomFix
SSR crashesRename the Nuxt plugin to .client.ts or keep DOM work in onMounted
Launcher remains after leaving routeRemove the slug-specific root in onBeforeUnmount
Launcher resets on every routeUse the site-wide client plugin/layout instead of a page component
Preview domain failsAdd that exact HTTPS origin separately
Script is inserted twiceUse one stable owner and root/ID guard

No npm Vue/Nuxt adapter is currently published; this guide uses the supported hosted loader directly.