Skip to main content
Share
Guides

Chat Widget Not Showing on Your Website? Work These 11 Causes in Order

A chat widget that works in preview and vanishes in production is almost always one of eleven things - a CSP directive, a z-index, a consent manager, a cached page or a script in the wrong place. Ordered by how often each turns out to be the answer.

Content & Engineering
Aug 5, 2026
13 min read
Updated Aug 2026Expert Reviewed
chat widget not showing on websitechatbot widget not appearinglive chat widget not loadingcontent security policy blocking chat widgetchat widget z-index issue
TL;DR

A chat widget that works in preview and vanishes in production is almost always one of eleven things - a CSP directive, a z-index, a consent manager, a cached page or a script in the wrong place. Ordered by how often each turns out to be the answer.

Key Takeaways
  • Before touching any setting, open DevTools with F12 (or Cmd+Option+I on Mac) and read the Console tab.
  • A widget that fails to appear almost always leaves an error there, and the error normally names the exact cause.Last verified: August 2026.
  • The diagnostic sequence below applies to any embedded chat widget, not one product in particular.Match what you see against this table and jump straight to the relevant section.Console outputCauseSection"Refused to load the script ...
  • Content Security Policy"CSP is blocking it1404 or net::ERR_ on the widget scriptWrong URL, or a blocker2, 3Nothing at all, no widget request in NetworkScript never ran - placement or caching4, 5Script loads 200, still nothing visibleCSS - z-index, overflow, or a container6"Uncaught TypeError" from another scriptAn earlier JS error halted execution7Then check the Network tab, filter for the widget domain, and note whether the request appears at all.

Open the console first - it usually names the cause

Before touching any setting, open DevTools with F12 (or Cmd+Option+I on Mac) and read the Console tab. A widget that fails to appear almost always leaves an error there, and the error normally names the exact cause.

Last verified: August 2026. The diagnostic sequence below applies to any embedded chat widget, not one product in particular.

Match what you see against this table and jump straight to the relevant section.

Console outputCauseSection
"Refused to load the script ... Content Security Policy"CSP is blocking it1
404 or net::ERR_ on the widget scriptWrong URL, or a blocker2, 3
Nothing at all, no widget request in NetworkScript never ran - placement or caching4, 5
Script loads 200, still nothing visibleCSS - z-index, overflow, or a container6
"Uncaught TypeError" from another scriptAn earlier JS error halted execution7

Then check the Network tab, filter for the widget domain, and note whether the request appears at all. "Request never made" and "request made and blocked" are entirely different problems, and this distinction saves the most time of any single check - it separates the loading-side sections of this guide from the CSS-side ones before you have read a single one of them, and it takes less time than reading this paragraph did.

1. Content Security Policy is blocking the script

The console message is unambiguous:

Refused to load the script 'https://widget.example.com/loader.js'
because it violates the following Content Security Policy directive:
"script-src 'self'"

CSP restricts which domains may serve scripts, styles, images and connections. It is a genuinely valuable security control, and it blocks third-party widgets by default unless you allow them explicitly.

The four directives a chat widget usually needs

DirectiveWhy the widget needs it
script-srcLoad the loader and the widget bundle
connect-srcAPI calls and the WebSocket that carries live messages
img-srcAvatars, uploaded images and icons
style-srcWidget styling, often injected inline at runtime

A partial allowance produces the most confusing symptom of all: the launcher appears but the conversation never connects, because script-src was allowed and connect-src was not. If your widget opens and then sits loading forever, check connect-src first - and remember WebSocket URLs use the wss: scheme, which must be permitted explicitly.

The 'unsafe-inline' problem

Many widgets inject inline <style> tags at runtime. Under a strict policy without 'unsafe-inline' in style-src, the browser blocks those styles and you get an unstyled or invisible widget - the script loaded successfully, so the console shows no script error and the failure looks like a rendering bug.

Where a nonce-based policy is in place, most vendors document a way to pass the nonce to the widget. Check the integration docs before weakening the policy globally.

Where the CSP actually comes from

Look in three places, because teams often edit one and miss the others: a Content-Security-Policy HTTP response header from your server or framework config, a <meta http-equiv="Content-Security-Policy"> tag in the document head, and your CDN or WAF - Cloudflare, Vercel and similar platforms can inject or modify headers independently of your application.

If the widget uses an iframe, script-src is not enough

