Analytics Script Size and Page Speed: What the Tag Costs You

Every analytics tag is a request, some bytes and some work on the main thread. Here are the real numbers for one cookieless tracker, the honest limits of the comparison, and a method to price any script on your own pages.

By Null Agency · Updated November 4, 2026 · Written for developers who care about Core Web Vitals and every kilobyte on the critical path

TL;DR — the tag is small, but measure yours

We measured the GhostMetrics tracker on November 4, 2026: gm.js is 8,420 bytes uncompressed, 2,459 bytes gzip and 2,485 bytes brotli as served from the edge, so about 2.5 KB on the wire. In our own earlier measurement, Google's gtag.js came to roughly 150 KB compressed. That is about sixty times the bytes.

Jump to the measurement how-to, or open the live demo and inspect the tracker yourself.

Why analytics weight is a Core Web Vitals question

An analytics tag is third-party-style code that runs on every page of your site. Whatever it costs, it costs on every visit. That is why script weight shows up in conversations about Core Web Vitals, the set of field metrics Google uses to describe loading speed, visual stability and responsiveness. Three of them are relevant here.

Largest Contentful Paint (LCP) measures when the main content of the page appears. A tag can delay it by competing for bandwidth early in the load, by blocking parsing if it is loaded synchronously, or by occupying the main thread when the browser wants to paint. Cumulative Layout Shift (CLS) measures unexpected movement. Analytics tags themselves rarely shift layout, but consent banners and widgets that load alongside them often do. Interaction to Next Paint (INP) measures how quickly the page responds to input, and long-running script work on the main thread is a classic cause of poor INP.

The effect of one small tag on any of these is usually modest. The effect of ten tags is not. Analytics, a tag manager, ad pixels, a chat widget, a heatmap tool and an A/B test snippet each look reasonable alone and add up together. Treating analytics as the cheapest tag to remove is wrong in the other direction too: a tracker that weighs a few kilobytes is not where a slow page comes from. The useful question is not "is analytics slow?" but "what does this tag cost, measured on my page?" For the field-measurement side, see Core Web Vitals and real-user monitoring.

The measured numbers for gm.js

These figures come from requesting the live tracker file on November 4, 2026 with curl, once per encoding. The first request asked for a gzip response, the second for brotli, and the third decoded the response to count the raw bytes.

Measuregm.js sizeHow we got it
Uncompressed8,420 bytesDecoded response body length
Gzip2,459 bytesRequest with Accept-Encoding: gzip
Brotli2,485 bytesRequest with Accept-Encoding: br

Two things in that table are worth a note. Brotli is usually smaller than gzip, but for a file this small the difference is within a few dozen bytes and can go either way, so we report both rather than pick the flattering one. And the number that reaches the browser depends on what the visitor's browser asks for, so "about 2.5 KB on the wire" is the honest summary. The script is served from Cloudflare's edge with a short browser cache, so repeat visits within the cache window do not download it again.

What does the tracker do with those bytes? It reads the privacy flags, builds a pageview payload, attaches a few listeners for scroll, visibility changes and clicks on elements with a data-gm-event attribute, observes paint, layout-shift and navigation timing entries, and sends small JSON payloads with navigator.sendBeacon, falling back to fetch with keepalive. Sending with a beacon matters for speed: the browser queues it without holding up navigation or the main thread waiting for a response.

It is fair to ask whether size is the right proxy. A small file can still do expensive work, and a large file that mostly sits idle can be cheap. We chose to report bytes because they are exact and reproducible; for execution cost, use the profiling method below on your own pages rather than relying on a number from us.

How that compares with other analytics tags

Gtag, the tag behind Google Analytics 4, is a general-purpose loader that also serves ads, conversion tracking and other Google products, and it can pull additional resources depending on what you configure. In our own measurement it came to roughly 150 KB compressed, which is why GA4 shows up so often in page-speed audits. That figure is a point-in-time measurement of a file Google updates, so re-measure it on your site with the method below rather than quoting ours.

For the other tools, we do not publish byte counts we have not measured. The table compares the dimensions that are well established and leaves the rest to your own test.

