Skip to content
XICBOT

Settings

Deutsch
Technology, projects & quality

Chat Widget and Load Time: What It Costs a Page

What a chat widget costs in load time: one loader, a chat window after the page has loaded, measured with the compression the web server actually sends.

In plain language

Your page runs only one file for the chat. What counts is how much of it is actually sent, not its size before packing. The chat window is built in its own frame after the page has loaded. With a consent check, it loads only after a yes or a click. The button that opens it has a fixed place from the start. So the window has no reason to shift the page. Your design and the window do not get in each other's way. Measure the same page several times with and without the chat and compare the middle values.

13 min read By XICBOT

More on integration

An AI chat assistant is code that runs in your visitors' browsers, and every line of it shares the load time with your content. Asking what the widget costs is therefore fair. The honest answer consists of two figures and one order of events. The first figure is the size of the file that is actually transferred while the page builds, not its size in the source code. The second is the number of requests the widget adds to the page. The order of events decides a great deal: what loads only after the visible content cannot delay it, but it is still transferred. This article describes how a widget is built that keeps to that order: a loader that does not hold up the page build, a chat window in its own frame that is only created once the page has loaded, styles encapsulated via the Shadow DOM. And it describes how to measure the difference yourself, with and without the widget. The figures come from our own measurement of the delivered files, documented under measurement series.

What a chat widget costs in load time
What a chat widget costs in load timeOne file while the page builds, the chat window after the page has loadedOrder in which the page buildsLCP is inpage fully loadedHTML and CSSimages and visible textrest of the pageloaderchat window in its own frameWhile the page builds1 file on the host page: the loader24.1 KB transferred, compressed (Brotli)76,439 bytes raw, unpacked without BrotliWhat counts is what arrives, not what the source says.After the page has loadedchat window loads inside its own framestyles encapsulated, no reach into page CSSoutside the critical path, no click neededWith a consent gate only after agreement.Own measurement: 1 file, 24.1 KB compressed on the host pageMeasured on the delivered file, not on the source code
One file while the page builds, the chat window after the page has loaded
Labels in the illustration
  • Order in which the page builds
  • LCP is in
  • page fully loaded
  • HTML and CSS
  • images and visible text
  • rest of the page
  • loader
  • chat window in its own frame
  • While the page builds
  • 1 file on the host page: the loader
  • 24.1 KB transferred, compressed (Brotli)
  • 76,439 bytes raw, unpacked without Brotli
  • What counts is what arrives, not what the source says.
  • After the page has loaded
  • chat window loads inside its own frame
  • styles encapsulated, no reach into page CSS
  • outside the critical path, no click needed
  • With a consent gate only after agreement.
  • Own measurement: 1 file, 24.1 KB compressed on the host page
  • Measured on the delivered file, not on the source code

What a chat widget costs in load time

What actually loads while the page builds

When people talk about a chat widget, they usually mean two different things under one word. The first is the loader: the file your page embeds, which draws the launcher and then inserts the frame for the chat window. The second is the chat window with conversation history, input field, formatting and the connection to the assistant, in its own frame with its own files. What matters is therefore not only how much code an AI chat assistant brings along in total, but when each part loads: while your page builds, after the page has loaded, or only when a visitor opens the chat. Each of these three stages costs something different.

That makes the question quantifiable. In our own measurement the loader on your page, compressed came to 24.1 KB. The scope of that figure belongs with it: only the file that runs on the host page was measured, with the compression the web server actually sends; the chat window lives in its own frame and loads once your page has finished loading. The value describes our own state of the delivered files and is not a promise for another project. How the series is produced and what it does not cover is described under measurement series.

Compressed, not raw: which figure counts

Size claims about widgets are often useless because they describe the wrong file. A web server delivers text files packed, usually with gzip or brotli, and the browser unpacks them on arrival. What is transferred is the packed version, and only that consumes bandwidth and time. Weighing the file in the build directory measures a size that never travels the network. The figure drifts even further when someone quotes the unpacked size in memory, or the entire source directory. Only one statement is meaningful: what arrives at the browser, with the compression the web server actually sends.

