Add a Voice AI Agent to a Rails App
Add the AnveVoice voice agent to a Ruby on Rails 7 or 8 app with javascript_include_tag in the application layout, plus CSP and Turbo notes.
How to add AnveVoice to a Ruby on Rails app
Rails renders every page inside app/views/layouts/application.html.erb. Add the AnveVoice script there with javascript_include_tag and a full URL, which the asset pipeline leaves untouched. If you have a Content Security Policy initializer, allow anvevoice.app in script_src. Steps checked against the official documentation on 2026-10-14.
At a glance
- Where the code goes: app/views/layouts/application.html.erb, inside head or just before </body>
- Coding needed: One ERB line; a CSP initializer edit only if you enforce a policy
- Plan limits: None from Rails; works wherever you deploy (Kamal, Heroku, Render, your own server)
- Time: About 3 minutes
How the layout works
The Rails guide on layouts and rendering explains that the main body of a view is rendered into the unnamed yield of the layout, and that a newly generated app already includes a named yield for the head. Asset helpers such as javascript_include_tag and stylesheet_link_tag are usually placed in the layout's head. The guide also notes these helpers generate links without checking that the asset exists. That behavior is useful here. Pass javascript_include_tag a complete URL instead of a bundled file name, and Rails writes the tag as given. The API documentation for the asset tag helper includes an example with a full address and the async: true option, producing a script element with the async attribute. A bare name such as 'main' would instead be looked up through the asset pipeline and served from /assets, which is the wrong place for a third-party script. The guide is written for Rails 8.1 and the layout structure is the same in recent 7.x releases.
- 1. Get your install tag — Create the bot in the AnveVoice dashboard at app.anvevoice.app and copy the embed ID. Keep the rest of the URL exactly as written, including the query string. Code: <script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" async></script>
Method 1: use javascript_include_tag in the layout
If you prefer plain HTML, paste the literal script tag into the ERB file instead. ERB prints text outside <% %> markers unchanged, so both approaches produce the same page.
- 1. Open the layout — Edit app/views/layouts/application.html.erb. If you have other layouts (for example admin.html.erb), decide which of them should carry the voice agent.
- 2. Add the helper before the closing body tag — The async option keeps it from blocking page rendering. Rails renders the attribute as async="async", which is equivalent. Code: <%= javascript_include_tag "https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID", async: true %> </body> </html>
- 3. Restart or reload — In development, ERB changes apply on the next request. In production, redeploy; there is no asset precompile step for this tag.
Method 2: add it per page with content_for
The Rails guide describes content_for as the way a view fills a named yield, useful for page-specific script or link elements in an otherwise generic head. To get the voice agent on a few pages only, give the layout a named yield and push the tag from those views.
- 1. Add a named yield — In the layout, add this before </body>. Code: <%= yield :voice_agent %>
- 2. Fill it in selected views — In a view such as app/views/pages/pricing.html.erb: Code: <% content_for :voice_agent do %> <%= javascript_include_tag "https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID", async: true %> <% end %>
Content Security Policy and Turbo
- CSP: Rails apps can define a policy in config/initializers/content_security_policy.rb. The security guide shows policy.script_src :self, :https, which already allows any HTTPS script host. If yours is stricter, add the origin: policy.script_src :self, "https://anvevoice.app". The guide also describes report-only mode so you can watch violations first.
- Turbo Drive: Rails 7 and 8 apps use Turbo, which swaps the body on navigation without a full reload. A script tag placed in the layout body is evaluated once and persists, which is the desired behavior; the AnveVoice script also ignores a second copy on the page.
- Fragment and page caching: if you cache the whole layout (for example with a CDN rule), purge the cache after the first deploy.
- Environments: wrap the helper in <% if Rails.env.production? %> to keep the button off development and test.
Check that it works
- 1. Inspect the generated HTML — Open the site in a private window, view source and look for embed.js with the async attribute.
- 2. Use the button — Click the microphone button, allow access (HTTPS or localhost) and speak or type a question about your site.
Common problems
- Request goes to /assets/...: the argument was a bare file name. Use the full https address so Rails does not resolve it through the pipeline.
- Blocked by CSP: the console names script-src. Add the host or switch the policy to report-only while you investigate.
- Appears twice: the tag exists in both the layout and a content_for block; keep one.
- Not visible on admin pages: they use another layout file, add the tag there if wanted.
Sources
- Rails Guides: Layouts and Rendering (asset tags, yield, content_for) (https://guides.rubyonrails.org/layouts_and_rendering.html) — checked 2026-10-14
- Rails API: ActionView AssetTagHelper (javascript_include_tag, async) (https://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html) — checked 2026-10-14
- Rails Guides: Securing Rails Applications (Content Security Policy) (https://guides.rubyonrails.org/security.html) — checked 2026-10-14
Related
- How to add AnveVoice to a Laravel application
- How to add AnveVoice to a Django project
- How to add AnveVoice to a Flask application
- 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.