Many “vue chatbot” tutorials show how to build a chat app from scratch with the OpenAI API. That’s a good weekend project, but then you also own retrieval over your docs, storage, rate limits and handoff to a human. If you need a working assistant on an existing Vue site, embed one. Below is how with Feedbot (our product).
What you need
- A Feedbot bot id from Dashboard → Bot → Install (the Free plan works).
- A Vue 3 app (Vite) or a Nuxt 3/4 app. Vue 2 works the same with the script tag.
Option 1: script tag in index.html
-
Open
index.htmlat the root of your Vite project. -
Paste before
</body>:<script src="https://w.feedbotai.com/v1/feedbot.js" data-bot-id="YOUR_BOT_ID" async></script> -
Run
npm run dev. A chat button appears in the corner. Ask it a question to check.
That’s the whole install. It loads about 6 KB gzipped and fetches the chat only when the visitor hovers or clicks, or when the browser is idle.
Option 2: load it from a composable
Use this when the bot id comes from an environment variable or you want to load the chat only after login.
type FeedbotFn = ((...args: unknown[]) => unknown) & { q?: unknown[] };declare global { interface Window { Feedbot: FeedbotFn } }
export function useFeedbot() { // Queue stub: calls made before the loader finishes are replayed. window.Feedbot = window.Feedbot || function (...args: unknown[]) { (window.Feedbot.q = window.Feedbot.q || []).push(args); };
function load(botId: string) { if (document.querySelector("script[data-bot-id]")) return; const s = document.createElement("script"); s.src = "https://w.feedbotai.com/v1/feedbot.js"; s.async = true; s.dataset.botId = botId; document.body.appendChild(s); }
const call = (...args: unknown[]) => window.Feedbot(...args); return { load, call };}<script setup lang="ts">import { onMounted } from "vue";import { useFeedbot } from "./composables/useFeedbot";
const feedbot = useFeedbot();onMounted(() => feedbot.load(import.meta.env.VITE_FEEDBOT_BOT_ID));</script>
<template> <RouterView /> <button @click="feedbot.call('open')">Chat with us</button></template>The loader ignores a second copy of itself, so remounting App.vue in development is harmless.
Nuxt
Add the script globally in nuxt.config.ts, using the app.head option:
export default defineNuxtConfig({ app: { head: { script: [ { src: "https://w.feedbotai.com/v1/feedbot.js", async: true, "data-bot-id": "YOUR_BOT_ID" }, ], }, },});To load it only in one layout or page, use useHead() there instead, with tagPosition: "bodyClose":
<script setup lang="ts">useHead({ script: [{ src: "https://w.feedbotai.com/v1/feedbot.js", async: true, "data-bot-id": "YOUR_BOT_ID", tagPosition: "bodyClose", }],});</script>Call window.Feedbot only on the client, for example in onMounted, since it doesn’t exist during server rendering.
Open the chat from a button
| Command | What it does |
|---|---|
Feedbot("open") / Feedbot("close") / Feedbot("toggle") |
Show or hide the chat |
Feedbot("sendMessage", "How do refunds work?") |
Open the chat and send the text as the visitor |
Feedbot("setMetadata", { plan: "pro" }) |
Attach context to the conversation |
Feedbot("on", "message", cb) |
Listen to ready, open, close, message |
The full list is in the JavaScript API docs.
Identify signed-in users
Watch your auth store and call identify with a hash your backend computes:
import { watch } from "vue";
watch(() => auth.user, (user) => { if (user) { window.Feedbot("identify", { userId: user.id, email: user.email, name: user.name, hash: user.feedbotHash, // HMAC-SHA256(identitySecret, user.id), from your API }); } else { window.Feedbot("reset"); // logout: forget the visitor on this device }}, { immediate: true });Never compute the hash in the browser: the identity secret must stay on your server. In Nuxt you can compute it in a server route (server/api/). Code for Node, Python and PHP is in Identify users.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| No chat button | Bot id is empty | Vite only exposes env variables prefixed with VITE_. Restart the dev server after editing .env. |
window.Feedbot is not a function |
Called before the stub exists | Add the queue stub (see the composable) before your first call. |
window is not defined in Nuxt |
Called during server rendering | Move the call into onMounted or a .client plugin. |
| Requests rejected | Domain not in Allowed domains | Add localhost and your domain in Bot → Install → Allowed domains. |
| Blocked by CSP | Strict policy | Allow https://w.feedbotai.com in script-src and https://api.feedbotai.com in connect-src. |
Train it on your content
On Free, add text and FAQ. From Starter, import your site by URL or sitemap (pages rendered by Vue in the browser are read with a real browser) and upload PDF, DOCX or Markdown. See knowledge base. For questions the bot can’t answer, it hands off to you in Telegram, Slack, Discord or email: handoff docs.
Next steps
- Install docs for inline mode and all
data-*options. - Using React or Next.js too? See React and Next.js.