Site Speed & Core Web Vitals
This page is written for an IT or security lead evaluating whether the AXO tag will slow a site down. It covers exactly how the tag loads, its measured effect on Google's Core Web Vitals, how to verify that on your own pages, and the guardrails that keep it fast on every release. It is intended to be linked directly from an RFP response or vendor-review questionnaire.
The short answer
- One
<script defer>tag. It is never render-blocking and runs after your content has painted. - The core is ~27 KB Brotli over the wire (~31 KB gzip) — optional features load as separate small modules only where used — and its total main-thread CPU on load is around 32 ms.
- Its contribution to layout shift (CLS) is 0.00 — personalization is rendered flicker-safe, not by shoving content around after paint.
- On a first-time visitor the tag does nothing visible before paint at all — the anti-flicker step is skipped until someone is a returning, recognized visitor.
- You can confirm all of this yourself in minutes with Lighthouse — no site traffic required (see “Verify it on your own site” below).
How the tag loads
Installation is a single line placed before </head>:
<script src="https://axoapp.ai/tag.js?site=YOUR_SITE_ID" defer></script>
- Deferred, not blocking. The
deferattribute means the browser keeps parsing and painting your HTML and downloads the tag in parallel, executing it only after the document is ready. It cannot delay First Contentful Paint or block your own scripts. - Small and compressed. The core tag — the part every page loads — is ~27 KB over the wire (Brotli; ~31 KB gzip). For comparison that is smaller than a single typical hero image, and it is cached after first load.
- Optional features load on demand. Behavioral scoring, the personalization decision, and rendering all live in that core. Capabilities only some sites or pages use — the HIPAA-safe privacy proxy, third-party enrichment, and the dashboard’s authoring preview — are split into separate small modules the core fetches at runtime, from the same first-party origin, only when they are actually needed. So a page never downloads code for a feature it doesn’t run, and the core stays lean as the platform grows.
- First-party origin. It loads from one origin (
axoapp.ai) over HTTP/2+. There is no chain of third-party redirects on the critical path. - No work before your content. Behavioral scoring and the personalization decision run client-side after paint (sub-200 ms), so they never sit in front of your Largest Contentful Paint.
Measured Core Web Vitals impact
Below is a lab (synthetic) trace of a live site running the tag, captured in Chrome. We show two cases because the tag behaves differently for a brand-new visitor versus a returning one (see the anti-flicker section). Absolute load times depend on the host page and the test device/network — the figures to focus on are the tag's own additions: its CPU time and its layout-shift contribution.
| Scenario | LCP | CLS | Tag main-thread CPU |
|---|---|---|---|
| First-time visitor (anti-flicker dormant) | 0.48 s | 0.00 | ~32 ms |
| Returning visitor (personalization + anti-flicker active) | 0.83 s | 0.00 | ~32 ms |
Both LCP figures sit well inside Google's “good” threshold (< 2.5 s), and the tag adds zero cumulative layout shift in both cases. For a returning visitor the tag briefly holds the specific personalized region (only that region) until the decision resolves, which adds a small amount of render time to that one element — never to the rest of the page, and always capped by a safety timeout (below). The numbers above are from one representative site in an unthrottled lab run; your own results will reflect your page, which is exactly why we recommend you measure it yourself.
Why it doesn't shift your layout (anti-flicker by design)
“Flicker” — the original content flashing before a personalized version replaces it — is the classic way personalization tools hurt CLS and LCP. AXO avoids it structurally:
- Per-zone, not whole-page. Only the specific elements that will be personalized are briefly held; the rest of the page paints immediately. We never blank the
<body>. - Skipped for first-time visitors. The pre-hide only engages once a visitor is recognized (a returning, cohorted visitor). A cold first visit — which is what a fresh Lighthouse run simulates — incurs none of it.
- Hard safety timeout. If a decision is ever slow, the held region reveals itself automatically within a few seconds no matter what, so a stalled request can never leave content hidden.
- Swap-in-place. Personalized content occupies the same layout box as the original, so there is no reflow when it appears — hence the 0.00 CLS.
Reading PageSpeed Insights correctly: field vs lab data
A common point of confusion: pagespeed.web.dev shows two different things, and one of them will look empty on a low-traffic site.
- Field Data (CrUX) is measured from real Chrome users and requires your site to have enough traffic to be included in Google's public dataset. A new or low-volume site shows “no data” here — that is expected and is not a problem with the tag.
- Lab Data (Lighthouse) is a fresh synthetic audit Google runs on demand, in a controlled browser, every time you click Analyze. It needs zero traffic and is the authoritative way to judge whether a script slows the page.
So you do not need to wait for traffic to be confident — the lab run gives you the answer immediately.
Verify it on your own site
- Open pagespeed.web.dev (or Chrome DevTools → Lighthouse, or the
lighthouseCLI) and run a report on a page that has the tag installed. Read the Lab/Lighthouse section; ignore that Field Data may be empty. - For the strictest comparison, run it twice — once as a first-time visitor (incognito), and once as a returning visitor (reload after the tag has set its cohort cookie). The second run exercises the personalization + anti-flicker path.
- To isolate the tag's exact cost, run Lighthouse with and without the tag line and compare. The difference is AXO's contribution.
- What “good” looks like: CLS < 0.1 (the tag should add ~0), LCP < 2.5 s, and a small Total Blocking Time contribution from the tag.
How we keep it fast on every release
Performance is enforced in our build pipeline, not just measured once:
- Bundle-size budget. Every change runs an automated check that fails the build if the compressed size of the core — or any on-demand module — exceeds its budget (the core is currently ~31 KB gzip / ~27 KB Brotli). Neither the core nor any feature module can silently get heavier.
- Lighthouse budgets. A synthetic Lighthouse audit with Core Web Vitals budgets can be run against any deployed page on demand; cumulative layout shift is a hard gate.
- Caching. The tag is served with long-lived caching and a content-hashed URL, so repeat visits pay no download cost and a new release busts the cache cleanly.
For reviewers: the tag is a single deferred, first-party core script of ~27 KB (plus small feature modules it loads on demand, only where used) that adds ~32 ms of main-thread work and 0.00 layout shift, runs its logic after your content paints, and is held to a size budget on every release. It is designed to be invisible to your Core Web Vitals, and that is verifiable synthetically without any traffic.