Portfolio performance baseline — 6 surfaces · 2026-05-20
The first portfolio-wide perf-trend run, the day-zero baseline that 90-day comparisons get anchored against. Six public surfaces measured via Google’s PageSpeed Insights Lighthouse lab (synthetic). pa.gf.cx skipped — CDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF-Access-gated, lab would have measured the login page rather than the actual content.
TL;DR
| Surface | Mobile score | Mobile LCP | Desktop score | Desktop LCP | Verdict |
|---|---|---|---|---|---|
| dare.co.uk | 100 | 817ms 🟢 | 100 | 409ms 🟢 | Gold standard — top-tier both |
| beta.dogwood.house | 94 | 2,866ms 🟡 | 100 | 613ms 🟢 | Desktop great; mobile LCP needs trim |
| gf.cx | 93 | 3,157ms 🟡 | 100 | 522ms 🟢 | Built today — hero photo likely the LCP culprit on mobile |
| dansellars.com | 87 | 3,631ms 🟡 | 99 | 751ms 🟢 | Personal landing — mobile LCP NI |
| bookings.audreyinc.com | 80 | 3,610ms 🟡 | 98 | 850ms 🟢 | Functions-backed booking form — mobile LCP NI |
| audreyinc.com | 78 | 5,061ms 🔴 | 93 | 1,615ms 🟢 | Shopify default theme weight — real signal worth Audrey acting on |
Two real findings worth acting on:
- audreyinc.com mobile LCP at 5.06s is poor tier (Google’s threshold: ≤2.5s good · ≤4s NI · >4s poor). This is the real signal Workstream B (Shopify ↔ GitHub theme integration) was designed to address — once theme is git-tracked, perf-tuning via Liquid/CSS/JS edits becomes a normal commit + auto-deploy cycle.
- dare.co.uk’s 100/100 both is exceptional — confirmation that the hand-optimised static-rebuild work (Helvetica system stack, Newsreader for
<em>accent, inline SVG, no JS frameworks, image-dimensions-on-every-img, CDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF Pages caching) bought what it was supposed to.
The visual — mobile LCP across the portfolio
The visual — desktop LCP
What “synthetic lab metrics” actually means
Yes — sci-fi is the right framing. Here’s literally what happens behind every row in those tables:
- Google spawns a virtualised Chrome browser in one of their data centres
- For mobile: it emulates a Moto G Power (a mid-range 2020s Android phone — deliberately not a flagship, because Google’s measuring what real mid-range users see). CPU throttled 4× slower than the data-centre hardware. Network throttled to “Slow 4G” — about 1.6 Mbps down, 750 Kbps up, 150ms round-trip-time
- For desktop: standard Chrome on “Dense 4G” — about 10 Mbps down, 40ms RTT
- The virtualised Chrome loads the URL at that throttled speed, exactly once
- Lighthouse’s audit suite runs alongside the page load — instrumenting every paint, every script execution, every layout shift, every byte transferred
- It returns the numbers within ~30 seconds
So when you read bookings.audreyinc.com · LCP 3,610ms on the table, it literally means: “a robot Chrome browser in a Google datacenter, pretending to be a Moto G Power on slow 4G, just loaded bookings.audreyinc.com and the largest content element appeared on its virtual screen 3,610 milliseconds after the request.”
There is a phantom Chrome out there in the world right now, loading every surface in our portfolio, on demand, with a stopwatch.
Synthetic vs field — when each works
| Synthetic (PSI lab) | Field (CrUX) | |
|---|---|---|
| Who’s measuring | Robot Chrome in Google data center | Real Chrome users in the wild |
| When | On-demand, one page-load per call | Continuous, aggregated p75 over 28 days |
| Conditions | Standardised throttle (deterministic) | Whatever real users have (diverse) |
| Coverage | Any URL on the internet | Only origins with enough Chrome traffic (~thousand uniques/28d) |
| Today | ✅ Works for all 6 surfaces | ❌ Below threshold for all 6 |
CrUX field data would be richer (real users, p75 from real diversity), but our surfaces are all sub-threshold today. Synthetic gives us a deterministic baseline we can track over time. As traffic grows, the script will automatically prefer CrUX field data when it becomes available — no code change needed.
Per-metric thresholds (Google’s official Core Web Vitals)
| Metric | What it measures | 🟢 Good | 🟡 Needs improvement | 🔴 Poor |
|---|---|---|---|---|
| LCP | Largest Contentful Paint — when the biggest content element appears | ≤ 2.5s | ≤ 4.0s | > 4.0s |
| INP | Interaction to Next Paint — responsiveness to clicks/taps (lab proxy: Total Blocking Time) | ≤ 200ms | ≤ 500ms | > 500ms |
| CLS | Cumulative Layout Shift — how much things move during load | ≤ 0.10 | ≤ 0.25 | > 0.25 |
| TTFB | Time to First Byte — server response time | ≤ 800ms | ≤ 1800ms | > 1800ms |
| FCP | First Contentful Paint — when ANY content appears | ≤ 1.8s | ≤ 3.0s | > 3.0s |
The mobile-LCP 2.5s line is the most consequential threshold — it’s a Google SEO ranking signal as of 2024.
What this baseline tells us
Two-tier portfolio shape
Tier 1 — 🟢 mobile-good (the gold standard):
- dare.co.uk — 817ms · 100/100 · the static-archive build is exemplary
Tier 2 — 🟡 mobile needs-improvement (the workable middle):
- beta.dogwood.house — 2.87s · likely the hero image (per the dogwood-agent-stack build today)
- gf.cx — 3.16s · the Newsreader font + dan-audrey hero photo loading (just built today)
- dansellars.com — 3.63s · older personal landing, untouched in a while
- bookings.audreyinc.com — 3.61s · Functions backend doesn’t slow LCP; likely a font/CSS payload trim opportunity
Tier 3 — 🔴 mobile poor (the real opportunity):
- audreyinc.com — 5.06s · this is the Shopify default theme + Shopify’s framework JS payload
Where the lever is
The Tier 3 surface is where the Workstream B Shopify-GitHub theme integration earns its keep. Once audrey’s theme is in git, mobile LCP optimisations land via normal commit + auto-deploy:
- Defer / async non-critical JS
- Inline critical CSS, defer the rest
- Optimise hero image (responsive srcset, modern format, preload hint)
- Reduce font weights loaded
- Audit + remove unused Shopify apps that inject heavy JS
Realistic target after Workstream B: get audrey mobile LCP from 5.06s → ~2.5s. The 90-day trend card will show the lift as the work lands.
Where the lever isn’t
dare.co.uk already wins. Don’t optimise what’s working. Continue editorial work; the perf trend on dare just becomes the canary that catches regressions if/when they happen (e.g., a future image-heavy article that doesn’t follow the existing image-dimensions discipline).
What unlocks from here
Daily run → 90-day trend (automatic)
Schedule the script via launchd or cron at a stable time daily:
# launchd plist or crontab
0 7 * * * /Users/dansellars/bin/dare_perf_trend.py
0 7 * * * /Users/dansellars/bin/dare_perf_trend.py --origin https://www.audreyinc.com
0 7 * * * /Users/dansellars/bin/dare_perf_trend.py --origin https://beta.dogwood.house
0 7 * * * /Users/dansellars/bin/dare_perf_trend.py --origin https://gf.cx
0 7 * * * /Users/dansellars/bin/dare_perf_trend.py --origin https://bookings.audreyinc.com
0 7 * * * /Users/dansellars/bin/dare_perf_trend.py --origin https://www.dansellars.com
After 7 days: “vs last week” columns populate After 28 days: meaningful month-over-month After 90 days: the ~90d delta that Dan asked for becomes real
Dashboard cards for dash.dare.co.uk
The next build is per-surface mini-cards on dash.dare.co.uk showing this shape (here’s audreyinc.com as a worked example):
One card per portfolio surface. Color-coded threshold dot. Inline 90-day sparkline (red line drops below the 2.5s dashed reference = LCP improved across the window). Click-through to the full trend page. Same shape as the existing edge-health cards on dash.dare.co.uk that landed earlier today.
Build trigger: after ~7 days of daily runs accumulate so the sparklines have data to draw against. Until then, today’s portfolio baseline IS the data.
Health hygiene integration (Dan’s framing)
Per Dan 2026-05-20: “It’s a foundational capability that can be across our health/hygiene checks - and clients will love it.”
The perf-trend pattern becomes part of the daily-hygiene tripwire suite — same shape as dare_404_audit.py, dare_header_audit.py, dare_body_image_coverage.py. When LCP crosses the threshold (mobile good → NI, or worse), the daily hygiene report flags it before it becomes a SEO regression in GSC.
Client deliverable
The same script + report shape lifts to any client engagement:
~/bin/dare_perf_trend.py --origin https://client-site.example.com- Drops the markdown into a per-client dev-reports surface
- Daily cron + 90-day trend = “your site got faster” / “your site got slower” — a load-bearing answer that ad agencies typically can’t produce with primary evidence
Cost to provide: $0 marginal (free Google API). Cost to client value: meaningful — most SMB sites don’t have any perf tracking discipline, so this becomes a continuous-improvement substrate they couldn’t produce themselves.
Methodology (for the record)
- Tool:
~/bin/dare_perf_trend.py(sibling at~/Code/dare-pipeline/scripts/dare_perf_trend.py) - Data source: Google PageSpeed Insights API v5 (
pagespeedonline.googleapis.com) - CrUX fallback: Chrome UX Report History API (
chromeuxreport.googleapis.com) — empty for all 6 surfaces today (sub-threshold Chrome traffic) - Auth: API key in
op://Code Shared/Google PSI API/api_key(restricted to PSI + CrUX APIs) - GCP project:
dare-seo-audit(the MASTER canonical; seeparked_sketch_gcp_consolidation_xlab_co_2026-05-20for the consolidation runbook) - Sample size: single PSI lab run per origin per device-type — synthetic + deterministic, suitable for trend tracking
- Capture window: 2026-05-20 ~4pm ET
- Cost: $0 (well within the 25k-queries-per-day free tier)
- Reproducibility: re-run
~/bin/dare_perf_trend.py --origin <URL>any time; results land in~/Downloads/dare_perf_trend_<slug>_<date>.{md,html,json}and auto-publish toreports.dare.co.ukcatalog
Sibling memories + cross-references
feedback_gcp_one_project_per_surface.md— the GCP consolidation principle the API key sits insideproject_gcp_consolidation_xlab_co_runbook.md— the runbook for retiring legacy projects when readyproject_dare_traffic_baseline.md— the traffic-volume side; pairs with this perf side as the two halves of “how is dare doing?”project_audrey_commerce_flywheel.md— Workstream B (Shopify-GitHub theme integration) is the lever for the audrey mobile-LCP fixparked_sketch_audreyinc_archive_plus_shopify_github_2026-05-20.md— the audrey workstream the perf data motivates
The aphorism
The first measurement is the baseline. The first 100 measurements are the trend. The first 1,000 are the truth. Today is day one — start the clock.