The Performance Tax: How Bad Is It?
Key Takeaways
- 01Bundle size under 20KB compressed. Over 100KB is unacceptable for a consent widget.
- 02Parse-time or network-level script blocking. Runtime blocking leaves a compliance gap.
- 03Banner rendered from local template, not remote fetch.
- 04Hardware-accelerated animations (`transform`, not `bottom`/`top`).
- 05Gradual script release post-consent, not avalanche.
LCP Impact: Your Consent Banner Is the Largest Contentful Paint
OneTrust has been benchmarked extensively. DebugBear measured its impact on LCP: the banner text became the LCP element, jumping load times from 1.43 seconds to 3.61 seconds. A RUMvision case study found the cookie banner was the LCP element for 50% of mobile pageviews, with values hitting 4,721ms.
CookieYes is even worse on mobile: 6.5 seconds for LCP, with the banner as the largest contentful element. Google's "good" threshold is 2.5 seconds.
"The banner adds about 48,000 elements to the DOM. On mobile, the banner is the LCP, with an immense 6.5 seconds." stefanchetan, WordPress.org, May 2024
Termly drops WordPress sites scoring 70-74 on PageSpeed to 37-43 with the plugin installed.
"PageSpeed score WITH Termly plugin: 37-43. WITHOUT: 70-74." sriramdev, WordPress.org, June 2024
The pattern is clear: most CMPs don't just affect LCP, they become LCP.
See how the best consent management platforms compare
INP: How Slow Is That "Accept" Button?
DebugBear benchmarked 11 CMPs across 45 test sites (March 2026 update):
| Rank | CMP | Median INP |
|---|---|---|
| 1 | Sourcepoint | 6ms |
| 2 | Usercentrics | 56ms |
| 3 | Cookiebot | 57ms |
| 4 | TrustArc | 67ms |
| 5 | Termly | 69ms |
| 6 | Quantcast | 74ms |
| 7 | CookieYes | 81ms |
| 8 | Didomi | 95ms |
| 9 | OneTrust | 104ms |
| 10 | Osano | 225ms |
| 11 | Google Funding Choices | 468ms (worst) |
The spread is 78x between best and worst (37.5x if you exclude Google Funding Choices as the new outlier). Osano's Accept button still blocks the main thread for 448ms of CPU processing time on the worst-tested site. OneTrust still sits near the bottom of DebugBear's measurements at 104ms median INP, well over Google's 200ms 'good' INP threshold for many Accept interactions on mobile.
The consent banner is typically the first interaction a visitor has with your site. If clicking "Accept" produces a visible lag, you've created a poor first impression before the user has seen your content.
DOM Bloat
Google recommends keeping total DOM size under 1,500 elements. CookieYes injects approximately 48,000 DOM elements when its IAB TCF implementation loads. That's 32x Google's recommended maximum. Cookiebot injects 209 DOM nodes, the highest of any CMP in the Agence Web Performance benchmark (average: 84).
A well-built consent banner needs perhaps 20-30 DOM elements.
JavaScript Bundle Size
| CMP | JavaScript Size | Notes |
|---|---|---|
| OneTrust | 184KB+ | Multi-step chain: otSDKStub.js to otBannerSdk.js |
| Usercentrics | Large (async) | Async JS; exact size not independently benchmarked |
| Transcend | 54.3KB compressed | airgap.js core; UI adds 342KB async |
| Cookiebot | 34KB | Synchronous (render-blocking) |
| Ketch | 20.6KB | npm package, minified before gzip |
| ConsentStack | ~30 KB | Gzipped: 7 KB pre-parse stub plus 23 KB async core |
OneTrust's multi-step loading chain (stub, SDK, configuration) involves at least 3 sequential network requests. On a 3G connection with 200ms round-trip time, the chain alone adds 600ms+ before the banner can render. Cookiebot's synchronous loader has a similar render-blocking cost.
Caching Failures
Cookiebot has the shortest cache TTL of any CMP benchmarked: 11 minutes. Every returning visitor who comes back after 11 minutes re-downloads the entire script. Best practice for a consent SDK is at least 24 hours.
The Post-Consent Avalanche
The worst damage often happens after the user clicks "Accept All." One SpeedCurve study documented this cascade:
- User clicks "Accept All"
- CMP processes consent and updates storage
- CMP signals consent to GTM via
updateGtmMacros - GTM fires all previously-blocked tags simultaneously
- 73 additional third-party requests load at once
- Page becomes unresponsive during script evaluation
OneTrust's updateGtmMacros function alone takes 190ms of main thread time. Total accept-click processing: ~238ms.
ConsentStack addresses this with gradual script release: blocked scripts are re-injected in a controlled sequence rather than all at once. Learn how to set up Google Consent Mode v2 to handle GTM consent signaling properly.
Why CMPs Are So Heavy
The Platform Problem
Enterprise CMPs didn't start as consent tools. OneTrust is a privacy platform with modules for data mapping, DSAR workflows, and AI governance. The SDK that renders a banner is a delivery mechanism for the platform, not the product itself. Nobody optimized the thing users actually see because the SDK was never the revenue driver.
ConsentStack took the opposite approach: the SDK is the product. A ~30 KB gzipped bundle (a 7 KB pre-parse stub plus a 23 KB core that loads asynchronously) isn't a marketing constraint. It's a design decision.
Render-Blocking Patterns
Synchronous scripts prevent any content from rendering until they load. Cookiebot's 34KB loads synchronously.
CSS layout animations cause layout thrashing. OneTrust uses the CSS bottom property to animate the banner instead of hardware-accelerated transform: translateY().
Multi-step script chains multiply latency. OneTrust's fetch stub, fetch SDK, fetch configuration sequence involves 3 sequential network requests.
How Parse-Time Script Blocking Changes Everything
The Standard Approach: Runtime Blocking
- Browser begins parsing HTML
- Third-party scripts start loading and executing
- Cookies are set, tracking pixels fire
- CMP script loads (100-200KB+)
- CMP renders the banner
- CMP attempts to retroactively block scripts that already ran
There's a window of non-compliance between page load and CMP initialization. This is why 59% of websites with CMPs still set cookies before consent.
The Parse-Time Approach
ConsentStack installs a MutationObserver during HTML parsing, before any third-party scripts execute:
- ConsentStack stub loads high in
<head>(~7 KB gzipped, non-render-blocking). The full ~30 KB core arrives asynchronously after the stub installs the blocker. - MutationObserver installed at parse time, watching the DOM
- Any
<script>element is intercepted before the browser executes it - Scripts checked against 900+ tracker patterns sourced from open tracker databases
- Matched scripts blocked and held in memory
- User makes consent choice
- Approved scripts re-injected; denied scripts never execute
Zero cookies before consent. Zero data leakage.
Why This Matters for Core Web Vitals
No LCP impact. The pre-parse stub is ~7 KB, the core SDK loads asynchronously after the stub is already blocking trackers, and there's no remote configuration fetch or multi-step chain.
No CLS. Fixed positioning overlay instead of document flow insertion.
No INP disaster. Consent processed by a ~30 KB SDK, not a 200 KB+ enterprise bundle.
No post-consent avalanche. Gradual script release via staggered re-injection.
Learn how parse-time script blocking works
Measuring Your CMP's Performance Impact
Step 1: Baseline Without CMP
Remove your CMP on staging. Run Lighthouse 3 times and average: LCP, INP/TBT, CLS, total JS size, DOM element count.
Step 2: Measure With CMP
Re-add the CMP. Compare deltas. If LCP jumped 500ms+, your CMP is a significant bottleneck. If it added 50KB+ of JavaScript, it's heavier than it needs to be.
Step 3: Real User Monitoring
Check CrUX data via PageSpeed Insights. The critical question: is your consent banner becoming your LCP element?
Step 4: Network Waterfall
A well-designed CMP should add 1-2 requests totaling under 50 KB compressed. If you're seeing 4+ requests totaling 200 KB+, you have an architectural weight problem.
Step 5: INP Testing
Click Accept, Reject, and Preferences while recording in the Performance tab. Google's threshold is 200ms. Osano's Accept button still blocks for 448ms on the worst-tested site. OneTrust's chain regularly exceeds it. Both fail.
The CMP Performance Benchmark
| CMP | SDK Size | LCP Impact | INP (Median) | DOM Nodes | Blocking Method | Cache TTL |
|---|---|---|---|---|---|---|
| ConsentStack | ~30 KB gzipped | Negligible | <50ms target | Minimal | Parse-time MutationObserver | 24hr+ |
| Sourcepoint | N/A | N/A | 6ms | N/A | Proprietary | N/A |
| Usercentrics | Large | Moderate | 56ms | N/A | Runtime | N/A |
| Cookiebot | 34KB sync | Moderate | 57ms | 209 | Scanner-based | 11 min |
| TrustArc | N/A | 2+ min reported | 67ms | N/A | Runtime + fake delays | N/A |
| Quantcast | N/A | Moderate | 74ms | N/A | Runtime | N/A |
| CookieYes | N/A | 6.5s mobile | 81ms | 48,000 | Runtime | N/A |
| Didomi | N/A | N/A | 95ms | N/A | Runtime | N/A |
| OneTrust | 184KB+ | 1.43s to 3.61s | 104ms | N/A | Runtime | N/A |
| Osano | Small | Low | 225ms (10th of 11) | Low | Runtime | 1 day |
| Termly | N/A | 6.5s reported | 69ms | N/A | Runtime | N/A |
| Google Funding Choices | N/A | N/A | 468ms (worst of 11) | N/A | Runtime | N/A |
Key takeaways: INP spread is 78x between best and worst CMPs (37.5x excluding Google Funding Choices as a new outlier). OneTrust ships 184KB+ of JavaScript, over 6x larger than ConsentStack. Cookiebot's 11-minute cache means every returning visitor re-downloads the script. DebugBear data accurate as of 2026-03-17; figures will be re-verified each audit pass.
What to Look for in a Performance-First CMP
- Total bundle under 50 KB compressed, with a small pre-parse stub doing the script blocking. Over 100 KB is unacceptable for a consent widget.
- Parse-time or network-level script blocking. Runtime blocking leaves a compliance gap.
- No render-blocking scripts.
- Banner rendered from local template, not remote fetch.
- Hardware-accelerated animations (
transform, notbottom/top). - 24+ hour cache TTL.
- Gradual script release post-consent, not avalanche.
- INP under 100ms for all interactions.
ConsentStack was designed against every item on this checklist. ~30 KB gzipped SDK (7 KB stub + 23 KB core), parse-time MutationObserver blocking, async loading, local template rendering, hardware-accelerated animations, 24-hour+ caching, gradual script release, sub-50ms interaction targets.
Frequently Asked Questions
Yes, directly. Google uses Core Web Vitals (LCP, INP, CLS) as ranking signals. A CMP that pushes LCP from 1.4s to 3.6s (OneTrust, per DebugBear) or injects 48,000 DOM elements (CookieYes) will degrade your scores. Google doesn't penalize you for *having* a consent banner. It penalizes you for having a slow site.
It depends on the CMP. On the light end, well under 50 KB and negligible load time. On the heavy end: OneTrust adds 184 KB+ and increases LCP by over 2 seconds. Termly drops WordPress PageSpeed scores by 30+ points. CookieYes can produce 6.5-second mobile LCP. ConsentStack's ~30 KB SDK (a 7 KB pre-parse stub plus a 23 KB async core) keeps the impact at near-zero.
Yes. GDPR requires collecting consent before tracking, not 200 KB of JavaScript. A ~30 KB SDK with parse-time script blocking achieves the same compliance outcome as a 200 KB enterprise SDK. ConsentStack supports 195+ regulations with that bundle. [Read the full GDPR cookie consent requirements](https://www.consentstack.io/blog/gdpr-cookie-consent-requirements).
ConsentStack at **~30 KB gzipped** (7 KB pre-parse stub plus 23 KB async core). Ketch is 20.6 KB minified. Cookiebot is 34 KB synchronous. Transcend is 54.3 KB compressed plus 342 KB async UI. OneTrust is 184 KB+. Both size and loading strategy matter.
Neither is ideal. `async` may interrupt rendering. `defer` waits until parsing is complete, creating a compliance window. The best approach is a CMP small enough that the strategy barely matters. ConsentStack's ~7 KB pre-parse stub installs the MutationObserver before other scripts can execute, closing the compliance window without blocking rendering.
Conclusion
Consent management is a legal requirement. Performance destruction is not. Nothing in any privacy regulation says you need 200KB of JavaScript to ask someone if they accept cookies.
ConsentStack was built to prove consent management and web performance aren't in conflict. ~30 KB gzipped (7 KB pre-parse stub + 23 KB async core). Parse-time MutationObserver script blocking. Zero tracking before consent. 195+ regulations. $29/site/month.
Your Lighthouse scores earned every point through careful optimization. Your consent banner shouldn't take them away.