Some widgets render their conversation panel as a script-injected DOM tree; others load it inside an <iframe> pointed at the vendor's domain, which is a common way to sandbox the widget's styles and scripts away from the host page. An iframe is governed by a different directive entirely - frame-src, falling back to child-src and then default-src if neither is set. Allowing the widget's domain in script-src does nothing for its iframe: the outer loader script runs fine, requests the panel, and the browser silently refuses to create the frame. This produces a symptom easy to mistake for a CSS bug - the launcher button appears and is clickable, but nothing opens when you click it - so if connect-src checks out and the panel still never appears, check frame-src next.

CSP directiveGovernsSymptom when missing
script-srcLoading the widget's JS bundleConsole error, nothing renders at all
frame-srcCreating an iframe for the panelLauncher shows, panel never opens
connect-srcAPI and WebSocket callsPanel opens, stuck loading forever

2. Ad blockers, privacy extensions and tracking protection

Many blocklists include chat and support widgets under "tracking", so a widget that is entirely functional simply never loads for a meaningful share of visitors.

Test in a private window with all extensions disabled. If the widget appears there and not in your normal browser, an extension is the cause. Also try a second browser: Brave blocks aggressively by default, and Safari's Intelligent Tracking Prevention affects some third-party storage patterns even without an extension installed.

You cannot fix this for your visitors, and that is worth accepting rather than fighting. What you can do is make sure the widget is not your only contact route - a visible email address, phone number or contact page means a blocked widget costs you a convenience rather than a conversation.

Note also that corporate networks frequently block unknown third-party domains at the firewall. If the widget works everywhere except at one client's office, that is why, and it is resolved by their IT team allowlisting the domain rather than by anything on your side.

Storage partitioning is a quieter version of the same problem

Even when nothing blocks the script outright, browsers increasingly partition or restrict storage for third-party contexts by default - Safari's Intelligent Tracking Prevention caps or clears script-writable storage for classified trackers, and other browsers are moving toward partitioning cookies and storage per top-level site rather than sharing them across every site that embeds the same widget. The visible symptom is not a missing widget but a forgetful one: it loads and opens fine, yet a returning visitor's conversation history is gone, or a session that should persist across a page reload does not. If a widget worked identically to how it works now but the browser vendor tightened this policy, this is usually the explanation, and it is a platform trend rather than a one-time bug to patch.

Try it yourself
Build your first chatbot free
Free plan, no credit card required. Live on your site in about 10 minutes.
Start building free

3. The script is in the wrong place, or never runs

If the Network tab shows no request for the widget at all, the script never executed. Common reasons, in order:

Pasted outside the document

The snippet must sit inside <head> or <body>. Pasted after </html> - which happens easily in a CMS footer field - browsers may ignore it entirely.

An earlier JavaScript error stopped execution

Scripts run in order, and an uncaught error in an earlier script halts the rest of that block. If the console shows a TypeError from an unrelated script above your widget snippet, fix that first - the widget is a victim, not the cause. This is why the widget sometimes "stops working" after an unrelated site change.

Installed in a template that does not render on every page

Placing the snippet in a specific page template rather than the global layout means it appears on some routes only. Check whether it is missing on all pages or just some - the answer localises the problem immediately.

Single-page apps and route changes

In React, Vue, Next.js and similar frameworks, a widget initialised once on mount may not survive client-side navigation, or may double-initialise. The symptom is a widget present on first load that disappears after navigating. Initialise it at the application root rather than inside a page component, and guard against double-initialisation. Our guides on embedding a chatbot in React, Next.js, Vue and Angular cover the framework-specific patterns.

A tag manager that is not firing

If you installed via Google Tag Manager, the tag may be unpublished, restricted by a trigger condition, or blocked by consent mode. Check in GTM Preview whether the tag actually fires on the page you are testing - an unpublished container is the single most common GTM cause.

4. Caching - you are looking at an old page

You installed the widget, the code is correct, and the live site still shows the previous version. Between you and your HTML there may be several caches, and clearing one is rarely enough.

  • Browser cache. Hard reload with Ctrl+Shift+R (Cmd+Shift+R on Mac), or test in a private window.
  • CDN cache. Cloudflare, Fastly and similar hold HTML at the edge. Purge the cache from the provider dashboard.
  • Platform or plugin cache. WordPress caching plugins, Shopify's theme cache, and static site builds all serve pre-rendered HTML. Clear the plugin cache and, for static sites, trigger a fresh build - editing the template is not enough if nothing rebuilt.
  • Service worker. A PWA service worker can serve a cached shell indefinitely. Check Application -> Service Workers in DevTools and unregister it to test.

