Nexoply

How-to guides

How to add an AI chatbot to a Vue or Nuxt app

Add an AI chatbot to a Vue 3 (Vite) or Nuxt 3 app with one script tag: index.html, onMounted, nuxt.config.ts or useHead. No npm package needed.

Updated September 30, 2026 5 min read

In short

Nexoply is one script tag, not an npm package. In a Vue 3 app built with Vite, paste it into index.html just before </body>, or add it from App.vue in onMounted. In Nuxt 3, add it to app.head.script in nuxt.config.ts with tagPosition: "bodyClose", or with useHead in app.vue. It runs only in the browser, survives Vue Router navigation and keeps its styles separate from yours in a Shadow DOM.

  • No plugin or npm package: the widget is always https://nexoply.com/widget.js with a data-chatbot attribute holding your key.
  • Vue 3 (Vite): index.html before </body> is simplest; onMounted in App.vue works when the key comes from an env var.
  • Nuxt 3: app.head.script in nuxt.config.ts, or useHead in app.vue. It's SSR-safe because it only runs in the browser.
  • Loading it twice is harmless: it mounts once per chatbot key, so hot reload and repeated mounts don't create a second button.
  • Open the chat from your own button with window.dispatchEvent(new Event("nexoply:open-chat")).

Before you start

You need a Nexoply account and your chatbot's key. Sign up free (the Free plan includes 100 conversations a month, no card needed), add the business's information or import it from its website, then open Chatbot in the dashboard and copy the install code. It looks like this:

<script src="https://nexoply.com/widget.js" data-chatbot="YOUR-KEY" async></script>

The value of data-chatbot is your key. It's public, not a secret: it only tells the widget which business it belongs to, so it's fine in client-side code and in your repository. Keep the attribute name and a src containing widget.js exactly as shown, because the widget reads its settings from its own script tag.

Vue 3 (Vite): index.html or App.vue

The simplest option is to paste the tag into index.html at the root of your project, just before </body>. It loads asynchronously and never blocks rendering:

<body>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
  <script src="https://nexoply.com/widget.js" data-chatbot="YOUR-KEY" async></script>
</body>

Prefer to add it from code, for example to read the key from an env var or to load it only after a visitor accepts your consent banner? Create the script tag in onMounted in App.vue. Put the key in .env as VITE_NEXOPLY_KEY=YOUR-KEY:

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

onMounted(() => {
  // Already on the page? Nothing to do.
  if (document.querySelector("script[data-chatbot]")) return;
  const s = document.createElement("script");
  s.src = "https://nexoply.com/widget.js";
  s.async = true;
  s.dataset.chatbot = import.meta.env.VITE_NEXOPLY_KEY;
  document.body.appendChild(s);
});
</script>

Nuxt 3: nuxt.config.ts or useHead

In Nuxt, add the script site-wide in nuxt.config.ts. tagPosition: "bodyClose" places it just before </body>:

export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          src: "https://nexoply.com/widget.js",
          async: true,
          "data-chatbot": "YOUR-KEY",
          tagPosition: "bodyClose",
        },
      ],
    },
  },
});

Or add it with useHead in app.vue. If you'd rather keep the key in an env var, declare runtimeConfig: { public: { nexoplyKey: "" } } in nuxt.config.ts and set NUXT_PUBLIC_NEXOPLY_KEY; otherwise just write the key in place:

<script setup lang="ts">
useHead({
  script: [
    {
      src: "https://nexoply.com/widget.js",
      async: true,
      "data-chatbot": useRuntimeConfig().public.nexoplyKey,
      tagPosition: "bodyClose",
    },
  ],
});
</script>

Server rendering is fine: Nuxt renders the tag in the HTML, and the widget only runs in the browser. It doesn't touch your app's markup, so there are no hydration mismatches.

How it behaves in a Vue app

  • Outside your app. It mounts on document.body, outside #app (or Nuxt's root), so re-renders, layout changes and route changes never remove it.
  • Vue Router navigation. The conversation continues while visitors move between pages client-side, and page rules (such as a side tab only on /pricing) are checked again when the URL changes, with no extra code.
  • Shadow DOM. Your CSS, Tailwind classes or UI library don't leak into the chat, and its styles don't leak into your app.
  • Light footprint. It loads asynchronously, sets no cookies, and stores only an anonymous visitor id in localStorage and the current conversation in sessionStorage.

Open the chat from your own button

Want a "Questions? Ask us" button in your hero section or pricing table? Dispatch the nexoply:open-chat event from a click handler:

<script setup lang="ts">
function openChat() {
  window.dispatchEvent(new Event("nexoply:open-chat"));
}
</script>

<template>
  <button type="button" @click="openChat">Ask us a question</button>
</template>

To open the chat as soon as the page loads, add data-open="true" to the script tag (or "data-open": "true" in Nuxt).

Local testing, allowed websites and troubleshooting

  • Allowed websites. If you filled in Only allow on these websites on the Chatbot page, add your dev host with its port too: localhost:5173 for Vite, localhost:3000 for Nuxt. Or leave the list empty while testing.
  • Content-Security-Policy. If your app sends a CSP header, allow https://nexoply.com in script-src, connect-src and img-src.
  • Test it. Run the dev server, open the app, ask a real question, and check that the conversation appears under Conversations in the dashboard.

If the button doesn't appear:

  • Check the tag. In your browser's dev tools, look for a script with a data-chatbot attribute and a src containing widget.js. If it's missing, the key may be empty: check that VITE_NEXOPLY_KEY or NUXT_PUBLIC_NEXOPLY_KEY is set, and restart the dev server after editing .env.
  • Check the console and network tab. A CSP error means nexoply.com isn't allowed yet; a blocked request can also come from an ad blocker, so try a private window without extensions.
  • Check the dashboard. Make sure the Chatbot enabled switch is on and your domain (or localhost with its port) is in the allowed list, if you use one.
  • Hidden on purpose? A page rule set to "No button" hides it on matching pages.

Next steps: customize it without touching code

Once the tag is in, everything else happens in the dashboard, and changes reach the site within about a minute, with no redeploy. Under Chatbot → Customize you can style the message button (icon or your own image, label, shape, size, colours, position) or use a side tab on the edge of the screen instead. Set a different look on phones, and use page rules to change or hide the button on chosen pages (for example /blog/*). Style the chat window to match the brand and add start-screen buttons like Book, Call or WhatsApp.

See how it works and the features, or compare plans. Building with another framework? There are guides for React and Next.js.

Frequently asked questions

Is there a Vue plugin or npm package?

No, and you don't need one. The widget is a single script, https://nexoply.com/widget.js, with your key in a data-chatbot attribute. Add it in index.html, onMounted, nuxt.config.ts or useHead; all settings live in the dashboard.

Does it work with Vue Router?

Yes. It mounts outside your app, keeps the conversation while visitors navigate client-side, and re-checks page rules when the URL changes, with no extra code.

Does it work with Nuxt SSR?

Yes. Render the script tag normally with nuxt.config.ts or useHead. The widget only runs in the browser and doesn't touch Nuxt's markup, so there are no hydration issues.

Can I show it only on some pages?

Yes, with page rules: dashboard → Chatbot → Customize → Message button → Different on some pages. Choose "No button" for pages where it should be hidden. There's no API to remove the widget once loaded, so page rules are the way to do it.

Can I open the chat from my own button?

Yes. Call window.dispatchEvent(new Event("nexoply:open-chat")) from any click handler.

Let your website answer the questions for you

Add your business info, test your assistant, and put it on your website - all on the free plan.