0 cookiesnothing loads before a clickunlimited teammatesreply from slack or discord<4kb launcherno per-seat tax

/blog / guides

how to add live chat to your website without slowing it down

· by kuba · 9 min read

A browser window with a plain page, the Spookat cat as the chat button in the corner and a 4 kb label next to it.

Live chat should cost your page almost nothing until a visitor actually wants to talk. This guide shows what a chat widget loads before the first click, what to check before you pick one, how to install Spookat in a few minutes, and how to prove in DevTools that your page stayed fast.

what a chat widget costs before anyone clicks

Most visitors never open the chat. They read, scroll, maybe buy, and leave. Whatever the widget loads on page load, every one of them pays for it, including the ones on a cheap phone with a weak signal.

That cost has four parts:

  • Bytes. JavaScript, CSS, fonts, images and often an iframe with its own document. JavaScript is the expensive kind: the browser downloads it, parses it and runs it on the main thread, the same thread that handles scrolling and taps.
  • Requests. Every request is a round trip, and requests to new domains also pay for a DNS lookup and a TLS handshake. A widget that phones home on load adds those to every page view.
  • Storage. Cookies, localStorage and IndexedDB written before any interaction. In the EU that can decide whether you need consent before the widget loads at all.
  • Main-thread time. Code that runs at startup competes with your own code. Lighthouse reports it as Total Blocking Time, and it shows up in your score.

The four widgets on our comparison pages loaded between 220 and 509 kb gzipped before anyone clicked. We measured that on 2026-09-26 by loading each widget on a blank test page and adding up the transferred bytes; the numbers and sources are on /vs. For scale, the text of this whole article is under 20 kb.

None of that is needed to show a button. A button is a few hundred bytes of HTML and CSS. Everything else (the chat panel, the connection to a server, the history) is only needed after someone clicks it.

what to check before you pick a widget

You can judge any chat widget with a browser and ten minutes. Here is what to look at, in order of how much it affects your visitors.

weight before the click

Open the vendor’s demo page or your own staging site, open DevTools, and reload with the cache disabled. Filter the Network tab by the vendor’s domains and add up the transferred size. Anything above a few kilobytes before a click is code your visitors download for a panel most of them never open.

requests before the click, and to whom

Count the requests and note the domains. A widget that talks to its API on page load is sending something about every visitor, at least that they exist and which page they are on. Some also load analytics or error tracking from third parties.

cookies and storage before the click

Look in the Application tab after a fresh load, without touching the widget. Cookies set by the widget’s domains, or storage keys it wrote, are the ones a consent banner may have to cover. We’re not your lawyer, and the rules differ by country, so ask yours what applies to your site. The simplest case to explain is a widget that stores nothing until the visitor starts a chat.

where your team replies

A chat is only as good as the reply. If answering means opening another dashboard, someone has to keep that tab open all day. If the chats land where your team already talks (Slack, Discord), a reply is one message in a thread.

what it costs when the team grows

Per-seat pricing charges you for every person who might answer. Per-resolution pricing charges you for every answer. Per-site pricing charges you for the site, whoever answers and however often.

the phone

Check the launcher on a 375 px wide screen. It should not cover your own buttons, and it should be at least 44 px so a thumb can hit it. Open the panel and type: the keyboard should not hide the input.

step by step: live chat with spookat

Spookat is built around the checks above. The snippet loads one small launcher from our CDN, with your site’s look already inside. It makes 0 requests to our API before a click and sets no cookies. Your team answers in a Slack thread or a Discord forum post. It costs $4.99 a month per site on broke af, with unlimited teammates, and the trial is 14 days with no card.

1. get your snippet

Sign in to the dashboard and add your site. The install page shows your snippet with your site key already in it, and a copy button. You can open it directly with your domain in the address:

https://app.spookat.com/install?domain=your-domain.com

2. paste it before the closing body tag

One tag, anywhere in the page, ideally right before </body>:

<script src="https://cdn.spookat.com/s/YOUR_SITE_KEY.js" async></script>

async means the browser keeps rendering your page while it fetches the file, and runs it when it arrives. The file is the launcher: a button, its styles and the look you published in the dashboard. Its build fails if it grows past 4 kb gzipped. On 2026-09-27 it measured 2.0 kb.

If your site is a single-page app, put the tag in the root HTML template, not in a component that re-renders. The launcher checks whether it already exists, so a second copy does nothing, but one tag in one place is easier to reason about.

3. pick a look

There are 8 styles and 12 self-hosted fonts, plus the visitor’s system font. Choose them in the dashboard and publish; the launcher picks up the new look within a minute. Or set it on the page, above the snippet, where it wins over the dashboard:

<script>
  window.Spookat = { style: "clean", font: "system", accent: "#2F6FEB", side: "right" };
