Install on Vue / Nuxt
Edit nuxt.config.ts and register the script in the global head:
export default defineNuxtConfig({ app: { head: { script: [ { src: 'https://spelo.ai/spelo.js', 'data-site-id': 'YOUR_SITE_ID', async: true, }, ], }, },})Nuxt 3 will render this <script> tag into the <head> on every page. Since the attribute is async, it won’t block rendering.
Open index.html and paste before </body>:
<body> <div id="app"></div> <script type="module" src="/src/main.ts"></script>
<script src="https://spelo.ai/spelo.js" data-site-id="YOUR_SITE_ID" async ></script></body>Open public/index.html and paste before </body>:
<body> <div id="app"></div>
<script src="https://spelo.ai/spelo.js" data-site-id="YOUR_SITE_ID" async ></script></body>As a Vue plugin (optional)
If you want to control mount timing from inside Vue:
import type { App } from 'vue'
interface Options { siteId: string}
export default { install(_app: App, options: Options) { if (typeof window === 'undefined') return if (document.querySelector(`script[data-site-id="${options.siteId}"]`)) return
const s = document.createElement('script') s.src = 'https://spelo.ai/spelo.js' s.setAttribute('data-site-id', options.siteId) s.async = true document.body.appendChild(s) },}import { createApp } from 'vue'import App from './App.vue'import Spelo from './plugins/spelo'
createApp(App) .use(Spelo, { siteId: import.meta.env.VITE_SPELO_SITE_ID }) .mount('#app')Vue Router
Vue Router uses history.pushState for navigation. The widget auto-detects route changes and re-scrapes the DOM. Nothing to wire up.
Nuxt SSR considerations
The widget is a client-only script. On SSR (Nuxt server rendering), it will not execute — nuxt.config.ts injects it into the head but the browser is what actually runs it. No hydration issues.
If you need to gate it server-side (e.g. “only for authenticated users”), use a Nuxt middleware + useHead:
<script setup lang="ts">const auth = useAuth()
useHead({ script: auth.isLoggedIn.value ? [{ src: 'https://spelo.ai/spelo.js', 'data-site-id': 'YOUR_SITE_ID', async: true }] : [],})</script>Environment variables
| Tool | Prefix | Example |
|---|---|---|
| Nuxt 3 | NUXT_PUBLIC_ | NUXT_PUBLIC_SPELO_SITE_ID |
| Vite (Vue) | VITE_ | VITE_SPELO_SITE_ID |
| Vue CLI | VUE_APP_ | VUE_APP_SPELO_SITE_ID |
Verify
npm run dev- Hit the dev URL
- Gold orb at the bottom; click → allow mic → speak
Troubleshooting
- Nuxt: script doesn’t show in
<head>→ make sure you editednuxt.config.ts(not.nuxt/). Restartnuxt dev. - Widget disappears on route change → it shouldn’t, but if it does, make sure the
<script>is rendered on every page (not scoped to a single route). - SSR hydration warnings mentioning the widget → shouldn’t happen (the widget lives outside Vue’s tree). If you see one, file an issue with a minimal repro.