Add a Voice AI Agent to Nuxt (app.head Guide)
Add the AnveVoice voice agent to Nuxt 4 with app.head in nuxt.config.ts or useHead in app.vue, using async and tagPosition bodyClose, with SSR notes.
How to add AnveVoice to a Nuxt app
In Nuxt, declare the script once in app.head inside nuxt.config.ts, with async and tagPosition set to bodyClose. Every server-rendered or generated page then carries the tag. Use useHead in app.vue if you want it in code instead. Steps checked against the official documentation on 2026-10-14.
At a glance
- Where the code goes: nuxt.config.ts (app.head.script) or useHead() in app/app.vue
- Attributes: src, async: true, tagPosition: 'bodyClose'
- Coding needed: One config entry; no module to install
- Applies to: SSR, nuxt generate output and client-side navigation
Before you start
Get the embed ID from app.anvevoice.app; the Free plan needs no card. The examples use Nuxt 4 conventions (the app/ source directory and TypeScript). In an older Nuxt 3 project the same keys work, but app.vue sits at the project root. Nuxt builds the document head with Unhead. The official configuration reference describes app.head as default configuration for the head on every page, and its script list maps each object to a script tag, with object keys becoming HTML attributes. That is what lets one entry install AnveVoice site-wide.
Method 1: app.head in nuxt.config.ts (recommended)
The Nuxt SEO and meta guide says providing an app.head property in nuxt.config.ts statically customizes the head for the whole app. It also notes that this method does not allow reactive data, which does not matter here because the tag never changes.
- 1. Open nuxt.config.ts — It sits at the project root.
- 2. Add the script entry — Put the script object under app.head. async stops the file blocking rendering, and tagPosition bodyClose appends the tag to the end of the body. Code: // nuxt.config.ts export default defineNuxtConfig({ app: { head: { script: [ { src: "https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID", async: true, tagPosition: "bodyClose", }, ], }, }, });
- 3. Restart the dev server — Stop and start nuxt dev so the config change is applied.
Method 2: useHead in app.vue
Use this version if your team prefers code over config, or if you want to add the tag conditionally. Nuxt documents passing a script array to useHead, typically in app.vue, and lets the same object shape carry src and async.
- 1. Edit app/app.vue — Call useHead in the script setup block of your root component. Code: <!-- app/app.vue --> <script setup lang="ts"> useHead({ script: [ { src: "https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID", async: true, tagPosition: "bodyClose", }, ], }); </script> <template> <NuxtPage /> </template>
- 2. Scope it if needed — To limit the agent to certain pages, move the useHead call into those page components instead of app.vue.
Server rendering versus client navigation
With server-side rendering or nuxt generate, the script tag is written into the HTML, so visitors and crawlers see it on first load. On client-side navigation between routes, the head entry stays registered, and the AnveVoice script ignores a second copy on the same page, so route changes do not create duplicates. The tagPosition option accepts head, bodyClose and bodyOpen. bodyClose is a sensible home for a widget that does not need to run before the page paints.
Check that it works
- 1. Build and preview — Run nuxt build then nuxt preview (or nuxt generate and serve the output), so you test the production HTML.
- 2. View the page source — Search for anvevoice.app/embed.js near the end of the body to confirm the tag is in the server-rendered HTML.
- 3. Try the voice button — Open the site, find the round microphone button bottom-right, allow microphone access and ask a question.
Common problems
- Tag missing after editing config: restart the dev server; some config changes do not hot-reload.
- Tag appears twice: it is declared in both nuxt.config.ts and a useHead call. Keep one.
- Content Security Policy blocks it: allow https://anvevoice.app in script-src if you use a security module or custom headers.
- Microphone blocked: a Permissions-Policy header that disables microphone prevents the prompt, and the page must be on HTTPS.
Sources
- Nuxt Docs: SEO and meta (app.head, tagPosition) (https://nuxt.com/docs/4.x/getting-started/seo-meta) — checked 2026-10-14
- Nuxt Docs: nuxt.config app.head reference (https://nuxt.com/docs/4.x/api/nuxt-config) — checked 2026-10-14
- Nuxt Docs: useHead (https://nuxt.com/docs/4.x/api/composables/use-head) — checked 2026-10-14
Related
- How to add AnveVoice to a Vue app
- How to add AnveVoice to a Next.js app
- How to add AnveVoice to a site hosted on Netlify
- How to add AnveVoice to a SvelteKit app
Try AnveVoice on your site
Free plan: $0, 50,000 tokens a month, no card. Get your embed ID in the dashboard, then paste one tag.