AnveVoice

Add a Voice AI Agent to a Flask App

Add the AnveVoice voice agent to a Flask 3 app by placing one script tag in your base Jinja template, with a block for per-page control and CSP notes.

How to add AnveVoice to a Flask application

Flask renders pages with Jinja, and a base template with blocks is the standard way to share a layout. Put the AnveVoice tag in that base template, just before the closing body tag, and every page that extends it gets the voice button. Steps checked against the official documentation on 2026-10-14.

At a glance

  • Where the code goes: templates/layout.html (or base.html), the template your pages extend
  • Coding needed: One Jinja line; no Python changes and no extension
  • Plan limits: None from Flask; runs on any WSGI host (Gunicorn, uWSGI, PythonAnywhere, Render and so on)
  • Time: About 3 minutes

Where Flask looks for your layout

Flask uses the Jinja template engine, and the official template inheritance pattern builds every page from one skeleton, usually called layout.html. The skeleton defines blocks (head, title, content, footer in the documentation's example) and child pages begin with {% extends "layout.html" %}. Flask finds these files in the templates folder next to your application module or inside a blueprint's own templates folder. So the work is to open the skeleton and add one line. Nothing is registered in Python. Flask's templating documentation confirms that autoescaping is on for .html, .htm, .xml and .xhtml templates, but that only affects variables; a literal script tag typed into the template is output exactly as written. If your app returns HTML from render_template_string or from plain strings in a view, there is no template file to edit. Add the tag to the string, or better, move that markup into a template so there is one place to maintain.

  • 1. Get your install tag — In the AnveVoice dashboard at app.anvevoice.app, create a bot for your site and copy the embed ID into the URL. The default button sits bottom-right; add &position=bottom-left to move it. Code: <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async></script>

Method 1: put it in the base template

  • 1. Open templates/layout.html — Use whichever file your pages extend. Pages in blueprints that extend a different base need the tag in that base too.
  • 2. Add the tag with its own block — A dedicated block makes it easy to switch the voice agent off on specific pages later by overriding the block with nothing. Code: {% block voice_agent %} <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async></script> {% endblock %} </body> </html>
  • 3. Restart if needed — The Flask development server with debug enabled reloads on change. Under Gunicorn or another production server, restart the workers so they load the updated template.

Method 2: add it only to some pages

Leave the block empty in the base and fill it from the pages that should have the agent. The Flask pattern page also shows super() for adding to a block without replacing the parent's content, which is handy if the base already puts something in that spot.

  • 1. Declare an empty block in layout.html — Use {% block voice_agent %}{% endblock %} above the closing body tag.
  • 2. Fill the block in a page — In templates/pricing.html: Code: {% extends "layout.html" %} {% block voice_agent %} <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async></script> {% endblock %}

Flask-specific things to watch

  • Static files vs a remote script: the Flask static folder and url_for('static', ...) are for your own files. The AnveVoice script is loaded from anvevoice.app, so use the full address and do not copy embed.js into static; a local copy would not receive updates.
  • Security headers: Flask itself sends no Content Security Policy. If you add one (in an after_request handler or through an extension), include https://anvevoice.app in script-src, otherwise the browser blocks the tag and the console shows a CSP violation.
  • Behind a proxy: if Nginx or a CDN caches full HTML, purge it after you deploy, or the old page without the tag keeps being served.
  • Jinja whitespace and braces: the tag contains no double braces, so there is nothing to escape and no raw block is required.
  • Embed ID per environment: if you keep it in configuration, pass it to the template with a context processor and write ...embedId={{ anvevoice_embed_id }} in the URL.

Check that it works

  • 1. View the rendered page — Open a page in a private window, view source and confirm embed.js appears once near the end of the body.
  • 2. Try a conversation — Click the round microphone button, grant microphone permission (the page must be HTTPS or localhost) and ask a question.

Common problems

  • Template change has no effect: the process is serving a cached template or a different templates folder. Restart and confirm which layout the failing page extends.
  • TemplateSyntaxError after editing: a block was closed with the wrong tag. Check every {% block %} has an {% endblock %}.
  • Button missing on one blueprint: that blueprint has its own base template.
  • Console reports a CSP violation: allow the host in script-src.

Sources

  • Flask 3.1 docs: Template Inheritance (https://flask.palletsprojects.com/en/stable/patterns/templateinheritance/) — checked 2026-10-14
  • Flask 3.1 docs: Templates (Jinja setup, autoescaping) (https://flask.palletsprojects.com/en/stable/templating/) — checked 2026-10-14

Related

  • How to add AnveVoice to a Django project
  • How to add AnveVoice to an Express (Node.js) site
  • How to add AnveVoice to a Ruby on Rails app
  • How to add AnveVoice to a Laravel application

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.