For developers

A support widget that does not own your frontend

A script tag, or a one-component package if you would rather. Either way nothing wraps your component tree, the widget itself stays out of your bundle, and removing it is deleting two lines.

A developer at a two-monitor desk in a sunlit office, leaning back with a pleased grin.
What you will hear back

“Every support tool ends up owning part of the frontend.”

And the honest answer

Usually true, and the reason is the SDK. This is a script tag — or, if you prefer, a one-component package that does nothing but add that tag. Either way nothing wraps your component tree, there is no provider to thread through, and the widget itself is fetched at run time rather than bundled. Removing it is deleting two lines and shipping.

The case, in the order it lands

  1. 01

    No provider, no upgrade path

    The package is optional and pins our loader rather than a widget build, so widget fixes arrive without a version bump. Paste the script tag instead and package.json never hears about us at all.

  2. 02

    It loads async and stays out of the way

    Never blocking parsing, outside the React tree, with no mount point and nothing to clean up on unmount.

  3. 03

    The public key is meant to be public

    Domain locks, per-visitor rate limits and a hard daily cap are what make that safe. You set the ceiling; you do not discover it.

Send this to whoever has to approve it

It is a script tag, or one optional component — no provider either way, and the widget itself never enters the bundle. The public key is domain-locked with per-visitor rate limits and a hard daily cap, and uninstalling is deleting two lines.

Support tools are usually somebody else's architecture in your app

The typical widget ships an SDK, wants a provider at the root, pulls transitive dependencies into your lockfile, and puts you on its release cycle. For something that renders in its own layer and shares no state with your application, that is a lot of coupling to accept.

  • Widget SDKs adding measurable weight to the bundle
  • Version bumps required for reasons unrelated to your app
  • Third-party scripts hurting hydration and Core Web Vitals
  • No way to bound what a runaway client costs you

Deliberately decoupled

The widget is an async external script, whether you paste the tag or render the component. It does not participate in hydration and does not care which framework or router you use. The optional package is a thin wrapper that adds the script for you — the widget itself is fetched at run time, so it never lands in your bundle.

No version treadmill
The package is optional, and it pins our loader rather than a widget build — so widget fixes reach you without a release or a version bump. Or skip it entirely and paste two lines.
Async, not bundled
It loads in parallel and never blocks parsing. Defer it further with next/script if you measure closely.
Framework-agnostic
React, Vue, Svelte, Angular, or plain HTML — it is the same two lines.
Removable in one edit
Delete the snippet. There is no cleanup, no orphaned config, no leftover integration.

Limits you set, not limits you discover

Usage-based tooling is a liability without a ceiling. Domain locks restrict which origins may serve the widget, per-visitor rate limits bound a single client, and a hard daily reply cap bounds the day. All three are set in advance.

Domain locking
A leaked key cannot be used to run up your usage from another origin.
Hard daily caps
The ceiling is a number you chose, not one you find on an invoice.

An API when you need one

On Agency there is a query and ingest API if you want to drive it programmatically — feed sources from a build step, or query the knowledge base from your own surface rather than through the widget.

Before you take this to anyone

It is a script tag, with everything that implies

It runs in the page, so it is subject to your CSP and to whatever else shares the document. If you run a strict policy you will need to allow the widget host. That is the whole integration surface, and it is worth knowing before you start rather than at review.

  • Loads asynchronously; it is not in the critical path
  • The key is public by design and safe because of the domain lock
  • Strict CSP needs the widget host allow-listed
  • There is no server-side SDK to run and no webhook you must receive

On Next.js use next/script with afterInteractive rather than a bare tag, or it re-initialises on client-side navigation.

Hands at a mechanical keyboard on a sunlit desk, a closed laptop and an open notebook beside them.

What you will check before installing

Short answers. If yours is not here, the assistant on this page will try it — and tell you honestly if it cannot.

Is there an npm package?

Yes — four, one each for React, Vue, Svelte and Angular under @matterchat/ — and all of them are optional. Each saves you writing the mount code and nothing else: the widget still renders in its own layer, shares no state with your app, and is fetched at run time rather than bundled. They pin our loader rather than a widget build, so they do not put you on a release treadmill. If your team would rather add nothing to package.json, the two-line script tag is the same install.

What does it do to Core Web Vitals?

It loads asynchronously, so it never blocks parsing or rendering. The plain snippet is an async script, which can still fetch during the critical window — in Next.js, load it via next/script with the afterInteractive strategy and it stays out of your Largest Contentful Paint entirely.

How do I stop a leaked key costing me money?

Domain locks mean the key only works on origins you listed, and per-visitor rate limits plus a hard daily reply cap bound the damage regardless. The key is a public identifier, so it is designed to be bounded rather than secret.

All solutions

Answer honestly. Capture the rest.

Point Matter Chat at your site and see what it can — and can't — answer. It's honest about both.

Start free — see it on your site

No credit card. 2 minute setup.

Every answer cites the source it came from. When there isn't one, it says so — and hands the visitor to you.

Installs on the tools you already run.