Short answer: Shopify admin → Online Store → Themes → ⋯ (on your live theme) → Edit code → Layout → theme.liquid. Paste the widget's <script> tag just before the closing </body> tag. Save. Reload the storefront in an incognito tab. The widget renders on every page.
If that worked — close the tab, you're done. If you pasted into the theme editor's Custom CSS box or a sidebar HTML block and are wondering why the widget isn't loading, the next 1,200 words are for you.
Why "just paste the script" is harder on Shopify than most builders
Most chat-widget install docs say "paste this script before </body>." On a hand-coded site you'd open a template file and drop the tag in. On Shopify there are three different places that all look like "somewhere I can paste code":
- theme.liquid (correct) — the site-wide template, edited via Edit code.
- The theme editor's sections/blocks — drag-and-drop, including an HTML block and a Custom CSS field. These look tempting and they're the first thing merchants find. They don't load site-wide and they strip most
<script>tags. - Shopify App embeds — a newer system where apps inject code via the theme editor's App embeds sidebar. Chat apps distributed through the Shopify App Store use this path; hand-pasted scripts from a non-app vendor do not.
Pasting into the wrong one produces the same observable result: widget doesn't appear, no errors. This post covers the hand-pasted case — your chat vendor gave you a <script> tag and you need to put it somewhere Shopify will render on every page.
Click path — the only path that works site-wide
- Log in to your Shopify admin.
- In the left sidebar, click Online Store → Themes.
- Find your live theme (the one marked Current theme, not a draft or backup).
- Click the ⋯ three-dot menu on the theme card → Edit code.
- In the file tree on the left, under Layout, click theme.liquid.
- Scroll to the bottom of the file. Find the
</body>tag. - Paste your widget's
<script>tag on the line immediately before</body>. - Click Save in the top-right.
- Open your storefront in an incognito / private window and reload.
The widget now renders on every page served from this theme — home, product, collection, cart, 404, everything.
If you have multiple themes, the script only lives in the one you edited. If you duplicate your live theme for a redesign, copy the script into the duplicate before you publish it — otherwise Go Live day silently removes your widget.
Two places people paste instead, and why they fail
The theme editor's HTML block (or a Custom HTML section). This is the drag-and-drop block some themes expose for "add custom HTML to this page". It runs inside a sandboxed section. Most <script> tags are stripped or sandboxed into a way your widget can't use. Even when the script survives, it only renders on whichever page the block was placed on — not site-wide.
The theme editor's Custom CSS or Theme settings → Custom code field. Some themes have a free-text box in theme settings labelled something like "Additional CSS" or "Custom code". The CSS box isn't going to run JavaScript — that's self-evident in hindsight. The "custom code" box, if your theme has one, usually injects into <head>, not before </body>, and many chat widgets specifically need to mount after the body is parsed. Check your widget's docs, but when in doubt, use theme.liquid.
Both of these are the second thing support gets asked about on every chat-widget vendor's docs. The first thing is people who pasted the script and forgot to click Save.
Head vs. body: which side of theme.liquid?
Some chat vendors say "paste in the head"; some say "paste before </body>". Most widgets work either way, but there's a real distinction:
- Head: the widget library is requested earlier, so
window.YourWidgetis defined sooner. Downside: it can delay first paint if the library is large and not loadedasync. - Before
</body>: the page renders first, then the widget loads. Your storefront feels faster, at the cost of a slightly-later chat button appearance.
Unless the widget docs are explicit about head, paste before </body>. Shopify storefronts are speed-sensitive — Google's Core Web Vitals feed the shop's SEO, and a chat widget that adds 300ms to LCP is a measurable hit.
How to tell if it actually fired
Pasting the script and seeing no widget on the storefront is the most common "it's broken" moment. In order of what to check:
Is the script tag in the page source at all? Open your live storefront in an incognito window, view source (Ctrl+U / Cmd+U), search for the vendor's domain — e.g. intercom, crisp, tawk, drift, whatever applies. If it's not in the source, you either pasted into the wrong theme or didn't save.
Did the script load? Open DevTools → Network tab, reload, filter by the vendor's domain. You should see at least one 200 response. A 403 or a blocked request usually means a Content Security Policy set by an app or a theme is rejecting the script — rare on stock Shopify, common on themes that ship with their own CSP.
Did the widget initialise? In the Console, type the global your widget defines (window.Intercom, window.$crisp, window.Tawk_API, etc.). If it's defined, the library loaded. If it's undefined, the library either didn't load or threw during init — check the Console for red errors.
If all three pass and the widget still doesn't visually appear, the vendor's app-side config (project ID, workspace ID, visibility rules) is the next place to look. That's out of scope for this post and usually well-covered in the vendor's own docs.
Shopify-specific gotchas
Checkout pages are different. Shopify's checkout runs on a separate surface that does not inherit theme.liquid. Scripting the checkout page itself now flows through Checkout Extensibility — Shopify's current extension framework — which most widget vendors expose as a Shopify app rather than a raw script tag. Legacy Checkout.liquid still works for some Shopify Plus shops that haven't migrated yet, but it's on a sunset path and new Plus shops get Checkout Extensibility by default. For post-purchase events, the Order status page additional scripts box under Settings → Checkout is still available. If you need your chat widget on the checkout page specifically, install the vendor's Shopify app if they offer one; hand-pasted <script> tags into theme.liquid do not reach checkout.
Theme updates overwrite code. When Shopify or your theme vendor releases an update and you accept it, your hand-pasted script in theme.liquid can be wiped. Two mitigations: (1) keep your theme in version control via the Shopify CLI, or (2) note the script in your team's deploy-day checklist so re-pasting is routine.
App blocks are the "proper" path for apps. If your chat widget is distributed via a Shopify app (and not a raw script tag), install it through the Shopify App Store and enable the App embed in the theme editor's left sidebar under App embeds. That survives theme updates because the app, not your theme, owns the embed.
Password-protected / coming-soon storefronts. If your shop is behind Shopify's password page, theme.liquid does not render on that splash. Your widget will only appear once the shop is public or the visitor enters the password.
What this doesn't cover
- Installing via a Shopify App instead of pasting code. If your chat vendor has a Shopify App Store listing, use it. Use the App embed toggle in the theme editor rather than pasting script tags.
- Scripting the checkout page. Covered in brief above — Checkout Extensibility is the current path; the vendor's Shopify app is the practical answer for most merchants.
- Removing the widget. Delete the
<script>tag from theme.liquid, click Save. If it persists, you also need to disable the app embed in the theme editor — two places to check. - Multiple chat widgets. Don't. Running two at once doubles-fires events, confuses routing, and the second widget almost always fails to render on top of the first. Pick one.
Why your users shouldn't have to read this
If you're a SaaS founder reading this and nodding grimly — because right now your Shopify-merchant users are out there, bouncing between theme.liquid and the theme editor HTML block and the App embed sidebar trying to figure out which one actually works — you're in the right place for a different reason.
The install step your users hit is full of platform quirks like this one. Shopify vs. Shopify Plus, theme.liquid vs. the editor, checkout being a separate surface, theme updates eating your code. Every one of those is a support ticket waiting to happen, or — worse — a merchant who gives up halfway through and churns before they ever see value.
We built Inboard for exactly this shape of problem. Your users drop into a widget on your dashboard that walks them through the install on their platform with their click path and verifies the script fired before they close the tab. If your SaaS ships a chat, support, or embedded widget that merchants install on Shopify (and WooCommerce, and Wix, and all the other storefronts this guide doesn't cover), this is the page for you.
If you're the merchant — you got what you needed above. Close the tab. The chat button's in the bottom-right.