Skip to content
GitHub
Get started →

Install on Vue / Nuxt

Edit nuxt.config.ts and register the script in the global head:

nuxt.config.ts
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.

As a Vue plugin (optional)

If you want to control mount timing from inside Vue:

src/plugins/spelo.ts
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)
},
}
src/main.ts
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

ToolPrefixExample
Nuxt 3NUXT_PUBLIC_NUXT_PUBLIC_SPELO_SITE_ID
Vite (Vue)VITE_VITE_SPELO_SITE_ID
Vue CLIVUE_APP_VUE_APP_SPELO_SITE_ID

Verify

  1. npm run dev
  2. Hit the dev URL
  3. Gold orb at the bottom; click → allow mic → speak

Troubleshooting

  • Nuxt: script doesn’t show in <head> → make sure you edited nuxt.config.ts (not .nuxt/). Restart nuxt 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.