Four 100s on PageSpeed, and exactly what it took

Google PageSpeed Insights gives this site 100 for performance, accessibility, best practices and SEO, on desktop and mobile. Rather than post the screenshot and leave it there, here is every change that got it there.

A row of glass plates stepping down into the distance, like a loading waterfall

If you have worked in e-commerce you already know why this matters, and it is not mainly SEO. Page speed shows up in conversion rate, in bounce, in how many people reach the second page of a funnel at all. It is one of the few technical numbers that translates into revenue without an argument.

The most impressive thing we have seen in the wild was an e-commerce platform carrying roughly eight million products and serving a page in about seven tenths of a second. Five years ago the honest explanation for a result like that would have been a world-class engineering team and a budget to match. It is more achievable now - better defaults, better tooling, and a lot less hand-written glue - but it is still not free, and it is still made of dozens of small decisions rather than one clever trick.

So: PageSpeed Insights, four 100s, desktop and mobile. This is what is behind them.

Start by not shipping a framework

This site is static HTML with one stylesheet and one script. There is no client-side router, no hydration step, no component runtime. That decision is worth more than every optimisation below it combined, because the fastest JavaScript is the JavaScript that was never sent.

That is not an argument against frameworks in general - we build plenty of applications where one earns its place. It is an argument against reaching for one to render eleven marketing pages that do not change between deploys.

Nothing stands between the HTML and the first paint

The stylesheet is minified at build time and inlined into every page as a <style> element. A separate CSS file would be a second round trip before anything can be painted, and the sheet is small enough that the bytes cost less than the request. So the first response contains everything needed to render.

Montserrat is self-hosted as a variable woff2, Latin and Latin Extended, weights 400 to 800 in one file. No third-party font handshake, no DNS lookup to another origin before text can appear. Each page preloads the Latin subset.

Three things that used to run while the reader waited

This is where most of the measurable gain came from.

  • A WebGL shader. The glass effect behind the step cards on the home page compiles a fragment shader, and that blocked the main thread for most of a second. The section it decorates is well below the fold, so an IntersectionObserver now holds it until the reader is two viewports away.
  • Google Tag Manager. About 120 KB of third-party JavaScript that nothing on the page depends on. dataLayer is still created immediately, so no event is lost, but the container itself is fetched on the first interaction or once the browser goes idle after load, whichever comes first.
  • Step thumbnails. Roughly 590 KB of animated GIFs that are only ever visible on an open card. They carry their address in data-src and the script fills in src when a card opens. On a pointer device the whole row is warmed on hover, so the reveal still feels instant.

Images: the boring 400 KB

Large decorative images are AVIF with the original kept as a <picture> fallback, which is worth about 400 KB on the home page alone.

One trap worth passing on. A CSS background does not get the same treatment: it stays a plain url() in a format every browser reads. image-set() with type() only parses correctly from Safari 17 - older Safari accepts the declaration and then paints nothing at all. Every case-study hero background silently vanished for those visitors while looking perfect in Chrome. Our build now refuses to run if image-set( appears in the stylesheet. Content negotiation belongs in <picture>, where every browser has behaved correctly for a decade.

Two things we check before re-encoding anything:

  • What size is it actually rendered at? One product photo was a 3072 × 4096 original being displayed in a 624 × 680 box.
  • A gradient does not need resolution. The scrim over every case-study hero was 557 KB at 2880px. At 1440px as AVIF it is 8 KB and samples within three units of the original, because background-size: cover stretches it either way.

Every <img> carries explicit width and height, so nothing reflows as it loads - that is the layout-shift half of the score, and it is free. Plus loading="lazy" and decoding="async".

Video, which is where sites usually lose

There is a looping glass animation behind the hero. It is also the single heaviest thing on the page, so it is treated as optional.

The poster frame is painted by CSS as the section background, so the hero is never empty and the video is never part of the first paint. Each loop is encoded four ways - 1080p and 720p, each as H.264 and HEVC - and the script picks the smallest file that covers the rendered size, after checking whether the browser can decode HEVC. A phone never downloads a 1080p decorative background.

It is skipped entirely under prefers-reduced-motion or Save-Data, it waits for the load event, and anything below the fold waits until it is within a viewport of being seen. Open one of our pages halfway down and the hero video is never fetched at all.

Caching, which costs nothing to get right

A one-year immutable cache on static assets, no-cache on HTML, and compression on everything text-shaped. Asset URLs carry a version string, so a changed file is a changed URL and the long cache is never a lie.

The other three 100s are not performance

Accessibility, best practices and SEO are mostly discipline rather than engineering, and they are much cheaper to hold than to retrofit.

  • One h1 per page, sections are h2, cards are h3, and no section invents its own heading size to look important.
  • A skip link, real landmarks, aria-labelledby on every section, visible focus states, and contrast checked against the background each element actually sits on rather than the one it was designed against.
  • Canonical and hreflang on every page, in all three languages, each page declaring itself among its own alternates.
  • Structured data generated from the same source as the visible page, so the markup and the content cannot disagree. Our FAQ page and its FAQPage schema are rendered from one array; there is no second copy to forget to update.

What a score does not tell you

Worth saying plainly: PageSpeed is a lab measurement on a simulated device and connection. It is a good proxy and a genuinely useful checklist, but the number that matters is field data from real visitors on real networks. A perfect lab score with no field data behind it is a nice screenshot, not a finished job.

It is also not permanent. Add one third-party script, one unsized image, one webfont from someone else's CDN, and it is gone. The useful outcome is not the four 100s - it is having a build that makes the fast choice the default one, so the score survives the next person who edits the site.

And yes: when PageSpeed hands you four 100s, you take the screenshot before it changes its mind.