FigureWhat it describesIn our own measurement
Raw in the build directoryThe file before the web server packs it76,439 bytes
Transferred with BrotliWhat arrives at a browser using Brotli24,641 bytes
Only gzip offeredWhat a browser gets that does not offer Brotli76,439 bytes, unpacked
Files on the host pageAdditional requests while the page builds1
"wirtsseite": { "dateien": 1, "byte_roh": 76439, "byte_uebertragen": 24641, "kodierung": "br" }
XICBOT, own measurement of the delivered files

Three figures for one file, and all three are correct. They simply answer different questions. The raw value says something about the amount of code, the packed value something about the transfer. Which version a visitor's browser actually pulls is decided by the web server, based on the compression the browser offers: with us, a browser offering Brotli receives the packed version, one that offers only gzip currently the unpacked one. That is why every weight claim needs a note on how it was measured. Without it, the same file can be presented very differently depending on interest, without anyone having to lie.

One request on the host page

Bytes are only half the calculation. The other half is the number of requests, because every additional request costs time regardless of its size: name resolution, connection setup, and for a foreign target an extra handshake for encryption. On a slow mobile network this overhead often weighs more than the transferred bytes themselves. In our measurement the host page carries exactly one file. By default it comes from the widget domain, and the browser opens a connection of its own for it. If delivery runs over a path on your own domain, the browser reuses the connection that is already open for the page's HTML.

  • One file instead of a bundle

    The loader is a single file with no chain of follow-up requests. While the page builds it pulls no stylesheet, no web font and no second script file.

  • One connection target instead of several

    By default the file comes from the widget domain, one additional target with its own overhead. Over a path on your own domain even that disappears: no second name resolution, no additional handshake.

  • The rest comes after loading

    All further requests belong to the chat window. They occur once your page has finished loading, without a click and on every page view; with a consent gate only after agreement. They fall outside the measurement of the page build, but not outside the transferred bytes.

Deferred loading: after the page has loaded

The biggest lever is not compression but timing. A widget that attaches itself to the page build competes with the content for the same connection and the same main thread in the browser. A widget that waits does not compete with the build. That is why the loading chain is staged: the script is embedded deferred and only runs once the document is in place. It draws the launcher and inserts the frame with the chat window only once the page has finished loading. That saves visitors the wait when they open it, but it costs transfer even for visitors who do not chat at all. Anyone who weighs this differently uses the setting for the consent gate; the frame then waits for agreement or a click on the launcher. How the launcher is placed and when a proactive greeting makes sense is covered in the article on placing the chat widget.

  • Document first: the script is embedded deferred and does not hold up the page build.
  • Draw the launcher: the button gets its fixed place before anything loads, so nothing jumps.
  • Wait for the load: only once the page has finished loading does the script insert the frame for the chat window.
  • Respect consent: if the consent gate is switched on, the frame waits for agreement or a click on the launcher.
  • Open the conversation: the connection to the assistant is made inside the frame, not on the host page.
  • Keep it separate: the window's styles and scripts stay inside its frame and do not reach into your page's document.

What loads later does not hold up the build

The most effective optimisation on a chat widget is not a smaller bundle but a later load. What only comes after the page has loaded does not delay the visible content. It is still not free: it is transferred on every page view, and that belongs in any honest weight claim.

Why the widget does not move the LCP

Largest Contentful Paint, LCP for short, is the moment when the largest image or text block in the viewport has finished painting. Two things can push that moment back: a resource that competes with the largest element for bandwidth, and main-thread work that holds up painting. A deferred script usually does neither, because it starts after the document is in place and only pulls in the frame once the page has loaded. And the launcher itself does not become the measured element as long as it stays smaller than the largest visible image or text block, which is the usual case for a button in a corner. It is therefore not a candidate for the LCP, only a small element beside it.

The same logic applies to the two other metrics. A layout shift occurs when an element takes up space afterwards that something else had before. That is why the launcher is assigned its place before anything loads, and it sits above the content rather than inside it, so it displaces nothing. Responsiveness to input suffers when the main thread is occupied in one long block. A script that draws a button and inserts a frame after loading occupies it briefly and releases it again. Whatever happens afterwards in the chat window runs in its own frame, not in your page's document. How long the assistant then takes to answer is an entirely different measurement, described in the article on response time.

