Running it

Troubleshooting

The four things that account for nearly every support message about a fresh install.

The widget does not appear.

Check three things in order: that you are looking at the published site rather than an editor preview, since several platforms do not run custom code in preview; that the current domain is on the allow-list, including the www variant; and that the snippet landed before the closing body tag rather than somewhere the platform strips scripts.

It refuses things it should know.

Almost always a coverage problem rather than a tuning one. Open the source list and confirm the page that answers the question was actually crawled — pages linked from nowhere are never discovered. If it is missing, add it directly; if it is not written yet, the gap report will keep reminding you.

An answer is wrong but confident.

Read the citation. A wrong answer with a citation nearly always means the cited page is out of date — an old pricing or policy page that is still indexed. Stale content is worse than missing content, because it produces authoritative answers with a source attached.

The API returns 403.

API access is an Agency plan feature and is checked on every request rather than when the key is created. A key that worked yesterday and 403s today usually means the plan changed, not the key.

The widget still will not load

13 reasons a correct install still shows nothing, grouped by what you can see. The ones marked seen in the wild are the ones that actually stopped a real integration.

Start here: the whole CSP, in one edit

Content Security Policy accounts for most widgets that never appear. These are every directive the widget needs — set them together and you will not meet them one deploy at a time.

Content-Security-Policy:
  script-src  'self' https://app.matterchat.co;
  connect-src 'self' https://app.matterchat.co wss://app.matterchat.co;
  frame-src   https://app.matterchat.co;
  font-src    'self' https://app.matterchat.co data:;

Nothing appears at all

The loader is usually fine and the page is usually right. Four times out of five this is Content Security Policy, and the browser console says so in one line.

A strict CSP blocks the inline snippetSeen in the wild

The loader downloads without error and nothing renders. The console reads: Executing inline script violates the following Content Security Policy directive 'script-src …'.

Why

The install snippet sets your bot id in an inline <script>. A site running script-src 'self' without 'unsafe-inline' refuses to execute it, so the loader arrives with no idea which bot it belongs to and quietly does nothing.

Fix

Move the two init lines into a file on your own origin, load it with src, and keep the loader <script> exactly as the install page gave it to you. Do not add 'unsafe-inline' — that reopens your whole page to injected script to fix one widget, and it cannot be scoped to a single tag.

// matterchat-init.js — the two lines the inline <script> was running
window.MatterChat = window.MatterChat || { q: [] };
window.MatterChat.q.push(["init", { id: "YOUR_BOT_KEY" }]);
CSP does not list the loader host

Console: Loading the script 'https://app.matterchat.co/loader.js' violates the following Content Security Policy directive.

Fix

Add https://app.matterchat.co to script-src.

The loader tag lost its crossorigin attribute

The loader is refused and the console mentions the integrity check, even though the hash is the right one for that file.

Why

integrity and crossorigin="anonymous" only work as a pair. Without the crossorigin attribute the browser will not expose the response to the integrity check, so it cannot verify the hash and blocks the script rather than risk running it.

Fix

Paste the loader tag whole. If a CMS or template strips attributes it does not recognise, that is the thing to fix — dropping integrity to match is trading a real guarantee for a formatting convenience.

CSP is missing frame-src or font-src

The launcher renders but the panel is blank, or the text falls back to a system font.

Why

Only bites when the widget frames content or loads its webfont, which is why it tends to surface days after the first two fixes rather than alongside them.

Fix

Set every directive the widget needs in one edit — the block above — instead of discovering them one deploy at a time.

The launcher appears, but it cannot talk

The script ran. What fails now is the connection back, and these fail silently by design — nothing is shown to the visitor.

The origin is not on the bot's allow-listSeen in the wild

Nothing mounts, and the network tab shows GET /api/widget-config returning 404. The console says: “Matter Chat: this assistant is not allowed on <your host>.”

Why

The bot is scoped to your production domain, so localhost and staging are refused. The 404 looks like a wrong URL and sends people hunting for a typo — check the console before you do, because it names the host and the exact setting.

Fix

Add your local and staging origins to the bot's allowed domains, under Settings → Access → Allowed domains, alongside production. www counts as the same site; every other subdomain needs its own entry.

CSP does not allow the socket

The launcher opens, the visitor types, and messages never send. The console names connect-src.

Why

Chat needs both the HTTPS origin and the WebSocket one, and the WebSocket scheme is a separate entry — allowing https:// alone is the common near-miss.

Fix

Add both https://app.matterchat.co and wss://app.matterchat.co to connect-src.

A CDN is still serving the page without the snippet

You added the snippet, and view-source disagrees.

Fix

Purge the CDN cache, or load the page with a cache-busting query string to confirm what the origin is really sending before you change anything else.

It works, but the environment gets in the way

Nothing here is broken. These are the things that make a working widget look broken, and most of them are worth knowing before you go looking.

Your tests cannot find the widget

document.querySelector('.launcher') returns null even though the launcher is visible on screen.

Why

The widget mounts inside a shadow root, which is what stops your CSS and ours from reaching into each other. Shadow roots are also invisible to ordinary selectors.

Fix

Find the host element by its [data-matter-chat] attribute, then query through its shadowRoot. The root is opened deliberately so you can, and this is the same path our own tests take.

const host = document.querySelector("[data-matter-chat]");
const launcher = host.shadowRoot.querySelector("button.launcher");
Client-side routing loses or duplicates it

The widget is there on first load and gone after navigating, or two launchers appear.

Why

On single-page apps and Astro view transitions, a script that runs once on load may never run again — or run again on every navigation.

Fix

Load the snippet once at the app shell level rather than inside a page or route component. Init is idempotent, so a second call is ignored rather than doubling the launcher.

An ad blocker or privacy extension removes it

It works for you and not for one particular colleague.

Why

Chat widgets are a common blocklist category, so this is not specific to us.

Fix

Test in a private window with extensions disabled before spending time on the integration itself.

Two launchers

The snippet ended up in a layout and in a page, so it runs twice.

Fix

Keep it in exactly one place. A second init is ignored, so this is usually harmless — but it was not always: the framed path once lacked that guard and built a second iframe over the first, which is what an opaque white rectangle over the page turned out to be.

It loads before the visitor has consented

Not a bug you will see — a compliance problem you will be told about, especially in the EU.

Why

Loading any third-party script on page load is a choice your privacy policy has to cover.

Fix

Defer the loader until consent is given, and call init from your consent callback. The same path suits privacy-focused sites that would rather nothing third-party ran before an interaction.

An integrity attribute blocks a new loader

The widget stops after a release, with a console message about a resource failing an integrity check.

Why

An integrity hash pins one exact file, so a build published at the same URL would stop matching and be refused outright. The snippet already avoids that: the loader is served from a versioned path, so a new build gets a new URL and the hash you pasted keeps matching the file it was taken from. This bites when the pair is broken by hand — a version edited without its hash, or a hash copied onto a different URL.

Fix

Keep the src and the integrity value together as the install page issued them, and re-copy both from the install page when you move to a new build. Deleting integrity makes the error go away and drops the guarantee that a compromised CDN cannot serve different code than you approved.