Google warns that your site is slow and suspicion falls on the advertising. Sometimes rightly, sometimes not. Here is what each metric measures, which part of the problem really belongs to the ads, and what can be fixed without giving up revenue.
What Google measures when it says your site is slow
Core Web Vitals is the set of metrics Google uses to summarise the real experience of your readers. They are not a lab score: they are calculated from the browsing data of people who have opened your pages, and the value published is the 75th percentile, the value below which three out of four visits fall.
There are three. LCP (Largest Contentful Paint) measures how long the main content takes to appear. CLS (Cumulative Layout Shift) measures how much the page moves on its own while it loads. INP (Interaction to Next Paint) measures how long it takes to respond when someone taps something. All three have a public Google threshold for being considered good.
LCP: how long the reader waits for what they came for
LCP marks the moment the largest visible element of the first screen finishes painting: usually the header image or the headline. Google considers an LCP of 2.5 seconds or less to be good, up to 4 to need improvement, and anything above that to be poor. It is measured from the moment the user requests the page, not from the moment your server replies.
Advertising is rarely the direct culprit behind a bad LCP: the creative is almost never the largest element on the first screen. It is an indirect one. If the browser is busy downloading and running ad libraries, it takes longer to reach your main image. Nothing in the ad stack should compete for bandwidth with the resource that defines your LCP.
CLS: the jump that makes the click miss
CLS is not measured in seconds but as a unitless score that combines how much of the screen moves and how far it travels. Google considers a CLS of 0.1 or less to be good, up to 0.25 to need improvement, and anything above that to be poor. Zero is achievable, and it is the reasonable target for a content page.
It is the easiest metric to understand because everyone has suffered it: you are reading, something loads above, the text drops and you lose your line. Or worse: you go to tap a link and at that instant a block appears and pushes it down, so you tap something else. A shift right after a user interaction does not count; one that happens on its own does.
Why advertising is the usual suspect for CLS
Because an ad slot, as implemented by default, is a box with no size until the auction ends. The browser paints the page with the slot at zero height, the response arrives, the creative is 250 pixels tall and everything below it shifts down by 250 pixels. Repeat that across five slots and CLS spikes. The most frequent patterns:
- Slots with no reserved height, going from zero to their final size when the ad arrives.
- Multi-size slots where there is no way to know which height will come.
- Ads injected between paragraphs once the page has already painted.
- Containers that collapse on an empty auction and are then filled with a fallback.
- Sticky bars that push the content instead of sitting on top of it.
Reserve the space before the ad arrives
The fix is boring and it works: give the container its height before requesting anything. If the slot is going to serve a 300x250, it occupies 250 pixels of height from the first paint, with a neutral background. Whatever arrives, nothing moves. In CSS you get there with min-height or aspect-ratio, and it pays to declare different heights per breakpoint.
If a slot accepts several sizes, reserve the height of the largest one you actually serve, or trim the list so the difference stays small. And for the empty auction, decide up front: either the container always keeps its height, or it collapses, but it does not collapse after having been open. Slots above the fold are the ones that hurt most.
Reserving the space costs no one any revenue: the ad still serves, it just stops pushing the text around.
INP and the real cost of ad scripts
INP replaced the old FID (First Input Delay) and measures something more honest: across all the interactions in a visit, how long the page takes to show a visible response. Google considers 200 milliseconds or less to be good, up to 500 to need improvement, and above that to be poor. Here advertising does weigh directly.
A modern stack loads the ad server library, a header bidding wrapper and one adapter per demand partner. All of that is JavaScript running on the same main thread that handles the user's taps. While that thread is resolving an auction, the menu does not open. What you need to watch is not how many partners you have, but how much main thread they consume between them.
Loading asynchronously: what it fixes and what it does not
A normal script blocks: the browser stops, downloads it, runs it and only then carries on building the page. With async it downloads in parallel and runs as soon as it is ready, without holding up the HTML parser. With defer it also waits until the document is complete. Any ad tag should be async.
But it is worth understanding the limit: async avoids the download block, not the cost of execution. The script still consumes main thread when its turn comes, and it can still move the layout if the slot has no reserved height. Asynchronous is the starting point, not the whole solution.
Lazy loading: do not request what nobody has looked at yet
A long article may have six or seven slots, but the reader only sees one or two before deciding whether to stay. Requesting them all at once multiplies the calls, stretches the auction and ties up the main thread for nothing. Lazy loading fires each slot's request only when it gets close to the visible area.
The margin of anticipation is what needs calibrating. Too short and the ad arrives once the slot has gone past, which lowers viewability. Too long and you are back to loading everything. A common starting point is to request when the slot is one screen away. Slots on the first screen are never deferred.
How many slots a page can take
The temptation when revenue drops is to add one more slot. Every new slot adds requests, auction time and main-thread work, and splits the same attention across more units. At the same time the page responds worse, and a reader who leaves never loads a single impression.
The useful exercise is to look at each slot on its own: what viewability it has, what revenue it brings and what it costs the page. There is almost always one or two that barely bill anything and do dirty the metrics. Removing them usually works out better than adding an eighth.
The summary is short: reserve the height of every slot, load tags asynchronously, defer everything below the fold and review each position for what it really contributes. Advertising and a fast page are not incompatible; what is incompatible is an ad implementation nobody has reviewed.
What could your inventory earn?
We analyse your site and tell you what can be improved. No commitment.
Evaluate your site