The fastest way to confirm caching is the culprit: view page source (Ctrl+U) and search for your widget's domain. If the snippet is not in the source, the browser never had a chance - the problem is upstream in your build or cache, not in the widget.

Calculate your chatbot ROI
See exactly how much a chatbot saves your business. Free calculator, no signup required.
Try Calculator

6. It loaded and it is invisible: the CSS causes

The script returns 200, no console errors, and still nothing. The widget is on the page and something in your CSS is hiding it. Confirm by searching the Elements panel for the widget's container element - if it exists in the DOM, this section is your answer.

z-index

The most common cause. A sticky header, a promotional banner, a cookie bar or a full-page overlay with a higher z-index renders on top. Widgets typically use a high value such as 999999, so a competing element needs an absurd one - and site-wide overlays often have exactly that.

Inspect the element sitting where the widget should be. If it is not your widget, that element is covering it.

A parent with overflow: hidden

A widget injected inside a container with overflow: hidden gets clipped out of view. Widgets are normally appended to <body> to avoid this, but a script that runs inside a component tree can end up nested. Check where the widget's element actually sits in the DOM.

Aggressive global CSS resets

Rules such as div { position: static !important; } or blanket * { } selectors carrying !important can override the widget's positioning. Third-party widgets normally scope their styles, but a sufficiently aggressive global rule wins anyway.

Mobile-specific hiding

If the widget shows on desktop and not on mobile, check for a media query hiding it - some themes hide floating elements below a breakpoint deliberately to protect the viewport. Also check the widget's own settings, since most offer a mobile visibility toggle that is easy to leave off.

Positioned off-screen

Custom offset settings that place the launcher 200px from the bottom work on a tall desktop viewport and push it out of a short mobile one. If the element exists with sensible dimensions but is not visible, check its computed bottom and right values against the viewport size.

Shadow DOM changes where these rules apply

Many widgets attach their markup inside a shadow root - an isolated DOM subtree created with element.attachShadow() - specifically to avoid the global-reset and z-index problems above: styles inside a shadow root do not leak in either direction across its boundary by default. That isolation is also why some general-purpose CSS debugging habits stop working. Selecting the widget in the Elements panel shows a #shadow-root node rather than the widget's markup directly under <body>, and a browser extension or site script that walks the DOM with document.querySelector will not find elements inside it unless it explicitly pierces the shadow boundary. If you are trying to style or debug a shadow-DOM widget from outside its own settings panel, most of the CSS overrides in this section simply cannot reach it - which is by design, not a bug to work around.

7. Configuration: it is working exactly as configured

Finally, a category that is not a bug at all. Check these in the widget's own dashboard before spending more time in DevTools.

  • Domain allowlist. Most widgets restrict which domains may load them. A widget configured for example.com will not load on staging.example.com, on www.example.com if only the bare domain was added, or on a preview deployment URL. This is by far the most common configuration cause.
  • Business hours. A widget set to appear only during business hours is invisible outside them, exactly as intended - and this is a favourite cause of "it works for me but not for our overseas team".
  • Page targeting rules. Show/hide rules based on URL patterns can exclude more than intended, particularly when a rule was written for a path that has since changed.
  • Bot paused or unpublished. A flow in draft, or paused during editing, may stop the widget rendering at all rather than showing an empty one.
  • Time or scroll delay. A launcher configured to appear after 30 seconds or 50% scroll is not missing during the first few seconds of testing.

The domain allowlist deserves a specific test: compare the domain in the browser address bar, character for character, against the allowlist entry. www versus bare domain accounts for a surprising share of these, and so does a preview or staging subdomain that nobody thought to add because it did not exist when the allowlist was first configured.

The diagnostic sequence

Worked in this order, the cause is normally identified within a few minutes.

#CheckTells you
1View source, search for the widget domainAbsent = build or cache problem, not the widget
2Console tabCSP violations and JS errors name themselves
3Network tab, filtered to the widget domainRequest absent vs blocked vs 200
4Private window, extensions offIsolates ad blockers and stale cache together
5Accept all cookies, then reloadIsolates the consent manager
6Search Elements for the widget containerPresent = CSS problem; absent = loading problem
7Widget dashboard: domain, hours, targetingWorking as configured rather than broken

Step 1 is the highest-value check in the list. If the snippet is not in the page source, nothing about the widget itself can be the cause, and you have eliminated six of the seven sections instantly.