Your own origin instead of a foreign server

Where the file comes from decides both speed and data flow at once. If the loader comes from your own address, the browser uses the connection that is already open for the page. If it comes from a foreign server, the chain starts over: name resolution, connection setup, encryption handshake, and only then the actual bytes. On top of that, a request to a foreign server shows that server's operator the visitor's address, often before any consent exists. With XICBOT the loader comes from the widget domain by default; on request, delivery runs entirely over a path on your own domain, and then only your address is involved for the visitor. Hosting is in Germany, and the answers are generated by a specialised model provider, also outside the EU on the basis of standard contractual clauses; details are on the page about data protection and hosting, and the technical path of embedding on the page about integration.

Step while loadingFrom a foreign serverFrom your own origin
Name resolutionAn additional lookup at the name serviceNot needed, the name is already resolved
Connection and handshakeA new connection including encryptionThe existing connection is reused
Visibility of the visitor addressThe foreign operator sees it on requestIt stays on your side
Consent layerOften loadable only after agreementEmbedding follows your own concept

The difference is barely noticeable on a fast connection and clearly noticeable on a weak mobile network. Yet that is exactly where it is decided whether a page feels sluggish. So when you check your values, do not measure only under the best conditions. A throttled measurement on a mid-range device shows the overhead an additional connection costs, while a measurement on a fast machine lets it disappear into the noise.

Shadow DOM against style collisions

A widget that pours its own styles into the page is not a load-time problem but a maintenance problem, and it often surfaces only weeks later. Classically this happens through broad rules that hit every element of a kind, or through a bundled stylesheet that happens to use the same names as your theme. The result is displaced buttons somewhere nobody suspects a widget. The Shadow DOM solves this at the root: the launcher hangs on an element of its own, beneath which a separate tree sits. Rules from the outside do not reach in, and rules from the inside do not reach out.

  • Protected inwards

    A broad rule in your theme, say for buttons or input fields, does not reach the widget's separate tree and cannot distort it.

  • Sealed outwards

    The widget's styling stays inside. Your headings, spacing and colours stay exactly as your theme defines them.

  • Adjustable on purpose

    Adjustments to colour, corner radius and position run through a few deliberately exposed settings instead of overriding foreign rules.

Encapsulation has a limit worth knowing: it separates styling, not responsibility. The launcher is part of your page, it must be reachable by keyboard, carry a visible focus marker and have a meaningful name. The contrasts inside the window need checking too, because a screen reader reads the separate tree like any other content. What to check is on the page about accessibility and in the article on the accessible AI assistant.

Measuring with and without the widget

Every figure in this article, including ours, is only a point of reference for your page. The question becomes solid only through a comparison on your own setup: the same address, once without and once with the widget embedded, under identical conditions. What counts is not the best value of a single run but the middle of several runs. A single measurement varies with the network, with the cache and with whatever else the machine happens to be doing; deriving a statement from it means reading noise.

  • The same page twice: one version without the widget, one with; nothing else changes, not a word and not an image.
  • Identical conditions: same device profile, same throttling, empty cache, no browser extensions.
  • Several runs: five or more per version, and compare the middle run, not the fastest one.
  • Record four quantities: transferred bytes, number of requests, LCP and layout shift, for each version.
  • Separate from the chat window: report the page build up to the load event separately from what the frame pulls in afterwards, and measure a second pass with the chat open.
  • Look at the field too: lab values show the direction, real page views show what your visitors experience on their devices.
MetricWhat it shows hereWhat to watch out for
Transferred bytesThe additional weight while the page buildsRead it compressed, do not weigh the raw file
Number of requestsHow many extra targets are contactedCount foreign origins separately, they cost overhead
LCPWhether the largest visible content finishes laterMeasure throttled, otherwise the effect disappears
Layout shiftWhether the launcher displaces anything on appearingCheck narrow screens first

What our own figure says and what it does not

