To add live chat to Hugo you need one small partial and one line in a template. The partial holds the Talkmio snippet, the template includes it just before the closing body tag, and a check on the build environment keeps the widget out of your local preview. That is the whole job, and it takes about ten minutes. This guide shows where the files go, how to deal with a theme that owns your layout, how to switch the chat off on selected pages and how to test the result.
Talkmio is an AI live chat for websites. Its assistant, Mio, answers visitors in their own language from your website, FAQ and uploaded documents, and hands the conversation to your team when it cannot answer. A Hugo site is a good fit, because the content Mio needs is already public, structured and well written.
What You Need Before You Add Live Chat to Hugo
Create a free account at app.talkmio.com, confirm your e-mail and add your website under Websites. You receive a site key and an install snippet. The examples below use the placeholder SCRIPT_ADDRESS_FROM_YOUR_SNIPPET for the script address. Copy the snippet exactly as Talkmio shows it, including every attribute, and never retype the site key by hand.
Then teach Mio. Open Mio AI, then Knowledge base, and add your deployed site. Mio reads every public page on the same domain and respects robots.txt, so a published Hugo site is easy to ingest. If you keep content outside the site, such as a price list or a migration guide, upload it as a file (PDF, DOCX, TXT, MD, CSV or HTML, up to 15 MB each). You can do this before or after the widget is live, but doing it first means the first visitor already gets good answers.
Where the Snippet Belongs in a Hugo Site
Hugo builds every page from a base template, usually layouts/_default/baseof.html (in the newest layout structure it sits at layouts/baseof.html). Almost every theme closes that file with a footer area and the closing body tag. The snippet belongs just before that closing tag, so it loads after your content and never blocks rendering.
You have four realistic ways to get it there. The table compares them.
| Method | Effort | Survives theme updates | Best for |
|---|---|---|---|
| New partial plus one include in your own base template | Low | Yes | Sites with their own layouts |
| Theme extension partial (for example an “extend footer” hook) | Lowest | Yes, if the theme keeps the hook | Themes that document a hook |
| Override of the theme’s footer or base file in your site folder | Medium | Only partly, you must compare after updates | Themes without a hook |
| Loading through Google Tag Manager | Medium | Yes | Teams that already manage scripts in a tag container |
The first row is the one to choose when you can. It is explicit, it is easy to find a year from now and it does not depend on a theme decision you do not control.
Method 1: Create a Partial and Include It
A partial is a reusable template fragment. The Hugo configuration reference explains the project layout, and the rule that matters here is simple: files in layouts/partials/ are available to any template by name. Create layouts/partials/talkmio.html and paste the snippet into it, exactly as copied from Talkmio.
<!-- layouts/partials/talkmio.html -->
<script async src="SCRIPT_ADDRESS_FROM_YOUR_SNIPPET"></script>
Now include it in your base template, just above the closing body tag.
<!-- layouts/_default/baseof.html -->
{{ partial "footer.html" . }}
{{ partial "talkmio.html" . }}
</body>
</html>
If your snippet is a longer inline script rather than a single script address, the approach is the same. Keep the whole block in the partial and avoid putting Hugo template actions inside the script itself. Go templates escape values that appear inside script blocks for safety, which is correct for data but can mangle a snippet that you simply want to output as written. A literal snippet in a partial is output untouched.
Method 2: Use the Hook Your Theme Provides
Many Hugo themes are built to be extended without editing them. Some provide empty partials for exactly this purpose, with names such as an extend-head or extend-footer file. PaperMod, for example, documents this pattern. If your theme has such a hook, create a file with the same name inside your own layouts/partials/ folder and put the snippet there. Hugo prefers files in your site over files in the theme, so your version is used and the theme folder stays untouched.
Check your theme’s documentation for the exact file name before you rely on this. If the theme has no hook, do not edit files inside the theme folder or a Git submodule. Copy the theme’s base or footer file into the same path in your site’s layouts/ folder, add the include there and keep a note of the date. When you update the theme, compare your copy with the new original.
Load the Chat Only in Production Builds
When you run hugo server, Hugo uses the development environment. A plain hugo build uses production. You can read the environment in a template with hugo.Environment, as the reference for the environment function describes, and use it to wrap the include.
{{ if eq hugo.Environment "production" }}
{{ partial "talkmio.html" . }}
{{ end }}
This keeps test conversations out of your Inbox while you work on layouts. It also keeps a preview deployment from sending visitors to your support team. If your staging site is built with a custom environment name, for example hugo --environment staging, the check naturally leaves the widget out there as well. If you want the chat on staging for a final test, change the condition to allow it, run the test and change it back.
Switch Live Chat Off on Selected Pages
Some pages should not carry a chat bubble. A checkout redirect, a printable invoice, a kiosk page or a landing page built for a very specific call to action are common examples. Hugo makes this easy with front matter.
# content/print/invoice-template.md
---
title: "Invoice template"
nochat: true
---
{{ if and (eq hugo.Environment "production") (not .Params.nochat) }}
{{ partial "talkmio.html" . }}
{{ end }}
You can apply the same flag to a whole section by setting it in a cascade in the section’s front matter, so you do not repeat it in every file. Keep the number of exceptions small. A chat that is missing on half the site confuses visitors, and the pages where people hesitate most, such as pricing, delivery and returns, are exactly the pages where an answer helps.
Language Versions and Multilingual Hugo Sites
Hugo supports multilingual sites with a separate content tree for each language. The snippet itself does not need to change per language. Mio replies in the language the visitor writes in and the chat window is translated as well, so a German visitor on your German pages and an English visitor on your English pages are both served from the same widget. In the website settings you can leave the language on auto-detect or fix it if your pages are strictly single-language.
The knowledge base is where multilingual sites need a decision. Because Mio finds answers across languages, a question in German can be answered from an English FAQ. That is helpful when only some pages are translated. It is worth reading a few German answers yourself with the Try Mio feature before launch, and adding a German page or a question-and-answer pair for anything important that the English source states too loosely.
Performance, Caching and Content Security
A static site is fast because there is little to load, so protect that. The async attribute lets the browser fetch the script without pausing the page. Placing the include at the end of the body means your content paints first. If you run a strict content security policy, add the Talkmio script address and the connections it needs to the allowed list. If visitors must consent before scripts load, read our guide to chat widget cookies and consent and load the partial only after consent. Measure the effect on your own pages instead of guessing.
Because the widget is added at build time, a CDN cache will serve the same HTML to everyone, which is what you want. You do not need to purge caches when you change widget colours, position or texts in Talkmio. Changes made under Websites apply within five minutes.
Common Problems When You Add Live Chat to Hugo
Most failures come from a short list of causes. The widget appears twice when both a theme hook and your own include load the snippet, so search the generated HTML for the script address and make sure it appears once. The widget is missing in production when the deployment tool builds with a custom environment name and your check only allows the default one. The widget appears on a draft preview when a build includes drafts, so keep the production check in place. Partial names are case sensitive on most servers, so a file called Talkmio.html will not match a call for talkmio.html.
If you maintain several static sites, the general guide to adding live chat to a static site covers the generic steps, and this page covers the Hugo details. Whichever route you choose, the goal when you add live chat to Hugo is the same: one clear include, one environment check and a short list of pages that opt out.
Test the Result Before You Announce It
- Run
hugo --minifyand open a generated HTML file. Confirm the script appears once, near the end of the body. - Run
hugo server. The widget should not appear locally. - Deploy to production, open the live site in a private browser window and check that the chat bubble appears in the corner.
- Ask Mio two or three questions your customers often ask and check that each answer comes from your own pages.
- Open a page with
nochat: trueand confirm the bubble is absent. - Ask for a person. The conversation should appear in the Inbox with a needs-human badge, and your browser should notify you.
- Test on a phone. The guide to mobile widget design covers overlap with cookie banners and sticky bars.
If the bubble does not appear, view the page source. A missing script usually means the environment check is false, the include sits outside the final template, or a minifier removed the line. Fix the source, rebuild and test again.
Frequently Asked Questions
Do I need a Hugo plugin to add live chat?
No. Hugo has no plugin system for this. You add the Talkmio snippet to a partial and include it in a template, which is a few lines of code. The WordPress plugin is only for WordPress. Any static site works with the plain snippet, including Hugo, because the widget is just one script.
Which Hugo file should hold the snippet?
Put it in layouts/partials/talkmio.html and include it from your base template just before the closing body tag. If your theme provides an extension partial for footers, use that instead, since it survives theme updates. Avoid editing files inside the theme folder itself.
How do I stop the chat appearing on my local preview?
Wrap the include in a check for the production environment, using hugo.Environment. The development server uses the development environment, so the widget stays out of your local pages and your test chats stay out of the Inbox. A normal hugo build runs in production, so the widget appears in the deployed site.
Can I hide the chat on a single page?
Yes. Add a front matter flag such as nochat: true to the page, then test for it in the template with not .Params.nochat. You can apply the flag to a whole section with a cascade, which avoids repeating it in each file. Keep exceptions rare, because visitors expect help on every page.
Will the widget slow down my Hugo site?
The script loads with the async attribute at the end of the body, so your content paints first. The effect is usually small, but measure it on your own pages before and after. Test on a mid-range phone and a slow connection, since that is where any added cost shows up first.
Does Mio know about my Hugo content automatically?
After you add your deployed site to the knowledge base, Mio reads every public page on the same domain and respects robots.txt. When you publish new pages, use the re-read option so Mio picks up the change. Mio answers only from your content and hands over to a person when it cannot.
The Bottom Line
To add live chat to Hugo, create one partial, include it before the closing body tag, wrap it in a production check and give pages a simple opt-out. Use your theme’s extension hook if it has one, and avoid editing theme files directly. Then teach Mio from your own pages and test with real questions in a private window. Start free with Talkmio, paste the snippet into your partial and see how many visitor questions your Hugo content can already answer.
