Add a Voice AI Agent to a Qwik App (2026 Guide)
Add the AnveVoice voice agent to Qwik or Qwik City: one script tag in the head of src/root.tsx, why to skip Partytown, and how to verify the build.
How to add AnveVoice to a Qwik app
In a Qwik project, the document head is written in src/root.tsx. Add the AnveVoice script tag inside that head element and every route is served with it. Load it as a normal async script and leave Partytown out of it. Steps checked against the official documentation on 2026-10-14.
At a glance
- Where the code goes: The head element in src/root.tsx
- Coding needed: One JSX line
- Plan limits: None from Qwik. Free AnveVoice plan is enough
- Time: About 3 minutes plus a build
Where Qwik writes the head
Qwik's project-structure reference describes src/root.tsx as the root of the application tree, the entry point and the first component rendered. In the generated starter, root.tsx contains the document's head and body elements around the router outlet, which is why a tag placed in that head appears on every page. Two generations exist side by side. The stable releases published as @builder.io/qwik and create-qwik 1.x use Qwik City, and the 2.0 release candidates use @qwik.dev/core with Qwik Router. The edit is the same in both: root.tsx, inside head. Check your package.json to see which names you have.
- 1. Copy the install tag — Make a bot at app.anvevoice.app and substitute its embed ID. Options: &position=bottom-left, &theme=dark. Code: <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async></script>
Method 1: edit src/root.tsx
Create an app with npm create qwik@latest (pnpm, yarn and bun variants exist), choose the empty or basic starter, and open src/root.tsx. The code below shows the Qwik 1.x layout. In Qwik 2 the root file imports DocumentHeadTags, RouterOutlet and useQwikRouter from @qwik.dev/router, and the head contains DocumentHeadTags. Add the script element beside it in the same head.
- 1. Open root.tsx and find the head — Inside QwikCityProvider (v1) or the fragment returned after useQwikRouter (v2), locate the head element. In v1 it holds a charset meta tag, a manifest link and the RouterHead component.
- 2. Add the script after RouterHead — Keep the existing children and add one script element at the end of the head. It is a plain JSX tag with the async attribute. Code: import { component$, isDev } from "@builder.io/qwik"; import { QwikCityProvider, RouterOutlet } from "@builder.io/qwik-city"; import { RouterHead } from "./components/router-head/router-head"; import "./global.css"; export default component$(() => { return ( <QwikCityProvider> <head> <meta charset="utf-8" /> {!isDev && ( <link rel="manifest" href={`${import.meta.env.BASE_URL}manifest.json`} /> )} <RouterHead /> <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async /> </head> <body lang="en"> <RouterOutlet /> </body> </QwikCityProvider> ); });
- 3. Preview a production build — Qwik's getting-started guide says the preview command creates a production build and serves it, on localhost:4173. Dev mode (npm run start) works too, but preview shows what visitors will get.
Skip Partytown for this tag
Qwik's Partytown integration page shows third-party scripts placed in the head with type="text/partytown" so they run in a web worker, and says the qwik add partytown command wires up the configuration. That is a good fit for analytics and tag managers that only read and send data. AnveVoice draws a button, opens a panel and uses the microphone and audio output, which are things a page's main thread owns. We have not tested it under Partytown, so load it as an ordinary async script as shown above rather than adding the partytown type.
Resumability and navigation
- Qwik renders pages on the server and resumes in the browser instead of hydrating. A plain script tag in the head is just HTML, so it loads as it would on any static page and does not add to the amount of JavaScript Qwik has to resume.
- Navigation between routes is handled by the router without a document reload, so the voice agent is loaded once per full page load.
- Static output from an adapter (SSG) includes the head from root.tsx in every generated page.
- The public directory is copied to dist on build and served from the root, but it does not contain your page template. Edit root.tsx, not files in public.
Check that it works
- 1. Build and preview — Run the preview command and open the printed address in a private window. HTTPS is required for microphone access on a deployed site.
- 2. View the source — View Source and search for anvevoice.app. It should appear in the head of the raw HTML.
- 3. Try the button — Click the round microphone button at bottom-right, allow the microphone and speak a question.
Common problems
- Script is missing from the page: the tag was added to a route component, where it renders in the body and may not execute. Put it in the root.tsx head.
- Button does not appear in dev: restart the dev server after editing root.tsx and hard-reload.
- Two buttons: both a Partytown copy and a normal copy exist. Delete the type="text/partytown" one.
- Edge or CDN returns old pages: purge cached HTML after deploying the new build.
Sources
- Qwik docs: project structure (src/root.tsx, public) (https://qwik.dev/docs/project-structure/) — checked 2026-10-14
- Qwik docs: getting started (create-qwik, preview) (https://qwik.dev/docs/getting-started/) — checked 2026-10-14
- Qwik docs: Partytown integration (https://qwik.dev/docs/integrations/partytown/) — checked 2026-10-14
Related
- How to add AnveVoice to a SolidStart app
- How to add AnveVoice to a React app
- How to add AnveVoice to an Astro site
- How to add AnveVoice to a plain HTML website
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.