The 24.1 KB from our measurement describe one file at one point in time, measured on delivery; they do not include the frame with the chat window, which fetches its own files after the page has loaded. They say nothing about how fast your page is overall, because your images, your fonts and your remaining scripts weigh far more in that. They say nothing about tomorrow either: if the launcher gains functionality, the file grows, and the old figure no longer holds. And they say nothing about the quality of the answers that then appear in the window; that depends on the knowledge base and not on the weight of the script. Under Section 5 subsection 1 of the German Act Against Unfair Competition, anyone who engages in a misleading commercial practice capable of causing a market participant to take a transactional decision they would not otherwise have taken is acting unfairly. A weight claim without a statement of how it was measured falls squarely into that field, which is why the scope stands next to every figure we publish. What the widget does for your visitors once it is opened is shown on the page for the website assistant.

  • Ask for the transferred, compressed size, not the size in the build directory
  • Ask how many files and how many foreign origins appear on the host page
  • Check when the chat window loads: during the page build, after the page has loaded, or only on opening
  • Check the launcher for a fixed place, keyboard operation and a visible focus marker
  • Measure the same page without and with the widget, throttled and as the median of several runs
  • Record the scope alongside every figure you adopt, otherwise it cannot be verified later

Frequent questions

Does a chat widget slow down my website?

That is decided by how it is built, not by what it does. A widget that brings an entire chat window and framework along while the page builds competes with your content for bandwidth and the main thread. A widget that adds only a deferred loader during the build and pulls in the window after the page has loaded usually does not delay the visible content, but it is still transferred. In our own measurement that loader came to 24.1 KB in one file, compressed. Whether it shows up on your site is answered only by comparing the same page without and with the widget.

How many kilobytes does the loader add?

There is no universal figure, because every widget is built differently. What can be stated is our own measurement: the loader on your page, compressed, came to 24.1 KB. Its scope: only the file that runs on the host page, with the compression the web server actually sends; the chat window lives in its own frame and loads once your page has finished loading. The raw values are 76,439 bytes raw and 24,641 bytes transferred with Brotli, for one file on the host page. These figures describe our state, not that of another widget.

Why is the compressed size the right figure?

Because only that travels the network. A web server delivers text files packed when the browser offers a suitable compression, and transfer time depends on the packed size. For our file the two figures are 76,439 bytes raw and 24,641 bytes with Brotli; a browser that offers only gzip currently receives it unpacked. Quoting the first describes the amount of code; anyone talking about load time has to quote the transferred one and say which compression was measured.

How do I measure the difference with and without the widget?

Take the same address in two versions, one without and one with the widget embedded, and change nothing else. Measure with the same device profile, the same throttling and an empty cache, five or more runs per version, and compare the middle run. Record four quantities: transferred bytes, number of requests, LCP and layout shift. Report the page build up to the load event separately from what the frame pulls in afterwards, and measure a second pass with the window open, otherwise you mix page build, frame and conversation.

Can the widget interfere with my CSS or my layout?

That is what the Shadow DOM is for. The launcher hangs on an element of its own with a separate tree beneath it; your theme's style rules do not reach in, and the widget's rules do not act outwards. The chat window additionally sits in its own frame and therefore in its own document. What remains is position: the launcher needs a fixed place from the start and enough distance from other floating elements so that nothing jumps when it appears. Check that on narrow screens first.

Does the widget affect LCP or layout shift?

LCP measures when the largest image or text block in the viewport has finished painting. A launcher in a corner is smaller than that element and is therefore not the one measured; and a deferred script only starts once the document is in place and pulls in the frame only after the page has loaded, so it usually does not compete with the visible content for bandwidth or the main thread. For layout shift it depends on the implementation: if the launcher gets its place before anything loads and sits above the content rather than inside it, it displaces nothing. You should still measure it.

How does the assistant get onto your website?

The integration page shows how the widget goes into a website, CMS or shop with a short snippet and appears in the design of your site.

Enquiry in three steps

  1. 1. Topic
  2. 2. Your case
  3. 3. Contact

What is this about?

One click is enough, everything else is optional.

Tell us briefly about your case

Everything in this step is optional. It helps us reply with something concrete straight away instead of asking back.

Enquiries per month, roughly (optional)
When should it start? (optional)
How can we reach you?

Name and email address are enough. We reply personally.

We use your details to handle your enquiry. More on this in the privacy policy.