Add a Voice AI Agent to an Express App
Add the AnveVoice voice agent to an Express 5 app: edit your view template or static HTML, and allow anvevoice.app in Helmet's script-src policy.
How to add AnveVoice to an Express (Node.js) site
How you add the tag depends on how Express serves your pages. With a template engine such as Pug, EJS or Handlebars, add it to the shared layout. With express.static serving plain HTML, add it to the HTML files. If you use Helmet, also allow anvevoice.app in script-src. Steps checked against the official documentation on 2026-10-14.
At a glance
- Where the code goes: Your shared view layout in the views folder, or the HTML files in your static folder
- Coding needed: One line in a template or HTML file; a small Helmet config change if you use Helmet
- Plan limits: None from Express; runs wherever Node runs
- Time: About 5 minutes
Express has no layout of its own
Unlike batteries-included frameworks, Express does not impose a page structure. The Express guide on template engines says you set two application settings: views, the directory holding templates (defaulting to a views folder in the app root), and view engine, which names the engine. Then res.render('index', data) renders a template. Which file wraps your pages is therefore decided by the engine you picked and by how you structured your views. The second common arrangement is serving finished HTML. The static files guide shows app.use(express.static('public')), which makes files in that folder available at paths relative to it, without the folder name in the URL. A single-page app build, for instance, is typically served this way. Express 5 documentation is the current reference for both pages. Work out which of the two your project uses by looking at server.js or app.js: a call to app.set('view engine', ...) means templates; app.use(express.static(...)) alone means static files.
- 1. Get your install tag — Create a bot at app.anvevoice.app and copy its embed ID into the tag. You can add &theme=dark if your site has a dark background. Code: <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async></script>
Method 1: add it to the shared template
With any engine, find the file that outputs the html, head and body elements. In Pug that is often layout.pug, with EJS a header and footer partial, with Handlebars a layouts/main.hbs when using a layout helper. Add the tag at the end of the body so it loads after the page content.
- 1. Edit the layout template — For EJS, for example, the footer partial included at the bottom of every page is the right home: Code: <!-- views/partials/footer.ejs --> <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async></script> </body> </html>
- 2. Pug equivalent — In Pug, indent the script element under body in the layout. Code: body block content script(src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID", async)
- 3. Restart the process — Express caches compiled templates when the view cache is on (the default in production). The docs note that the view cache stores only the compiled template, not the output. Restart Node after editing so the new template is compiled.
Method 2: add it to static HTML files
- 1. Open each HTML file in your static folder — Edit public/index.html and any other page that should carry the voice agent. Paste the tag above the closing body tag.
- 2. Rebuild if the HTML is generated — If public/ comes from a build step (Vite, webpack, a static site generator), add the tag to the source HTML or template of that tool instead, then rebuild. Edits made to generated files are overwritten on the next build.
Helmet and other security middleware
Many Express apps use Helmet. Its documentation states that the default Content-Security-Policy sets script-src to 'self', so an external script such as the AnveVoice tag is blocked until you allow it. Pass your directives to the contentSecurityPolicy option; Helmet merges them with its defaults, and the key may be written script-src or scriptSrc. If the button loads but conversations fail, read the CSP messages in the browser console and add the hosts they name to connect-src or the media and frame directives they mention.
- 1. Allow the host in script-src — Keep 'self' in the list and add the AnveVoice origin. Code: import helmet from "helmet"; app.use( helmet({ contentSecurityPolicy: { directives: { "script-src": ["'self'", "https://anvevoice.app"], }, }, }), );
Check that it works
- 1. Request the page — Run curl on a page URL and search the output for embed.js, or view source in a private window. It should appear once.
- 2. Use the voice button — The microphone button appears bottom-right. Click it, allow the microphone (HTTPS or localhost) and ask a question about your site.
Common problems
- Edited template but nothing changed: you edited a partial that is not included in that page's layout, or view caching is serving the old compile. Restart.
- Script blocked after adding Helmet: the default script-src is 'self'. Add the AnveVoice origin as shown.
- Relative static path confusion: express.static('public') resolves against the folder where you launch node. Use an absolute path if the app is started from elsewhere.
- Reverse proxy cache: Nginx, a CDN or a service worker is serving a stale HTML file.
Sources
- Express guide: Using template engines (https://expressjs.com/en/guide/using-template-engines.html) — checked 2026-10-14
- Express guide: Serving static files in Express (https://expressjs.com/en/starter/static-files.html) — checked 2026-10-14
- Helmet.js documentation (Content-Security-Policy) (https://helmetjs.github.io/) — checked 2026-10-14
Related
- How to add AnveVoice to a Flask application
- How to add AnveVoice to a Ruby on Rails app
- How to add AnveVoice to a React app
- How to add AnveVoice to a Next.js 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.