Almost every website in Europe greets its visitors with a consent dialog. Technically that dialog is not a side note: it sits on top of the visible area, it loads very early, and on mobile devices it regularly contains the largest text element the browser paints. That makes it a factor in Largest Contentful Paint, in the response time of the very first click and in layout stability while it appears and disappears. This article shows how to measure the consent layer's impact properly in the field, which changes take it out of the critical path, and where the legal framework limits design freedom.
Key takeaways
- A full-screen consent layer becomes the LCP element itself, since it brings a heading, body text and buttons and paints later than the hero image; on mobile, 23.7 percent (HTTP Archive Web Almanac 2025) of pages have a text block as LCP.
- The first dialog level belongs in the HTML the server already sends, with its CSS inlined in the document. This holds up legally because consent covers storing and reading data on the device, not displaying a notice.
- A fixed-position overlay moves nothing when it appears or disappears, whereas a block element at the top of the document pushes all content down; transitions run on transform and opacity instead of height.
- The click on accept is often the first interaction ever measured. Firing every tag inside that handler inflates processing time, while staggering the loads into idle periods keeps INP below 200 milliseconds (Google web.dev).
- Section 25 TDDDG and the German DSK guidance require consent-bound scripts to start only after the decision; if the banner covers content, the first level needs an equally reachable reject option (DSK).
- Purpose and vendor lists belong on the second level so the first stays at a handful of DOM nodes; which element supplies the LCP is settled by field measurement that logs the LCP element, not by a lab run on an empty profile.
Why the consent layer ends up in the critical path
The critical path covers everything the browser has to load, parse and execute before it can paint the visible area. A consent dialog belongs there by construction: it is supposed to appear before any consent-dependent script starts, and it is supposed to do so without flickering. Many implementations solve both by placing an external script as high in the document as possible, frequently without defer and often with an additional stylesheet. Before the first pixel there is a full chain: DNS resolution, TLS handshake, download, parsing, execution, DOM construction, style calculation. Every one of those steps costs considerably more time on a mobile connection than on the office network the dialog was built on.
How large that block turns out depends on third-party usage. The HTTP Archive Web Almanac 2025 finds that at least 90 percent (HTTP Archive Web Almanac 2025) of pages embed one or more third parties; across the full dataset the analysis counts around 79 third-party requests (HTTP Archive Web Almanac 2025) per page on mobile. The Privacy chapter adds that 74 percent (HTTP Archive Web Almanac 2025) of mobile pages load at least one third-party tracker. Almost all of those resources require consent, which ties them to the consent layer: it becomes the gate the rest of the page has to pass through.
Field data shows where this leads. According to Chrome UX Report measurements, 62 percent (HTTP Archive Web Almanac 2025) of pages reach a good LCP value on mobile devices while 13 percent (HTTP Archive Web Almanac 2025) fall into the poor range; on desktop 74 percent (HTTP Archive Web Almanac 2025) are good. The gap between device types is widest exactly where an overlay dominates the small viewport. If you want to place your own numbers in context, our page on optimizing the Core Web Vitals covers the fundamentals of all three metrics.
The dialog is mandatory, not an add-on
When the banner becomes the LCP element
Largest Contentful Paint measures the moment the largest image or text element in the visible area has been painted. Candidates include images, video posters, elements with a CSS background image and block elements containing text. The value keeps updating: if the browser paints a larger element later, that element replaces the previous candidate. This is exactly what happens when a full-screen consent layer appears after the hero area and covers it. The measurement then no longer refers to the hero image but to a dialog that only exists once the third-party script has run.
On mobile devices the effect is strongest. 76 percent (HTTP Archive Web Almanac 2025) of mobile pages have an image as their LCP element, while 23.7 percent (HTTP Archive Web Almanac 2025) have a text block; on desktop text accounts for only 14.4 percent (HTTP Archive Web Almanac 2025). A dialog that occupies two thirds of a 390 pixel wide viewport brings a heading, a description and two buttons with it. That makes it a serious LCP candidate, and it is typically painted later than the hero image underneath. In performance audits this is one of the most frequently recurring findings of all (project experience).
The damage is twofold. First, the late-painted layer pushes the measurement point back. Second, the consent script competes for connections and bandwidth with exactly those resources that are meant to fill the visible area. On a mobile connection every additional connection to an external host costs time that the hero image no longer has. The consent layer therefore slows down not only itself but everything it was only meant to cover.
Covering the hero area
The layer sits on top of the hero image and brings its own large text block. The browser treats it as a new, larger candidate and moves the LCP timestamp forward.
Late paint from an external script
If the dialog has to be created by an external script first, connection setup, download, parsing and DOM creation all happen before a single pixel of the dialog appears.
Its own font and icons
If the layer ships its own web font or icon file, text rendering waits for those resources as well. Render delay grows without any gain in content.
Measure the impact instead of guessing
A lab run rarely shows the consent layer's true effect. Some test setups start with an empty profile in which the dialog is bound to appear, while a large share of real visitors do not see it again because a decision is already stored. Other setups block external hosts and therefore suppress the dialog by accident. The assessment only becomes reliable with field data that contains both cases at their real frequency. How lab and field measurement complement each other is covered in the article on field data from CrUX and your own monitoring.
The decisive step is to log not just the LCP value but the LCP element in the field. The Chrome UX Report provides the distribution of values, not the information about which element causes them. The browser itself supplies that through its performance interfaces. Three observers are enough to clarify the consent layer's role: one for the LCP element, one for the subparts of the accept interaction and one for layout shifts including the node that caused them.
// Log the LCP element in the field
new PerformanceObserver((list) => {
const entry = list.getEntries().at(-1);
const el = entry.element;
report('lcp', {
value: Math.round(entry.startTime),
tag: el ? el.tagName : null,
id: el ? el.id : null,
insideConsentLayer: !!(el && el.closest('#consent-layer'))
});
}).observe({ type: 'largest-contentful-paint', buffered: true });
// Subparts of the accept interaction (INP)
new PerformanceObserver((list) => {
for (const e of list.getEntries()) {
if (!e.interactionId) continue;
report('interaction', {
target: e.target ? e.target.id : null,
inputDelay: Math.round(e.processingStart - e.startTime),
processing: Math.round(e.processingEnd - e.processingStart),
presentation: Math.round(e.startTime + e.duration - e.processingEnd)
});
}
}).observe({ type: 'event', durationThreshold: 40, buffered: true });
// Layout shifts including the element that caused them
new PerformanceObserver((list) => {
for (const e of list.getEntries()) {
if (e.hadRecentInput) continue;
for (const q of e.sources || []) {
report('shift', { value: e.value, node: q.node ? q.node.nodeName : null });
}
}
}).observe({ type: 'layout-shift', buffered: true });For interactions the thresholds are clear: a good INP value is 200 milliseconds (Google web.dev) or below, and from 500 milliseconds (Google web.dev) it counts as poor, measured at the 75th percentile. Every interaction splits into input delay, processing duration of the event callbacks and presentation delay (Google web.dev). On the accept click all three come together: the main thread is still busy with the consent script, the callbacks then start a whole series of tags, and afterwards the browser has to paint a frame without the dialog. The underlying systematics are covered in the article on optimizing Interaction to Next Paint.
For layout stability the construction decides. A fixed overlay sits outside the text flow and shifts nothing. A banner inserted as a block element at the top of the page pushes the entire content down and produces a shift both when it appears and when it is removed. In field data 81 percent (HTTP Archive Web Almanac 2025) of mobile pages reach a good CLS value, on desktop it is 72 percent (HTTP Archive Web Almanac 2025). Wherever the value breaks, a late-inserted layer is an obvious suspect.
| Metric | Typical contribution of the consent layer | Field measurement | Target range |
|---|---|---|---|
| LCP | Layer covers the hero and becomes the largest element itself | Log the LCP element with tag, id and container | under 2.5 seconds |
| INP | Accepting starts several tags at the same time | Event Timing with interactionId, subparts logged separately | under 200 milliseconds |
| CLS | Appearing pushes content, removal lets it jump back | Log layout shift sources with node names | under 0.1 |
| TTFB | An extra external host lengthens connection setup | Evaluate Navigation Timing and Server-Timing | around 40 percent of LCP |
| Blocking time | Parsing and executing the consent script before first paint | Long Animation Frames with the causing script | as close to zero as possible |
Serve the banner markup from the server
The most effective single measure is also the least spectacular: the first layer of the dialog belongs in the HTML document the server delivers anyway. It does not have to be produced by a script the browser first downloads, parses and executes. Once the markup is in the document, the dialog appears with the very first frame of the page. The resource load delay that otherwise sits between server response and rendering disappears entirely for this element.
Google web.dev suggests an LCP breakdown in which server response time accounts for roughly 40 percent (Google web.dev), loading the LCP resource for roughly 40 percent (Google web.dev) as well, and the two delay subparts - resource load delay and element render delay - each stay below 10 percent (Google web.dev). A dialog injected by a third-party script lands precisely in those two delay subparts, the ones the same source recommends keeping as close to zero as possible. If you also want to work on server response time, the levers are described on our TTFB optimization page and in the article on Early Hints and server think time.
<!-- First layer straight from the server response, no third-party script -->
<style>
#consent-layer{position:fixed;inset:auto 0 0 0;z-index:9999;background:#fff;
border-top:1px solid #d3d8e2;padding:16px;contain:layout paint;
font:16px/1.5 system-ui,-apple-system,sans-serif}
#consent-layer[hidden]{display:none}
.cl-actions{display:flex;gap:12px;margin-top:12px}
.cl-actions button{flex:1 1 0;min-height:44px;font:inherit;cursor:pointer;
border:1px solid #2356a0;border-radius:8px;background:#fff;color:#132d5c}
</style>
<div id="consent-layer" role="dialog" aria-modal="true" aria-labelledby="cl-title">
<h2 id="cl-title">Cookies and audience measurement</h2>
<p>Optional cookies are only set after your consent.</p>
<div class="cl-actions">
<button type="button" data-consent="deny">Reject all</button>
<button type="button" data-consent="allow">Accept all</button>
</div>
<p><a href="/en/privacy/">Privacy</a> | <a href="/en/imprint/">Imprint</a></p>
</div>Legally this change is unproblematic, because the banner itself does not require consent. Consent is required for storing information on terminal equipment and reading information already stored, not for displaying a notice. Server-rendered markup sets no cookie and calls no external host. It meets the requirement even better than a script-based solution that has to open a connection to a third party just to display the dialog.
Know the consent state on the server
Build the layer without a layout shift
A consent layer causes no layout shift as long as it does not touch the text flow. In practice that means position: fixed instead of a block element at the start of the document, positioning via inset instead of margins that displace other elements, and contain: layout paint so that changes inside the dialog do not trigger a recalculation of the rest of the page. If the notice is meant to sit in the flow on purpose, it needs a container with a fixed minimum height reserved from the first frame onwards. Inserting it afterwards reliably produces a shift.
A second problem often comes on top. 62 percent (HTTP Archive Web Almanac 2025) of mobile pages fail to set dimensions on at least one image. When a late-inserted layer meets images without reserved space, two shifts add up to a visibly jumping entry point. The systematics behind this and the matching remedies are described in the article on avoiding cumulative layout shift.
Fixed instead of in the flow
An overlay with fixed positioning sits outside the layout. Showing and hiding it changes the position of no other element, so its CLS contribution stays at zero.
Reserve the space up front
If the notice sits in the flow, give it a container with a fixed minimum height that is present in the first rendered frame. The content fills it instead of expanding it.
Composited animations only
Fading in and out via transform and opacity runs without layout calculation. Animating height or margins forces a layout recalculation on every frame.
CSS, fonts and icons of the dialog
A dedicated stylesheet for the consent layer is one more render-blocking file, at the most sensitive point of the loading process. The first layer rarely needs more than two to four kilobytes of CSS: background, border, typography, two buttons, a focus style. Those few rules belong inline in the document. Everything else - the settings layer with purposes, descriptions and vendor list - can be loaded when someone actually opens it. The approach follows the principle described in the article on critical CSS for the visible area.
Fonts deserve the same scrutiny. 87 percent (HTTP Archive Web Almanac 2025) of mobile pages embed at least one web font. If the consent layer brings an additional font because the tool ships its own design, the dialog's text rendering waits for another file from another host. The sensible choice is the font the page loads anyway, or the system font stack. The article on web font performance shows which levers exist.
Icons follow the same logic. A dialog rarely needs more than two or three symbols; these belong in the markup as inline SVG, not as an icon font or a sprite file. That removes another request from the critical path, and the symbols appear at the same moment as the text. Tackling these points together is the same construction site as frontend optimization in general.
- First-layer CSS inline in the document, no separate stylesheet in the critical path
- No additional web font just for the dialog, use the existing font or the system stack
- Symbols as inline SVG instead of an icon font or an external sprite file
- No background or gradient image that the browser has to load first
- Buttons with a target size of at least 44 pixels so mis-taps do not force a second interaction
- Focus order and labels in the markup, not added afterwards by script
Start deferred scripts only after consent
The fact that consent-dependent scripts must not run before the decision is not an optimization question but a requirement. The German data protection authorities' guidance puts it plainly: while the consent banner is displayed, no further scripts that access terminal equipment or process personal data are loaded, and in particular no content from external servers, insofar as consent is required for it (DSK guidance). The performance effect is a welcome side effect: everything moved behind the decision leaves the critical path.
The second part is frequently overlooked. After consent many implementations fire all tags in a single burst, triggered directly inside the click event. That is exactly the moment the browser measures the interaction. A trivial click turns into an interaction with long processing duration and delayed presentation. A staggered start works better: the click only hides the layer and stores the decision, while the tags follow during idle periods, on visibility or on interaction. The patterns that have proven useful are described in the article on trimming third-party scripts.
const layer = document.getElementById('consent-layer');
layer.addEventListener('click', async (ev) => {
const btn = ev.target.closest('[data-consent]');
if (!btn) return;
const granted = btn.dataset.consent === 'allow';
layer.hidden = true; // fixed overlay: hiding it causes no layout shift
storeConsent(granted); // own first-party cookie, no external call
if (!granted) return;
// Only now, and staggered: none of this sits in the critical path
await nextGap();
loadScript('/assets/measurement.js');
await nextGap();
onVisible('.map-embed', () => loadScript('/assets/map.js'));
});
function nextGap() {
return new Promise((done) => {
if (window.scheduler && scheduler.yield) return scheduler.yield().then(done);
if (window.requestIdleCallback) return requestIdleCallback(done, { timeout: 500 });
setTimeout(done, 0);
});
}The first click shapes the quality impression
Limit the DOM size of the dialog
Consent tools frequently ship complete purpose and vendor lists even when nobody opens them. A dialog with five visible lines quickly turns into several thousand DOM nodes. Google web.dev points out explicitly that rendering work scales with DOM size: when the DOM is small, rendering finishes quickly, but when DOMs get very large, rendering work tends to scale with them (Google web.dev). That affects not only the initial build but every later style change and every interaction.
Nesting amplifies the effect. The HTTP Archive Web Almanac 2025 measures a median inclusion chain depth of 3 levels (HTTP Archive Web Almanac 2025) for third parties and, in the extreme case, 2,285 levels (HTTP Archive Web Almanac 2025). A consent tool that loads vendor lists dynamically and embeds resources of its own sits right inside that chain. A clear separation therefore helps: layer one with text, two equivalent buttons and the mandatory information in the markup, everything else only on opening.
Where long lists are unavoidable, it helps to spare the browser rendering work for sections that are not visible. How that works is shown in the article on content-visibility and saved rendering work; the general systematics of node counts are covered in the article on reducing DOM size.
A consent dialog rarely needs more than thirty DOM nodes on its first layer. Everything beyond that is stock kept for a case that most visits do not reach - and it is paid for on every single page view.
What the legal framework requires
The basis is Section 25 TDDDG, the successor to the former TTDSG, together with the GDPR requirements for valid consent. The German data protection authorities make it clear that the declaration of intent must already have been given before consent-dependent access to terminal equipment takes place; it is not permissible to set consent-dependent cookies on the first call of a website and only ask for consent afterwards (DSK guidance). Any optimization that pulls scripts forward to smooth out loading is therefore ruled out.
The design requirements are equally clear. According to the guidance, the freely given nature of consent is noticeably affected if rejecting all consent-dependent access means measurable additional effort, for example because it is only possible on a second banner layer and thus with a higher number of clicks (DSK guidance). The authorities consider a reject function on the first layer necessary where users have to interact with the banner in order to continue their visit (DSK guidance). The legal requirement therefore hangs on exactly the same design decision that drives the metric: anyone covering the visible area with a layer needs the equivalent reject option.
The European Data Protection Board collected the recurring patterns in its Cookie Banner Taskforce report. The designs criticised include pre-ticked boxes, deceptively designed links and color schemes, and setting consent-dependent cookies before the decision (EDPB Cookie Banner Taskforce). Article 7(3) GDPR adds that withdrawing consent must be as easy as giving it. A consent layer that is lean on first load but hides its withdrawal option behind nested menus solves only half the problem.
| Measure | Effect on loading time | Legal assessment |
|---|---|---|
| Serve banner markup in the HTML | Removes an entire script round trip from the critical path | Permitted, the display itself does not require consent |
| Inline the first-layer CSS | Saves one render-blocking file | Permitted, concerns presentation only |
| Load scripts only after an active choice | Moves the whole third-party load behind first paint | Required under Section 25 TDDDG and DSK guidance |
| Render the vendor list on the second layer | Reduces DOM size considerably | Permitted, provided the first layer informs fully |
| Drop the reject button to save nodes | Negligible gain | Not permitted where the banner covers content (DSK) |
| Treat scrolling or clicking on as consent | Saves an interaction | Not valid consent (EDPB Cookie Banner Taskforce) |
Speed justifies no shortcuts
The order in which the rebuild pays off
The measures differ considerably in effort and effect. Starting with measurement avoids rebuilding places that play no role in the field at all. Only once it is established that the layer really shows up as the LCP element, or that the accept interaction dominates the INP distribution, is it worth intervening in delivery. The following order has proven itself in audits.
- Log the LCP element in the field and evaluate first visits and return visits separately
- Measure the subparts of the accept interaction: input delay, processing, presentation
- Record layout shifts with the causing node to separate showing from hiding
- Serve the first layer of the dialog from the server and inline its CSS
- Position the overlay fixed or reserve space, limit animations to transform and opacity
- Remove the dialog's font and icon load, move the vendor list to the second layer
- Start deferred scripts in stages after the decision and measure again in the field
In most projects the first three steps are done within a day, because they require no change to the production system. The rebuilds themselves depend on how deeply the consent tool in use reaches into the page. We classify the findings as part of a technical performance analysis, check them against the Lighthouse audit and implement the changes as part of frontend optimization. The overall view of the metrics and their causes is on our Core Web Vitals page, and the service overview shows the full scope.
One element, three metrics
Sources and studies
Related Articles
Speculation Rules: Instant Navigation via Prerendering
How the Speculation Rules API prefetches or prerenders next pages, tunes eagerness correctly, and avoids wasted prerenders and analytics side effects.
Mobile Performance: Speeding Up Shops on Phones
How throttled CPU, slow networks, viewport and touch shift mobile Core Web Vitals and which levers speed up your shop on the phone where revenue happens.
Break Up Long Tasks: Lower INP with scheduler.yield
Break long JavaScript tasks over 50 ms into chunks with scheduler.yield(), free the main thread between the chunks and keep the INP steadily under 200 ms.