8. It is loading, just not when you are looking

Some widgets are present and functional but appear late enough that a quick check concludes they are missing. Worth ruling out before deeper debugging.

Deferred loading

Many widgets deliberately delay initialisation until after the page's main content, to protect Core Web Vitals. On a slow connection that can be several seconds. Watch the Network tab rather than the viewport - if the request fires eventually, the widget is working and the question is whether the delay is acceptable.

Lazy-loading tied to interaction

Some installations only load the widget after first scroll, mouse movement or a timer. If you load the page and immediately screenshot it, you will conclude it is broken. Scroll, wait, and move the mouse before judging.

Slow third-party responses

If the widget request is pending for many seconds, the vendor's edge may be slow or degraded from your region. Check the vendor status page. This is also worth measuring: a widget that consistently takes 4 seconds to appear is costing you conversations even though it technically works.

The performance trade to be aware of

Widgets are third-party JavaScript and they have a cost - typically some main-thread work and a WebSocket connection. If Lighthouse flags your chat widget, the answer is usually to defer it rather than remove it, but check that your deferral is not so aggressive that visitors leave before it appears. Measure the actual time-to-launcher on a throttled connection and decide deliberately. The Core Web Vitals metric most relevant here is INP (Interaction to Next Paint), which replaced FID as Google's responsiveness metric - it measures the delay on every click and tap across the page's lifetime, not just the first one. A widget that parses a large bundle on the main thread right as a visitor clicks something else can show up as an INP regression even though the widget itself looks and works fine; the fix is the same deferral and chunking discipline as any other non-critical third-party script, not something specific to chat widgets.

9. Platform-specific traps: Shopify, WordPress, Wix, Webflow

Hosted platforms each have a characteristic way of losing your script.

Shopify

Code added to theme.liquid is lost when the theme is updated or replaced, which is the classic "the widget disappeared and nobody changed anything" report. Prefer a theme app extension or the script tag API where available. Also note that the checkout pages are separate and generally do not run theme code - a widget present on product pages and absent at checkout is expected behaviour, not a bug.

WordPress

Three things interfere routinely. Caching plugins serve stale HTML, so purge after installing. JavaScript minification and combination features in performance plugins can mangle third-party snippets - exclude the widget script from optimisation. And theme updates overwrite edits made directly to header.php or footer.php; use a child theme or a code-insertion plugin so the snippet survives.

Wix

Custom code is added through Settings rather than by editing pages, and each snippet has an explicit page-scope setting - "all pages" is not always the default. Wix also loads custom code inside a sandboxed context in some configurations, which can affect widgets expecting direct DOM access.

Squarespace and Webflow

Both distinguish site-wide code injection from per-page code, and both require a republish for changes to reach the live site. Editing the injection field and not publishing is the single most common cause of a widget that is "installed" and absent. On Webflow, also check that you added the code to the correct project and to the published domain rather than only the staging subdomain.

A general rule

On every one of these platforms, the definitive test is the same: load the live URL, view source, and search for the widget domain. If it is not there, the platform did not publish it, and no amount of widget-side configuration will change that. Platform-specific installation steps are covered in our guides for Shopify, WordPress, Wix, Squarespace and Webflow.

Installing a widget that stays installed

Most of the failures above are environmental rather than product-specific - CSP policies, consent managers, caching layers and z-index wars affect every embedded widget equally. What differs between products is how much they help you diagnose them.

Conferbot's website widget is available on the free plan and installs with a single script tag on Shopify, WordPress, Wix, Squarespace, Webflow and plain HTML, with framework guides for React and Next.js and a native mobile SDK for iOS, Android, React Native and Flutter when a web widget is not the right surface - a native app has no DOM, no CSP and no ad blockers to work around, so most of this guide simply does not apply there. The same conversation flow also runs on WhatsApp and Telegram, which matters more than it sounds: a visitor whose browser blocks third-party widgets can still reach the same bot on a channel their browser has no opinion about.

Start free with Conferbot - 600 conversations a month, no credit card required.

Debugging right now? Start with step 1. Whether the snippet appears in view-source decides which half of this guide you need, and it takes ten seconds.

Share this article:

Was this article helpful?

Ready to build your chatbot?

Join the businesses. Deploy on website, WhatsApp, and 11 more channels in minutes. Free forever plan available.

No credit cardNo coding13+ channels
Start Building Free

Get chatbot insights delivered weekly