</script>
<script src="https://cdn.spookat.com/s/YOUR_SITE_KEY.js" async></script>

font: "system" downloads no font at all. Any other font comes from our CDN, only after the click, never from Google. accent takes a hex color, and the text on it is picked for contrast. The full list of keys is in the docs.

4. connect slack or discord

In the dashboard, connect a channel. You approve the connection in Slack or Discord itself, then pick the channel from a list. Not an admin of the workspace? The dashboard gives you a one-time link for whoever is, valid for 7 days, and they don’t need a Spookat account.

From then on every conversation is a thread in Slack or a forum post in Discord.

5. reply from the thread

Reply in the thread and the visitor sees it in the widget. A message that starts with // stays internal, so you can ask a teammate without the visitor reading it. Visitors see your first name from Slack or your Discord nickname; /spookat me shows or changes it, per site.

If the visitor left before you replied and gave an email, cool guy and up send them the reply by email, in the widget’s language. On broke af the reply waits in the widget for their next visit.

or: let your agent do all of it

If you build with Claude Code, Cursor or another coding agent, paste this and let it read the manual:

Add Spookat chat to my site. Read https://spookat.com/llms.txt first, then match the chat style to my site.

The agent finds your root template, adds the snippet and picks a style that fits your site. Connecting Slack or Discord and paying stay with you: a human approves both.

verify it in devtools

Don’t take a vendor’s word for any of this, ours included. Here is how to check your own page in Chrome. Firefox and Safari have the same panels under slightly different names.

the network tab, before the click

  1. Open your page in a private window, so no old storage or cache is involved.
  2. Open DevTools, go to Network, tick “Disable cache” and reload.
  3. Type spookat into the filter box.

You should see one request: the launcher from cdn.spookat.com, around 2 kb transferred. Nothing goes to api.spookat.com. If you see more than that, something else on the page loaded it (a second snippet in a tag manager, for example).

the application tab, before the click

Open Application, then Cookies and Local storage for your domain. Spookat writes nothing here on page load. It sets no cookies at all, ever. The one storage key it uses, spookat: followed by your site key, is written only after the visitor sends a first message: it keeps their chat on that device.

after the click

Clear the Network log and click the launcher. Now the panel loads from the CDN: its script (16.6 kb gzipped on 2026-09-27) and the stylesheet of your style (about 2 kb). A font comes too if you picked one. Then the panel opens a connection to our API, and the visitor can type.

That is the whole trick: the expensive part moves behind the click, and only the visitors who want to chat download it.

lighthouse

Run Lighthouse in mobile mode on the page without the snippet and with it, a few runs each, and compare the medians. Single runs vary by several points on the same page, so one run proves nothing either way. With a 2 kb launcher and no work before the click, the difference should sit inside that noise.

four ways to make a light widget heavy again

A small launcher only stays small if the page around it lets it. These are the mistakes we see most, and each one quietly undoes the work above.

Opening the chat by itself. A panel that pops open after ten seconds loads the whole chat for every visitor, including the ones who were about to buy. It also covers the page on a phone. If you want to start the conversation, write a greeting; it shows when they open the chat.

Preloading the panel “to make it faster”. A <link rel="preload"> or prefetch for the panel script moves its download back in front of the click, for everyone. After the click it is two short requests to a CDN near the visitor. Let them wait for the click.

Wrapping it in a tag manager. A tag manager is a script that loads other scripts. If it exists only to hold the chat snippet, it costs more than the chat does. Put the tag straight into your template.

Two snippets. A theme adds one, a plugin adds another, someone pastes a third into the footer. The launcher ignores its own duplicates, but other widgets often don’t, and you end up with two chats competing for the same corner. Search your templates for cdn.spookat.com (or your old vendor’s domain) and keep one.

what happens to the data

When a visitor sends a message, it is saved first, then posted to your Slack thread or Discord post. We never store an IP address. The visitor’s country is looked up from an offline database at the moment of the message and the address is not kept. Chat history is kept for 30 days on broke af, 90 on cool guy and 365 on vc money, then deleted. The details, including the subprocessors, are on the privacy page.

a checklist you can reuse

For any chat widget, not only ours:

  • The snippet loads with async or defer and does not block rendering.
  • Before a click: a few kilobytes, one request, no requests to the vendor’s API.
  • No cookies and no storage before the visitor starts a chat.
  • The launcher doesn’t cover your own buttons on a 375 px screen.
  • The panel and its fonts load only after the click.
  • Your team replies where it already works, without another tab to babysit.
  • Pricing doesn’t punish you for adding a teammate.
  • You measured it yourself, with the cache disabled, in a private window.

Try it on your own site: the trial is 14 days and needs no card.

liked it? get in before launch.

invites go out in small batches. then 14 days free, no card.