ToolScript sizeLoads fromWhat to confirm yourself
GhostMetrics8,420 bytes raw, about 2.5 KB compressed (measured)Cloudflare edge, one fileRequests after load (pageview, leave, vitals)
GA4 (gtag.js)Roughly 150 KB compressed in our measurementGoogle's tag domainExtra requests and cookies set after load
PlausibleCheck the current script sizePlausible or your own proxySize of the variant you enable
FathomCheck the current script sizeFathom or a custom domainSize on your plan's script
UmamiCheck the current script sizeYour server or Umami CloudSize of the tracker you configure
Cloudflare Web AnalyticsCheck the current beacon sizeCloudflareWhether it is injected or added by hand

Notice what the table does not claim: it does not say the smallest script wins. A larger tag can buy you things a small one cannot, such as ad attribution, audiences and ecommerce funnels, which are real strengths of GA4 that a cookieless tool does not try to match. If you need those, the weight is the price. If you mostly need traffic sources, top pages, events and vitals, you are paying for features you do not use. Our GA4 alternative guide walks through that decision, and cookieless analytics compared covers the field.

Beyond bytes: what else a tag costs

Four other costs hide behind a file size, and a fair comparison has to consider them.

Connections. A tag served from a domain the page has not already contacted forces the browser to do DNS, TCP and TLS work first. Hosting the script on the same origin as the page, or on a host you already use, can remove that cost. Most hosted analytics offer a custom-domain or proxy option; check each vendor's docs for the setup.

Execution. JavaScript costs parse and compile time as well as download time, and phones pay more than laptops. A modest script that runs for a few milliseconds is fine; a tag that runs long tasks during load competes with your own code. This is why the profiling step below matters more than the byte count.

Follow-up requests. The first request is not the last. A tag that fires a pageview on load, another on scroll and another on exit makes several requests per visit, each cheap but not free. The GhostMetrics tracker sends a pageview when the page loads, a leave request when the tab is hidden or the page unloads, a vitals report on the same trigger, and an event request for each click on a tagged element. Those go out as beacons and are not on the critical path.

Side effects. Cookies, local storage writes and consent banners all add work and sometimes layout shift. A cookieless tracker that adds no banner removes a source of CLS that has nothing to do with its own file size. See analytics without a consent banner for that angle.

How to measure any analytics script on your own page

This works for any tag, ours included. Use a desktop Chrome or Edge profile with extensions disabled, since extensions add their own requests and skew the result.

  1. Open a clean window. Use an incognito window so cached files and extensions do not change the result. Open DevTools and select the Network tab.
  2. Disable the cache and record. Tick "Disable cache" so the first-visit download is measured, then reload the page and let it finish.
  3. Find the script. Filter by the analytics host name. Read two columns: Size, which shows the transferred (compressed) bytes over the wire, and the resource size in the response details, which is the uncompressed length. Note both.
  4. Count the follow-ups. Leave the filter on and interact: scroll, click, switch tabs. Count the extra requests the tag makes and their sizes. Switch to the Performance panel, record a load and look for long tasks attributed to the script's URL.
  5. Run it with and without the tag. Remove or block the script, reload and compare. Use Lighthouse in DevTools or a lab tool on both runs, and read LCP and total blocking time. Repeat three times and take the median, because a single run is noise.
  6. Confirm with real users. Lab numbers describe your machine. Field data describes your visitors. Compare Core Web Vitals before and after on a period long enough to smooth out traffic changes. A real-user view such as the vitals panel in GhostMetrics shows FCP, LCP, CLS and TTFB per page.

A quick command-line check also works for the file itself: request the script with curl, ask for gzip with Accept-Encoding: gzip, and count bytes with wc -c. That is how the figures above were produced.

curl -s -H 'Accept-Encoding: gzip' https://ghostmetrics.nullagency.io/gm.js | wc -c
curl -s --compressed https://ghostmetrics.nullagency.io/gm.js | wc -c

The first command prints the compressed length and the second prints the uncompressed length. Swap in any script URL to price another tag the same way.

