Add an AI support assistant to a Svelte or SvelteKit site
The whole appeal of Svelte is shipping very little JavaScript. One call in your root layout — or two lines in app.html — and the widget itself never enters your bundle.
- One function
- About two minutes
- One file
pnpm add @matterchat/svelte<script> import { onMount } from "svelte"; import { loadMatterChat } from "@matterchat/svelte"; onMount(() => { loadMatterChat({ publicKey: "bot_your_key" }); });</script> <slot />svelte · call it once
Where the call goes
Install @matterchat/svelte and call loadMatterChat({ publicKey }) from onMount in src/routes/+layout.svelte. It only ever touches the browser, so it is safe in a layout that also renders on the server, and onMount runs it once per page rather than once per render. If you would rather add nothing to package.json, paste the two lines into src/app.html — or index.html for a plain Vite Svelte app.
- SvelteKit: +layout.svelte
- One call in onMount covers every route. Svelte 4 or 5, legacy or runes — the call is the same.
- Or as an action
- use:matterChat on any element is the same function, for a component-scoped install. The element is left untouched.
- Script tag: src/app.html
- The shell every route renders into, before the closing body tag. Same widget, no package.
- Outside the bundle
- The widget is fetched at run time, never imported, so your build output is unchanged.
loadMatterChat only ever touches the browser, so it is safe in a layout that also renders on the server — but keep it inside onMount, because the widget needs loading once per page, not once per render. The same function is available as use:matterChat if you would rather attach it to markup.
Next to nothing in your build output
The package is a few hundred bytes and imports nothing from svelte at run time — it adds one script tag, and the widget it fetches never passes through your compiler, so widget updates need no version bump. The script tag route adds nothing to the build at all, and the widget loads asynchronously afterwards either way.
What the crawler sees on SvelteKit
Our crawler reads served HTML without executing JavaScript. SvelteKit's default server-side rendering means your pages arrive as complete documents, so a crawl works out of the box — and adapter-static output is exactly as crawlable.
Server rendering stays intact
SvelteKit renders on the server by default. loadMatterChat returns early when there is no window, onMount never runs there, and an external script never executes during that render — so there is no reference to guard and no hydration mismatch to debug.
Checking it actually worked
Four things, in order. The third is the one people skip, and it is the one that tells you whether the answers are grounded.
- 1Hard refresh the page — the launcher appears bottom-right.
- 2Ask it something your site answers, and check the reply cites a page.
- 3Ask it something your site does not cover, and check it declines.
- 4Open Conversations in the dashboard; both should be there.
On a different stack?
The snippet is the same everywhere. Only the place you paste it changes.
What developers ask
Short answers. If yours is not here, the assistant on this page will try it — and tell you honestly if it cannot.
Does the crawler handle SvelteKit's rendered pages?
Yes — SvelteKit renders on the server by default, so pages arrive as complete HTML and crawl like a static site. Only routes that opt out with ssr = false are invisible to a fetch-based crawler.
Where exactly does it go in SvelteKit?
Inside onMount in src/routes/+layout.svelte, so one call covers every route. The script-tag alternative is src/app.html before the closing body tag — the shell every route renders into.
Does it affect my bundle size?
By a few hundred bytes if you use the package: it imports nothing from svelte and only adds a script tag. The widget itself is one runtime request loaded asynchronously and is never bundled. The script tag route adds nothing.
Will it break SSR?
No. loadMatterChat does nothing without a window and onMount never runs on the server; the script tag does not run during server rendering either.
From the blog
All posts- BuildingDomain locks and why “works on localhost” isn’t enoughDomain allowlists exist so your bot answers only where you installed it. Testing on localhost proves the script loads; it does not prove production embeds are locked down.Read
- EvaluatingThe best AI chatbot for a Webflow site, compared honestly (2026)Matter Chat, Social Intents, Ultimo Bots, Chatling, WeblyChat and Chatbase on a Webflow site: Apps marketplace or custom code, the paid-site-plan gate, CMS coverage, citations, handoff and pricing. Checked on the vendors' own pages.Read
- BuildingWhat to index first when your site is a messStart with the pages that already resolve real support questions. Noise, archives, and unfinished docs can wait — indexing them first makes answers worse.Read
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.
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.


