Observability 2026-06-15

Measuring What Your Monitoring SDKs Cost Your Users

Every monitoring vendor describes their SDK as “lightweight.” Every single one. The word appears on the landing pages of tools whose script evaluation time differs by an order of magnitude. It is a marketing adjective, not a measurement, and the only browser SDK performance impact number that means anything is the one you collect from your own app, on your own users’ hardware.

The good news: getting that number is a two-week project, most of which is waiting for field data to accumulate. Here’s the method.

Step 1: inventory what you’re actually shipping

Before measuring anything, list every third-party script in your bundle and your tag manager. Error tracking, RUM, session replay, analytics, A/B testing, chat widget, consent manager. Most teams I’ve asked underestimate the count. The tag manager is where scripts go to be forgotten — somebody in marketing added a pixel in 2023 and it’s been evaluating on every page load since.

For each one, note how it loads: bundled with your app, async snippet, or injected by the tag manager. Bundled SDKs cost you at build time and you can measure them precisely. Injected ones are sneakier because their cost varies with network conditions and load order.

Step 2: lab numbers — script evaluation, not just transfer size

Open Chrome DevTools, Performance panel, 4x CPU throttling, and record a cold page load. Then look for each SDK in the bottom-up view, grouped by script URL.

Three numbers per SDK:

The bottom-up view groups by domain, which makes attribution mostly painless. The exception is SDKs that monkey-patch your code — their cost shows up inside your functions’ self-time. For those, diff two profiles, with and without the SDK, of the same scripted interaction.

Lab numbers tell you the mechanism. They don’t tell you whether users feel it. Hardware in the field is worse than your machine even with throttling, and real sessions hit code paths your script doesn’t.

Step 3: the A/B test that settles it

This is the part almost nobody does, and it’s the part that produces numbers you can defend in an argument.

Ship two cohorts. Cohort A gets your full bundle. Cohort B gets the bundle minus the SDK under test. Randomize per session, 50/50, using the same infrastructure you’d use for any feature flag. Collect Core Web Vitals from both cohorts with the web-vitals library — a few hundred bytes, and yes, I appreciate the irony of adding a script to measure the cost of your scripts. It’s the cheapest one you’ll ever ship.

Then wait. You need enough sessions for the INP distributions to stabilize — depending on traffic, days to a couple of weeks.

Compare percentiles, not means. An SDK that adds 5ms to the median INP is invisible. One that adds nothing to the median but fattens the p95 by 150ms is causing real jank for your slowest users — usually the interaction between the SDK’s periodic work (a flush, a snapshot) and an already-busy main thread. Means average that story away. Percentiles tell it.

Metrics worth comparing per cohort: LCP (did the extra script delay rendering?), INP at p75 and p95 (does steady-state work steal frame budget?), and total blocking time if you capture it. If the deltas are within noise after two weeks, congratulations: that SDK is free for your purposes. Write the number down and stop arguing about it.

Rotate through your SDKs one at a time. One flag, two weeks each. A quarter later you have a cost ledger for your whole third-party stack, built from your own users.

The compounding problem: five SDKs is not five times one SDK

Here’s the uncomfortable finding when teams run this exercise on the full stack instead of one SDK at a time: the total is often worse than the sum of the parts.

The reason is main-thread scheduling. Each SDK on its own does small work — a 3ms flush here, a 5ms batch there. Individually, each fits in idle time between frames. Stacked, they queue. Five SDKs that each wrap fetch means every network request passes through five layers of instrumentation. Three SDKs with their own periodic timers means more frequent wake-ups, fewer idle gaps, and long tasks assembled out of parts that were each individually “lightweight.”

So after testing SDKs individually, run one more cohort: everything versus nothing. The gap between “sum of individual costs” and “measured total cost” is your coordination tax. If it’s big, consolidation — one tool that does errors, replay, and tracing instead of three tools that each do one — buys you more than optimizing any single SDK. Session replay recorders deserve particular scrutiny in this exercise because their cost scales with DOM activity rather than sitting flat; I’ve written a separate breakdown of replay overhead specifically.

What to do with the numbers

Three outcomes, in rough order of frequency:

Most SDKs are genuinely fine. The field deltas are noise. Keep them, note the measurement date, re-test when you do a major version bump.

One SDK is the problem. Usually it’s the one with the eager synchronous init, or the tag-manager script nobody owns. Fix the load strategy first — async, deferred init, moved out of the critical path — before considering removal. Load strategy fixes recover most of the cost most of the time.

The pile is the problem. No single villain, but the everything-versus-nothing cohort shows a real INP regression. That’s a consolidation conversation, and now you have the data to have it like an engineering decision instead of a vendor-slide contest.

The meta-point: “lightweight” is a claim about their code on their demo page. Impact is a property of their code on your app, and it’s measurable with tools you already have. Two weeks of cohort data beats any benchmark a vendor will ever show you.

See the bug the way your user did

LogReplay captures session replays, console output, network requests, and errors in one timeline — so you stop guessing what happened before the ticket arrived.

Try LogReplay free