What GhostMetrics measures about your speed, and what it can't

A lightweight tag is only half of a speed story; the other half is seeing how real visitors experience your pages. GhostMetrics captures four field metrics from visitors' browsers using the standard performance APIs: First Contentful Paint, Largest Contentful Paint, Cumulative Layout Shift and Time to First Byte, shown per page in the dashboard's vitals table and per device in a Performance by Device view. TTFB follows Google's definition, measured from the start of navigation to the first byte of the response, so redirects, DNS, connection setup and server time are all inside it.

It does not capture Interaction to Next Paint. That is a real gap for this topic, because INP is the metric most likely to expose a heavy script. If you want INP, use a browser tool like Lighthouse in timespan mode or another field tool alongside it. We would rather say that here than let you infer coverage we do not have.

Another honest limit: visitors who send Global Privacy Control or Do Not Track are not measured at all, so vitals reflect the visitors who did not opt out. And because the tracker runs in the same page it measures, it observes entries like any other script; it cannot give you a "without analytics" baseline. For that you need the with-and-without comparison in the how-to above. Read the static site install guide if you want to see the one-tag setup with defer that this page assumes.

When should script size drive your decision? If you serve users on slow mobile networks, if your pages are mostly static and fast so a tag is a large share of the total, or if you are fighting for a Core Web Vitals pass on the margin, bytes matter. If your pages already ship megabytes of images and framework code, switching analytics tags will not be the lever that moves your scores. Measure first, then decide. Our guide to measuring website traffic covers what to look at once the tag is in place.

A 2.5 KB tag with real-user vitals built in

About 2.5 KB compresseddefer-friendly$0 forever1 site free$9.99/mo flat Pro

GhostMetrics is cookieless web analytics installed with one script tag, with FCP, LCP, CLS and TTFB captured from real visitors in the dashboard (not INP). The free plan is free forever: one website, unlimited pageviews, real-time dashboard, every dashboard view, full history. You can price the tag on your own pages with the method above.

Pro is $9.99/mo flat with unlimited pageviews, unlimited websites (fair-use ceiling of 250), a public shareable dashboard and a 30-day free trial (card required to start, nothing charged for 30 days, cancel anytime). Raw CSV or JSON export is on every plan, including free. Current details are on the pricing page.

Start free — no card See the live demo

FAQ

How big is the GhostMetrics tracking script?
We measured gm.js on November 4, 2026: 8,420 bytes uncompressed, 2,459 bytes gzip and 2,485 bytes brotli as served, so about 2.5 KB on the wire. Re-measure it with curl, since the file can change.
Does an analytics script hurt Core Web Vitals?
It can, depending on size, how it loads and how much work it does. A small deferred script usually has a modest effect, but the only reliable answer is to measure your page with and without the tag in Lighthouse and in field data.
Does GhostMetrics measure Interaction to Next Paint?
No. GhostMetrics captures First Contentful Paint, Largest Contentful Paint, Cumulative Layout Shift and Time to First Byte from real visitors. It does not capture INP, so use another tool for interaction latency.
How big is Google Analytics 4 compared with a cookieless tracker?
In our own measurement gtag.js came to roughly 150 KB compressed, compared with about 2.5 KB for gm.js. The gtag figure changes over time and depends on configuration, so measure it on your own site.
Should I load an analytics script with defer or async?
Both keep the download off the parsing path. GhostMetrics is installed with a defer attribute, which runs the script after the document is parsed. Whichever you choose, confirm in the Network tab that the page does not wait on it.

Keep reading

Core Web Vitals Monitoring

Measure LCP, CLS and TTFB from real visitors

Cookieless Analytics Compared

The full field, side by side

Add Analytics to a Static Site

One-tag install for common frameworks

GhostMetrics Live Demo

The real dashboard, live data

Disclosure: GhostMetrics is built by Null Agency and we use it on this site, so we are not a neutral party about our own product. The byte counts for gm.js were measured by us on the date given; the gtag figure is our own earlier measurement and other vendors' sizes are left for you to check. Script sizes change with releases, so measure before you decide.