Add a Voice AI Agent to a Spring Boot App
Add the AnveVoice voice agent to a Spring Boot web app with a Thymeleaf fragment or static HTML, and allow anvevoice.app in Spring Security's CSP.
How to add AnveVoice to a Spring Boot application
Spring Boot serves HTML from templates (Thymeleaf, FreeMarker, Mustache) or from static files. Put the AnveVoice tag in a shared template fragment or in your static HTML. If Spring Security sends a Content-Security-Policy header, allow anvevoice.app in script-src. Steps checked against the official documentation on 2026-10-14.
At a glance
- Where the code goes: A Thymeleaf fragment in src/main/resources/templates, or HTML in src/main/resources/static
- Coding needed: One fragment file and one include line; a security config edit only if you set a CSP
- Plan limits: None from Spring Boot; any JVM host
- Time: About 5 minutes
Where Spring Boot gets its HTML
The Spring Boot reference documentation lists the template engines it auto-configures: FreeMarker, Groovy, Thymeleaf and Mustache. With default configuration, templates are picked up from src/main/resources/templates. Static content comes from a directory called /static (or /public, /resources, /META-INF/resources) on the classpath. The reference also advises avoiding JSPs where possible. Look at your project to see which applies. A pom.xml or build.gradle with spring-boot-starter-thymeleaf means Thymeleaf. A folder src/main/resources/static with index.html and no template engine means a static or single-page front end. If the web app is a pure REST API with a separate front end, add the tag to that front end's HTML instead. The steps use Thymeleaf because it is the most common engine, and the same idea (one shared include) applies to FreeMarker and Mustache.
- 1. Get your install tag — Create the bot at app.anvevoice.app and copy the embed ID into the URL. Keep the URL as plain markup; do not wrap it in a th:src expression, which is meant for links relative to your own application. Code: <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async></script>
Method 1: a Thymeleaf fragment included by your layout
Thymeleaf's tutorial defines reusable markup with th:fragment and includes it with th:insert or th:replace, where th:replace substitutes the host tag with the fragment. Putting the tag into one fragment means every page that includes it stays consistent, and removal is a one-file change.
- 1. Create the fragment — Add src/main/resources/templates/fragments/voice-agent.html. A th:block element renders nothing of its own, so no extra wrapper element appears in the output. Code: <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <body> <th:block th:fragment="voice"> <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async></script> </th:block> </body> </html>
- 2. Include it in your page layout — In the template that wraps your pages (or in each page), place the include just before the closing body tag. Code: <th:block th:replace="~{fragments/voice-agent :: voice}"></th:block> </body>
- 3. Rebuild — Thymeleaf caches templates by default outside development. Restart the application, or rebuild the jar, so the new fragment is picked up.
Method 2: static HTML
- 1. Edit the files in /static — Open src/main/resources/static/index.html and any other HTML page that should show the button. Paste the tag above the closing body tag.
- 2. Repackage — Static resources are copied into the jar at build time, so run your build (for example mvn package or gradle build) and redeploy. In development, the IDE or Spring Boot devtools can serve updated resources without a full build.
Spring Security and Content-Security-Policy
The Spring Security reference states that it does not add a Content Security Policy by default, because a reasonable default cannot be known without the application's context. So with no CSP configured, the tag simply loads. If you do declare a policy, the documentation shows contentSecurityPolicy with policyDirectives, and you must add the AnveVoice origin to script-src or the browser blocks it. A report-only mode is available through reportOnly() while you test.
- 1. Allow the host in your security configuration — Extend the existing SecurityFilterChain bean with the directive below, merging with any directives you already use. Code: http.headers(headers -> headers .contentSecurityPolicy(csp -> csp .policyDirectives("script-src 'self' https://anvevoice.app") ) );
Check that it works
- 1. Read the response — Load a page in a private window, view source and search for embed.js. It should appear once near the end of the body.
- 2. Click the button — Use the microphone button at the bottom-right, grant access (HTTPS or localhost) and ask a question.
Common problems
- Fragment not found: the path in the th:replace expression does not match the file location under templates, or the file extension differs from the configured suffix.
- Static page shows the old version: the jar still contains the previous resources. Rebuild.
- Nothing appears and the console shows a CSP error: add https://anvevoice.app to script-src, as above.
- Button on error pages is missing: those pages use a separate template; include the fragment there too.
Sources
- Spring Boot reference: Servlet web applications (template engines, static content) (https://docs.spring.io/spring-boot/reference/web/servlet.html) — checked 2026-10-14
- Thymeleaf 3.1 tutorial: Using Thymeleaf (fragments, link URLs) (https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html) — checked 2026-10-14
- Spring Security reference: HTTP response headers (Content Security Policy) (https://docs.spring.io/spring-security/reference/servlet/exploits/headers.html) — checked 2026-10-14
Related
- How to add AnveVoice to an ASP.NET Core app
- How to add AnveVoice to a Laravel application
- How to add AnveVoice to a Django project
- How to add AnveVoice to an Express (Node.js) site
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.