To add live chat to Gatsby you have three clean options: inject the Talkmio script at build time from gatsby-ssr.js, load it in the browser from gatsby-browser.js, or place it with the Head API on chosen pages. Each takes a few minutes, none needs a plugin, and all of them keep the widget out of your component tree. This guide shows the code for each method, explains how to skip the widget during development, and ends with a test list you can run before you deploy.
Talkmio is an AI live chat for websites. Its assistant, Mio, answers visitors from your own pages and documents in their language and hands the conversation to your team when it cannot answer. The widget is one script, so it works with Gatsby the same way it works with any other site.
Before You Start
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. Keep it open: the examples below use the placeholder SCRIPT_ADDRESS_FROM_YOUR_SNIPPET for the script address, and you should copy any attribute or site key exactly as your snippet shows it.
Add your public website to the Mio knowledge base so the assistant can answer real questions on day one. Mio reads every public page on the same domain, respecting robots.txt, and you can add single pages, Q&A pairs, free text and files such as PDF, DOCX, TXT, MD, CSV and HTML up to 15 MB. For a Gatsby site that is built from Markdown or a headless CMS, deploy first, then add the live address, so Mio reads the rendered pages.
Method 1: Add Live Chat to Gatsby With gatsby-ssr.js
The most reliable way to add live chat to Gatsby is the server rendering API. Gatsby calls onRenderBody while it builds each page, and you can use it to add a script to the end of the body in the static HTML. Create or edit gatsby-ssr.js in the project root.
import React from "react";
export const onRenderBody = ({ setPostBodyComponents }) => {
if (process.env.NODE_ENV !== "production") return;
setPostBodyComponents([
<script key="talkmio-widget" async src="SCRIPT_ADDRESS_FROM_YOUR_SNIPPET"></script>,
]);
};
Because the script is part of the HTML that Gatsby writes, it loads on the first paint of every page, including pages a visitor lands on directly from a search engine. The production check keeps your test conversations out of the Inbox while you run gatsby develop, since onRenderBody runs for the development server as well. The Gatsby SSR API reference documents setPostBodyComponents and its siblings.
If your snippet is an inline script rather than a script address, use dangerouslySetInnerHTML with the exact code from your account instead of src. Do not retype it by hand, because a missing character in a site key is the most common reason a bubble never appears.
Method 2: Load the Widget From gatsby-browser.js
If you want the script to load only in the browser, after the page is interactive, use the browser API. Gatsby calls onClientEntry once when the client starts, which is a good place for a one-time loader, as the Gatsby browser API reference explains.
export const onClientEntry = () => {
if (process.env.NODE_ENV !== "production") return;
if (document.getElementById("talkmio-widget")) return;
const s = document.createElement("script");
s.id = "talkmio-widget";
s.async = true;
s.src = "SCRIPT_ADDRESS_FROM_YOUR_SNIPPET";
document.body.appendChild(s);
};
The id guard prevents a second copy if the function runs twice, for example after a hot reload. This method keeps the widget out of the static HTML, which some teams prefer when they want to delay it until consent. To load it after a visitor accepts cookies, call the same code from your consent handler instead of from onClientEntry. Our guide to chat widget cookies and consent explains the choices.
Method 3: Place the Script With the Head API
Recent Gatsby versions include a Head API that lets a page or template export a Head component. You can add the script there when you want the widget on selected templates only, such as marketing pages but not a members area.
export const Head = () => (
<script async src="SCRIPT_ADDRESS_FROM_YOUR_SNIPPET"></script>
);
This puts the script in the document head of that page. An asynchronous script does not block rendering, so the position is fine for a chat widget; the MDN page on the script element describes how async and defer behave. The cost is repetition: every template that should show the chat needs the export, so for site-wide use the SSR method is simpler. If your project still uses an older Helmet-based setup, the same idea applies with its component.
Which Method Should You Use?
| Question | gatsby-ssr.js | gatsby-browser.js | Head API |
|---|---|---|---|
| Effort | One file | One file | One export per template |
| Script in static HTML | Yes | No | Yes |
| Hide on some pages | Needs a path check | Needs a path check | Yes, only where exported |
| Wait for cookie consent | Awkward | Easy | Awkward |
| Skip in development | Environment check | Environment check | Environment check |
| Best for | Site-wide chat | Consent-based loading | Selected templates |
If you are unsure, start with gatsby-ssr.js, test it and move to the browser API only when a consent rule demands it.
Show the Chat Only Where It Helps
A chat bubble is not equally useful on every page. On pricing, contact, product and help pages it answers real questions. On a checkout step or a login screen it can cover buttons. Under Websites you can choose the widget colour and position, so move the bubble away from the main call to action. If you need to exclude pages in code, check the location path before loading the script.
export const onClientEntry = () => {
const skip = ["/checkout", "/account"];
if (skip.some((p) => window.location.pathname.startsWith(p))) return;
/* load the script as in method 2 */
};
Note that onClientEntry runs once, so a visitor who starts on a skipped page and navigates to another will not get the widget until the next full load. Gatsby also offers onRouteUpdate, which runs on every client-side navigation, if you need route-by-route rules. Keep rules few: each exception is something to test after every redesign.
Performance and Core Web Vitals
A chat widget is a third-party script, and every third-party script has a cost. Load it asynchronously, as all three methods above do, so it never blocks rendering. Static sites usually score well, so measure before and after. The article on live chat widget page speed shows how to test the effect and how to delay loading until the browser is idle. On many Gatsby sites the heaviest part is images and fonts, not the widget, but measure rather than assume.
If you use a content security policy, add the widget’s script address and its connections to the allowed lists. A blocked script fails silently, and the console will show a policy error. Check the console after your first production build.
Gatsby-Specific Traps
Stale builds and caches
If the chat does not appear after you edit gatsby-ssr.js, run gatsby clean and build again. The cache can hold the old HTML for pages that did not change. Also remember that gatsby develop and gatsby build are different runs: test with a production build served locally, not only with the development server.
Duplicate bubbles
Use one method only. If a teammate pasted the snippet into a layout component and you added it to gatsby-ssr.js, visitors may see two bubbles. Search the repository for the script address before you commit.
Hydration warnings
Do not add the script inside a page component’s render output. It can differ between the server and the browser and cause a hydration warning. Keep it in the SSR API, the browser API or the Head export.
Preview and staging sites
Staging sites should not send conversations to your real Inbox. Use an environment variable to hold the script address, set it only in production, and let the code skip loading when it is empty. A free Talkmio account allows one website and paid plans allow more, so a separate staging website with its own key is possible when you need it. Gatsby exposes variables that start with GATSBY_ to browser code, so name yours accordingly.
Maintaining the Setup Over Time
A chat setup is not finished when it first works. Gatsby sites change: a redesign adds a new layout, a plugin update changes how pages render, a developer replaces the SSR file during a clean-up. Write one line in your README that says where the Talkmio script is loaded and why, and add the six-step test below to your release checklist. When a teammate joins, they will find the loader in minutes instead of searching the repository.
Also decide who owns the chat itself. Someone should read the conversations Mio could not answer each week, add the missing facts to the knowledge base and use the Re-read option after publishing new pages. The code is a one-time job, while the quality of the answers depends on the content you keep up to date.
Test Before You Deploy
- Run a production build and serve it locally.
- Open the site in a private window and confirm the bubble appears on the home page and on a page you reach directly.
- Ask Mio three questions your customers often ask and check that the answers come from your own pages.
- Navigate between pages and confirm there is only one bubble.
- Check the browser console for blocked scripts.
- Open the Visitors page in your Talkmio account and confirm you can see your own visit.
When the test passes, deploy and repeat it on the live address. For other static and React frameworks see our guides to adding live chat to Next.js, static sites with Hugo, Jekyll and Astro and Google Tag Manager. You can compare plans on the pricing page: Free covers one website and 50 AI answers a month, and paid plans start with a 14-day trial.
Frequently Asked Questions
Where do I put the script to add live chat to Gatsby?
The simplest place is gatsby-ssr.js, using onRenderBody and setPostBodyComponents, which writes the script into the static HTML of every page. Use gatsby-browser.js if you want to load it in the browser after consent, or the Head API for selected templates only.
Do I need a Gatsby plugin for Talkmio?
No. The widget is one script, so you can add it with the standard Gatsby APIs and no plugin. Copy the script address and any site key from the snippet in your Talkmio account, and keep them exactly as shown.
Why does the chat bubble not show in gatsby develop?
If you used the production check from this guide, the script is skipped in development on purpose. Run a production build with gatsby build and serve it locally to test. If it still does not appear, run gatsby clean, rebuild and check the console for blocked scripts.
How do I load the chat only after cookie consent?
Use the browser API approach and call the loader from your consent handler instead of onClientEntry. Keep the id guard so a second call does not add a second copy, and remember to document in your privacy notes when the chat loads, so visitors and your own team know what happens before and after consent.
Will the chat slow down my Gatsby site?
A chat widget adds a third-party script, so it has some cost. Loading it asynchronously keeps it from blocking rendering. Measure your Core Web Vitals before and after, and consider delaying the load until the browser is idle if your scores are tight.
Can Mio read a Gatsby site built from Markdown?
Yes, once the pages are live. Mio reads the public pages on your domain, so deploy first and add the website to the knowledge base. Use the Re-read option after you publish new content so answers stay current.
The Bottom Line
To add live chat to Gatsby, start with gatsby-ssr.js: one file, one script, loaded on every page of the production build. Switch to the browser API when consent rules require it, or to the Head API when only some templates need chat. Test a production build, keep a single copy of the script and let Mio learn from your deployed pages. Start free with Talkmio and have your Gatsby site answering visitors before the next deploy.