Join 5,000+ professionals getting actionable AI chatbot strategies, industry benchmarks, and product updates.

🎯Automate this with a free chatbot

Build and deploy in 10 minutes. No coding needed.

FAQ

Chat Widget Not Showing on Your Website? Work These 11 Causes in Order FAQ

Everything you need to know about chatbots for chat widget not showing on your website? work these 11 causes in order.

🔍
Popular:

Open DevTools and check the Console and Network tabs first - the cause usually names itself. The most common reasons are a Content Security Policy blocking the script, a caching layer still serving the old page, a cookie consent manager holding the script until consent is given, a z-index conflict hiding it behind another element, or a domain allowlist that does not include the exact domain you are testing.

Add the widget's domains to four CSP directives: script-src for the bundle, connect-src for API calls and the WebSocket (remember the wss: scheme), img-src for avatars and uploads, and style-src for injected styling. Allowing only script-src produces the classic symptom of a launcher that appears but never connects. Check for the policy in your response headers, a meta tag, and your CDN or WAF, since teams often fix one and miss the others.

Usually a domain allowlist mismatch or caching. Compare the live domain character for character against the widget's allowlist - www versus the bare domain is a frequent culprit. Then check whether the snippet actually appears in view-source on the live page; if it does not, a CDN, caching plugin or static build is serving an older version.

Almost always a partial CSP allowance: script-src permits the bundle to load so the launcher renders, but connect-src blocks the API calls and WebSocket the conversation needs. Add the widget's API and WebSocket domains to connect-src, and make sure the wss: scheme is permitted explicitly.

A z-index conflict. A sticky header, promotional banner, cookie bar or full-page overlay with a higher z-index is rendering on top. Inspect the element occupying the widget's position - if it is not your widget, that element is covering it. Also check for a parent container with overflow: hidden clipping the widget out of view.

Yes, and it is easy to miss because the installation is otherwise correct. Consent platforms rewrite script tags to type="text/plain" until the visitor consents to the relevant category, and scanners often auto-classify unknown third-party domains as marketing. Check the rendered HTML for type="text/plain" on your widget tag, and review whether the widget is categorised correctly for your compliance position.

The widget was initialised inside a page component rather than at the application root, so client-side navigation unmounts it - or it double-initialises on each route change. Initialise once at the root layout and guard against re-initialisation. Framework-specific patterns differ enough that it is worth following a guide for your stack.

Frequently, yes - many blocklists categorise chat and support widgets as tracking. Test in a private window with extensions disabled, and try Brave or Safari, which block more aggressively by default. You cannot fix this for visitors, so make sure the widget is not your only contact route and consider offering a messaging channel like WhatsApp or Telegram as an alternative.

Check three things: a media query in your theme hiding floating elements below a breakpoint, the widget's own mobile visibility toggle in its dashboard, and custom position offsets that work on a tall desktop viewport but push the launcher off a short mobile one. Inspect the element's computed bottom and right values against the viewport size.

View page source with Ctrl+U and search for the widget's domain. If the snippet is not in the source, the browser never had a chance to run it and the problem is in your build, template or cache rather than the widget. If it is present, open the Network tab and check whether the request was made at all, blocked, or returned 200.

The snippet is installed in a specific page template rather than the global layout, or a page-targeting rule in the widget dashboard excludes those URLs. Determine whether it is missing on all pages or just some - that single distinction localises the problem immediately.

Yes. Scripts execute in order, and an uncaught error in an earlier script halts the rest of that block. If the console shows a TypeError from an unrelated script above your snippet, fix that first - the widget is a victim rather than the cause. This is why a widget can stop working after a site change that had nothing to do with it.

About the Author

Content & Engineering

The Conferbot team writes about building, deploying, and improving AI chatbots.

View all articles
Skip the blank canvas
Start from one of 250+ free chatbot templates for lead generation, support, e-commerce, and 20+ industries - customize and launch in minutes.
Browse free templates

Related Articles

Omnichannel Platform

One Chatbot,
Every Channel

Your chatbot works seamlessly across WhatsApp, Messenger, Slack, and 6 more platforms. Build once, deploy everywhere.

View All Channels
Conferbot
online
Hi! How can I help you today?
I need pricing info
Conferbot
Active now
Welcome! What are you looking for?
Book a demo
Sure! Pick a time slot:
#support
Conferbot
New ticket from Sarah: "Can't access dashboard"
Auto-resolved. Password reset link sent.