what a chat widget does to your lighthouse score

We ran Lighthouse on a plain test page with each of seven chat widgets, 7 times each, with Lighthouse’s default mobile settings. Six scored 100 and one scored 99. That sounds like good news for everyone, and it mostly says how Lighthouse measures. On the vendors’ own sites, where the widget shares the page with real content, the same widgets cost 4 to 14 points. This post has both sets of numbers and what’s behind them.
the setup, briefly
Lighthouse 13.5 as a Node module, driving Google Chrome 153 with a fresh profile per run. Default mobile settings: a Moto G Power screen, simulated slow 4G (150 ms round trip, 1.6 Mbps down) and a 4x CPU slowdown. Performance category only. Every number is the median of 7 runs, measured on 2026-09-27 (Spookat’s row again later that morning, after changes to its launcher). The machine’s Lighthouse CPU benchmark index was about 4,050 in every run.
The test page is a plain page for a made-up shop: text, a price grid, a footer, system fonts, no images, no scripts of its own. It’s the same page as in the weigh-in. How we test covers the rest.
what goes into the score
Lighthouse 13 scores performance from five timings, each turned into a 0–100 value against real-world data and then weighted:
| metric | weight | what it measures |
|---|---|---|
| Total Blocking Time | 30% | how long the main thread was blocked by tasks over 50 ms, between first paint and interactive |
| Largest Contentful Paint | 25% | when the biggest element on screen appeared |
| Cumulative Layout Shift | 25% | how much the page jumped around |
| First Contentful Paint | 10% | when anything first appeared |
| Speed Index | 10% | how quickly the screen filled in |
A chat widget can touch all five, but it usually touches two. Its scripts compete with the page’s own for the main thread, which is TBT. Its requests compete with the page’s images and fonts for a slow connection, which can push LCP later. A launcher that pops in and pushes content aside would hit CLS; none of the seven did, on any page.
on the test page: almost all 100
| widget | score | TBT | LCP | main-thread work | bytes Lighthouse saw |
|---|---|---|---|---|---|
| page alone | 100 | 0 ms | 750 ms | 117 ms | 3 kb |
| Spookat | 100 | 0 ms | 606 ms | 118 ms | 5 kb |
| Tawk.to | 100 | 0 ms | 606 ms | 318 ms | 223 kb |
| Tidio | 100 | 0 ms | 608 ms | 489 ms | 514 kb |
| Intercom | 99 | 106 ms | 750 ms | 399 ms | 290 kb |
| Crisp | 100 | 0 ms | 606 ms | 115 ms | 6 kb |
| LiveChat | 100 | 0 ms | 606 ms | 110 ms | 42 kb |
| Chatwoot | 100 | 0 ms | 606 ms | 102 ms | 11 kb |
TBT is Total Blocking Time, the part of the score that measures how long the main thread was too busy to respond. LCP is Largest Contentful Paint, when the biggest thing on screen appeared. Main-thread work is everything the browser’s main thread did during the run: parsing HTML, running scripts, styling, layout. LCP moved between 606 and 750 ms without a pattern we could tie to any widget, so we don’t read anything into it.
Two things stand out.
The score hides real work. Tidio added about 370 ms of main-thread work to the page, Intercom about 280 ms, Tawk.to about 200 ms. All three still scored 99 or 100. Lighthouse only counts the parts of a task that go over 50 ms and only up to the moment it considers the page interactive. A widget that loads after that, or splits its work into small pieces, adds work your visitor’s phone does without moving the score. Spookat’s launcher added 4 ms, which is inside the run-to-run noise of the page alone (78 to 131 ms).
Lighthouse stops watching. Lighthouse ends a run once the network and the CPU have been quiet for a moment. Anything a widget loads later is not in the report. In the weigh-in, with a 25-second window, Tawk.to transferred 256 kb; Lighthouse saw 223 kb of it.
When a widget starts matters. The snippets start their widgets at different moments. Intercom’s official snippet waits for the page’s load event before it even requests its loader. Tawk.to, Crisp, Tidio, LiveChat and Spookat insert an async script as soon as the snippet runs, and Chatwoot’s is async and defer. None of them block the first paint, which is why FCP is identical in every row. What differs is how much work lands in the seconds right after it, which is when Lighthouse is still measuring TBT.
JavaScript execution tells the same story as main-thread work. Lighthouse also reports how long the page spent running scripts. The page alone: 3 ms. Spookat: 3 ms. Tawk.to: 136 ms. Tidio: 197 ms. Intercom: 229 ms, even though it was refused and only got as far as its two base bundles. On a 4x slowed CPU that’s what a mid-range phone spends, per page view, before a visitor has decided anything.
Three rows are low for other reasons. LiveChat and Chatwoot refuse to run on a domain their owner didn’t allow, so they stopped early here too. Crisp also refuses our domain, but under Lighthouse it loaded even less than in the weigh-in: its 3 kb loader and nothing else. Its loader carries a list of user agents it won’t start for, and “Lighthouse” and “GTmetrix” are on that list. The user agent in our runs contained neither word, so that list doesn’t explain it on its own. We’re reporting what happened, not guessing why.
on the vendors’ own sites: 4 to 14 points
A test page is the best case for a widget: nothing else competes for the network or the main thread. Real pages have hero images, fonts, analytics and their own scripts, and that’s where a widget’s cost shows up in the score.
For the four widgets that won’t run on our domain we ran Lighthouse on the vendor’s own page twice: as it is, and with the widget’s loader script blocked (Lighthouse’s blockedUrlPatterns). Same page, same run settings, 7 runs each. The difference is what the widget costs there.
| page | score without widget | score with widget | TBT without → with | LCP without → with | main thread without → with |
|---|---|---|---|---|---|
| crisp.chat | 78 | 64 | 220 → 222 ms | 4.3 → 6.8 s | 1.35 → 1.32 s |
| intercom.com | 87 | 80 | 199 → 366 ms | 2.2 → 2.2 s | 2.48 → 3.34 s |
| livechat.com | 90 | 86 | 262 → 260 ms | 2.7 → 3.2 s | 1.87 → 2.06 s |
| chatwoot.com (help center) | 63 | 63 | 0 → 0 ms | 6.1 → 6.3 s | 0.71 → 0.90 s |
Each widget hurts in its own way:
- Intercom is the clearest case: 860 ms more main-thread work and 167 ms more blocking time, which is 7 points.
- Crisp barely changed the main thread, but the largest paint moved from 4.3 to 6.8 seconds, which cost 14 points. Our runs don’t show which element became the largest paint, only that it came later with the widget on the page.
- LiveChat cost 4 points, mostly through a later largest paint and 190 ms more main-thread work.
- Chatwoot added 194 ms of main-thread work and 865 kb of bytes on its help center page, but the score didn’t move: that page was already at 63 for its own reasons.
These pages are noisy. crisp.chat without the widget scored anywhere from 64 to 84 across 7 runs, and livechat.com with the widget from 67 to 92. That’s why we run 7 times and report medians, and why a single Lighthouse run of your own site tells you very little. All 7 runs of every page are in the raw data.
The comparison has one limit you should know about: each vendor’s page runs the widget with the vendor’s own settings. Intercom’s site pushes a message to new visitors, which loads more code than a quiet install would. Your site with the same widget will land somewhere else. What won’t change is the direction.
what we can’t show you yet
We couldn’t put Spookat on a vendor’s page, and we didn’t want to invent a heavy page just to make ourselves look good. Spookat’s own site scores 100 in Lighthouse, and we’ll write up how it got there in a later post. What the test page does show: Spookat’s launcher moved no Lighthouse number outside the noise, and it transferred 2.0 kb, the least of any widget here.
why the score can be 100 and the page still slower
A Lighthouse score is a weighted mix of five timings, measured on a simulated phone, over the first seconds of a page load. It’s a good proxy for “does this page show up fast”, and it’s what Google’s tools report. It isn’t a full account of what a page costs.
A chat widget mostly does its work after the page has shown up. Lighthouse scores that part lightly or not at all. Your visitor’s phone still does it: the parsing, the compiling, the websocket, the timers, the CPU and battery it costs, on every page view, whether anyone chats or not. That’s why we measure bytes and main-thread work next to the score, and why the weigh-in matters as much as this post.
If your page is light, most widgets won’t cost you your 100. If your page is already busy, which most real pages are, a widget can take 4 to 14 points, as the vendors’ own sites show.
lab score vs what Google sees from real visitors
Lighthouse is a lab test: one simulated phone, one load, no one touching anything. Google’s search ranking uses field data instead, the Core Web Vitals collected from real Chrome users: LCP, CLS and Interaction to Next Paint (INP), which replaced First Input Delay in March 2024.
INP is the one to think about with chat widgets. It measures how long the page takes to respond when someone taps or types, and a lab run with no interactions can’t measure it at all. It gets worse when the main thread is busy at the moment of the tap. The main-thread work in the first table, the 200 to 370 ms that the score ignored, is exactly the kind of work that can sit in front of a visitor’s first tap on a slow phone.
So a widget can leave your Lighthouse score alone and still show up in your field data. The only way to know for your site is to look at your own Core Web Vitals report, before and after.
what we’d check before picking a widget
- What loads before the click, in bytes and requests (the weigh-in).
- Main-thread work with and without it, not just the score.
- A before/after Lighthouse on your real page, the busiest one you have, median of at least three runs.
- Your field INP a couple of weeks after installing it.
- Whether the widget can wait for a click at all, or insists on booting with the page.
run it on your own site
Our whole run is one command in the widget lab (bun run lighthouse). You don’t need it to measure your own widget. In Chrome:
- Open your page, open DevTools, go to the Lighthouse tab, pick Mobile and Performance, and run it three times. Note the median score, TBT and LCP.
- Open the Network tab, right-click the widget’s loader script and pick “Block request URL”.
- Run Lighthouse three times again. The difference is your widget.
Look at “Reduce JavaScript execution time” and “Minimize main-thread work” in both reports too: that’s where a widget shows up even when the score doesn’t move.
Our raw data is at /research/lighthouse-2026-09.json: every run with its score, FCP, LCP, TBT, CLS, Speed Index, main-thread time, JavaScript execution time, total bytes and request count, the CPU benchmark index, the Lighthouse and Chrome versions, and the exact snippets.
the takeaway
A 100 on a test page is easy for everyone. It only takes a page with nothing else on it. The moment a widget shares a real page with real images and real scripts, whatever it does in the first seconds competes with everything else, and the vendors’ own sites show what that costs: 4, 7 and 14 points, and close to a second of extra main-thread work in Intercom’s case. Keeping a 100 on a real page means the widget has to do almost nothing until someone asks it to. That’s how we built Spookat: a 2 kb launcher, 0 requests to our API before a click, and everything else loaded when a visitor actually wants to talk.
Try it on your own page and run Lighthouse before and after. 14 days, no card.