Summary
Mobile Lighthouse performance is significantly behind desktop on the three pages the site's PR performance report tracks: Homepage, Install Pulumi, and AWS Get Started (all in the 48-53 range on mobile vs. 91-96 on desktop). This issue documents a root-cause investigation run locally against production with the same Lighthouse invocation and flags (--only-categories=performance, mobile default / --preset=desktop) as .github/workflows' run-lighthouse-pr.sh, and lays out follow-up work. A first, low-risk fix is already merged from this investigation: #20561 (explicit dimensions on the footer background SVG, closing a small CLS gap).
Measurements (single run, production, 2026-07-29)
| Page |
Device |
Score |
FCP |
LCP |
TBT |
TTI |
| Homepage |
mobile |
51 |
2.5s |
4.4s |
3,780ms |
17.7s |
| Homepage |
desktop |
91 |
0.4s |
0.6s |
240ms |
3.8s |
| Install Pulumi |
mobile |
48 |
1.2s |
5.6s |
6,120ms |
19.0s |
| Install Pulumi |
desktop |
96 |
0.4s |
1.1s |
130ms |
3.5s |
| AWS Get Started |
mobile |
53 |
1.2s |
4.8s |
3,000ms |
17.7s |
| AWS Get Started |
desktop |
96 |
0.4s |
1.3s |
80ms |
3.3s |
Single-run lab measurements carry normal Lighthouse run-to-run variance (typically a few points); treat these as directionally accurate, not exact.
Root cause: third-party tag execution, not first-party code or asset weight
This is not a story about unoptimized images, unminified first-party JS, or missing compression. unused-javascript scores clean for bundle.ca90377a.js on every page, and the consent-managed Segment snippet in head.html already uses the two best-practice deferral patterns available at the template level (requestIdleCallback for the analytics load itself in theme/src/ts/consent-manager/analytics.ts, and window.addEventListener('load', ...) for Common Room and the OpenAI pixel). That engineering is sound.
The bottleneck is downstream of it. Once the Segment snippet loads, it fires its configured device-mode destinations — third-party vendor SDKs that execute in-browser rather than server-to-server — essentially all at once. On the homepage, 17 third-party scripts start within a single ~550ms window, totaling 782KB transferred. Breaking down bootup-time scripting duration (JS execution only, excluding parse/layout/idle overhead attributed to the document itself):
| Page |
First-party JS execution |
Third-party JS execution |
Third-party share |
| Homepage |
2,243ms |
3,527ms |
61% |
| Install Pulumi |
1,041ms |
6,682ms |
87% |
| AWS Get Started |
910ms |
3,890ms |
81% |
13 distinct third-party entities appear across the three pages: Google Tag Manager, Google Analytics, Google/Doubleclick Ads, HubSpot, Intercom, LinkedIn Ads, Common Room (cr-relay.com), GrowthBook, OpenAI, Statuspage, Cloudflare CDN, JSDelivr CDN, and Other Google APIs/SDKs. None of these are hardcoded in this repo — grepping the codebase for intercom, licdn, googletagmanager, hs-analytics, etc. across layouts/ and theme/src returns nothing. They're entirely orchestrated by Segment's device-mode destination configuration, which lives in the Segment workspace, not in this codebase.
One concrete inefficiency within that: LinkedIn's destination loads two copies of its insight tag back-to-back on every page (insight.min.js, 20.8KB, and insight.old.min.js, 19.1KB) — 40KB and two script-parse/execute cycles for what should be one integration.
LCP follows from this rather than being an independent problem: lcp-breakdown-insight and lcp-discovery-insight both score clean (the LCP element's own resource loads fast), but elementRenderDelay is elevated because paint is queued behind main-thread contention from the third-party burst. This is consistent with Time to Interactive landing at 17.7–19.0s while the visual metrics (FCP, SI) are comparatively reasonable — the page looks done well before the main thread actually frees up.
What's already fixed
Recommended follow-ups, by owner
Marketing ops / Segment workspace admin (highest-leverage, not a docs-repo code change):
- Audit which configured destinations truly need device-mode execution. Intercom's messenger widget legitimately needs to render in-browser, but pure tracking/conversion destinations — GA4, Google Ads, LinkedIn Ads, HubSpot analytics — are strong candidates for Segment's cloud-mode (server-side) delivery instead, which would remove their browser-side JS (and most of the 61-87% third-party scripting share above) entirely.
- Resolve the duplicate LinkedIn insight tag load (
insight.min.js + insight.old.min.js both firing) — likely a legacy destination setting or a "classic + Insight Tag" double-configuration on LinkedIn's side of the destination.
Docs/frontend engineering:
- Profile
bundle.ca90377a.js specifically on the homepage (1.7-2.0s of scripting time, the single largest first-party contributor on that page, and unused-javascript shows it's all live code, not dead weight) to see whether any of its work can be deferred past first paint or split so less of it is needed for initial interactivity.
render-blocking-insight flags css/bundle.schedule-2e4134d1.css (57KB) on Install Pulumi and AWS Get Started for an estimated 200-230ms FCP/LCP savings — worth a critical-CSS extraction pass, scoped as its own change given the site-wide blast radius of the shared CSS bundle.
- Low priority: a handful of first-party icon SVGs serve with a 60-second cache lifetime (
cache-insight); confirm whether that's intentional or a CDN/hosting cache-control gap.
Methodology
Local lighthouse CLI, Chrome for Testing (headless, --no-sandbox --disable-dev-shm-usage), mirroring run-lighthouse-pr.sh's flags exactly (--only-categories=performance, --preset=desktop for desktop runs, unthrottled default preset for mobile). Full JSON reports for all six page/device combinations were captured and are available on request.
🧠 This issue was filed by workprentice, the automation identity behind Pulumi's Docs Groundskeeper agent, while investigating a Lighthouse performance report at a team member's request. No specific human requester triggered this filing.
Summary
Mobile Lighthouse performance is significantly behind desktop on the three pages the site's PR performance report tracks: Homepage, Install Pulumi, and AWS Get Started (all in the 48-53 range on mobile vs. 91-96 on desktop). This issue documents a root-cause investigation run locally against production with the same Lighthouse invocation and flags (
--only-categories=performance, mobile default /--preset=desktop) as.github/workflows'run-lighthouse-pr.sh, and lays out follow-up work. A first, low-risk fix is already merged from this investigation: #20561 (explicit dimensions on the footer background SVG, closing a small CLS gap).Measurements (single run, production, 2026-07-29)
Single-run lab measurements carry normal Lighthouse run-to-run variance (typically a few points); treat these as directionally accurate, not exact.
Root cause: third-party tag execution, not first-party code or asset weight
This is not a story about unoptimized images, unminified first-party JS, or missing compression.
unused-javascriptscores clean forbundle.ca90377a.json every page, and the consent-managed Segment snippet inhead.htmlalready uses the two best-practice deferral patterns available at the template level (requestIdleCallbackfor the analytics load itself intheme/src/ts/consent-manager/analytics.ts, andwindow.addEventListener('load', ...)for Common Room and the OpenAI pixel). That engineering is sound.The bottleneck is downstream of it. Once the Segment snippet loads, it fires its configured device-mode destinations — third-party vendor SDKs that execute in-browser rather than server-to-server — essentially all at once. On the homepage, 17 third-party scripts start within a single ~550ms window, totaling 782KB transferred. Breaking down
bootup-timescripting duration (JS execution only, excluding parse/layout/idle overhead attributed to the document itself):13 distinct third-party entities appear across the three pages: Google Tag Manager, Google Analytics, Google/Doubleclick Ads, HubSpot, Intercom, LinkedIn Ads, Common Room (cr-relay.com), GrowthBook, OpenAI, Statuspage, Cloudflare CDN, JSDelivr CDN, and Other Google APIs/SDKs. None of these are hardcoded in this repo — grepping the codebase for
intercom,licdn,googletagmanager,hs-analytics, etc. acrosslayouts/andtheme/srcreturns nothing. They're entirely orchestrated by Segment's device-mode destination configuration, which lives in the Segment workspace, not in this codebase.One concrete inefficiency within that: LinkedIn's destination loads two copies of its insight tag back-to-back on every page (
insight.min.js, 20.8KB, andinsight.old.min.js, 19.1KB) — 40KB and two script-parse/execute cycles for what should be one integration.LCP follows from this rather than being an independent problem:
lcp-breakdown-insightandlcp-discovery-insightboth score clean (the LCP element's own resource loads fast), butelementRenderDelayis elevated because paint is queued behind main-thread contention from the third-party burst. This is consistent withTime to Interactivelanding at 17.7–19.0s while the visual metrics (FCP, SI) are comparatively reasonable — the page looks done well before the main thread actually frees up.What's already fixed
width/heighton the footer background SVG, removing aunsized-imagesflag contributing to CLS. Merged as a same-session, zero-risk fix from this investigation.Recommended follow-ups, by owner
Marketing ops / Segment workspace admin (highest-leverage, not a docs-repo code change):
insight.min.js+insight.old.min.jsboth firing) — likely a legacy destination setting or a "classic + Insight Tag" double-configuration on LinkedIn's side of the destination.Docs/frontend engineering:
bundle.ca90377a.jsspecifically on the homepage (1.7-2.0s of scripting time, the single largest first-party contributor on that page, andunused-javascriptshows it's all live code, not dead weight) to see whether any of its work can be deferred past first paint or split so less of it is needed for initial interactivity.render-blocking-insightflagscss/bundle.schedule-2e4134d1.css(57KB) on Install Pulumi and AWS Get Started for an estimated 200-230ms FCP/LCP savings — worth a critical-CSS extraction pass, scoped as its own change given the site-wide blast radius of the shared CSS bundle.cache-insight); confirm whether that's intentional or a CDN/hosting cache-control gap.Methodology
Local
lighthouseCLI, Chrome for Testing (headless,--no-sandbox --disable-dev-shm-usage), mirroringrun-lighthouse-pr.sh's flags exactly (--only-categories=performance,--preset=desktopfor desktop runs, unthrottled default preset for mobile). Full JSON reports for all six page/device combinations were captured and are available on request.🧠 This issue was filed by workprentice, the automation identity behind Pulumi's Docs Groundskeeper agent, while investigating a Lighthouse performance report at a team member's request. No specific human requester triggered this filing.