Under the hood

The proof is this page

Every agency says they build fast, accessible, well structured websites. Almost none of them publish the numbers for their own site. Here are mine, and here is how to check them yourself.

Measured against the live site on 7 October 2026.

100 Performance
100 Accessibility
100 Best Practices
100 SEO
36 ms Time to first byte
1.1 s First paint
1.9 s Largest paint
1.1 s Speed index
20 ms Blocking time
0.00 Layout shift
6 Requests to first render
10 KB First party JavaScript
2 Third party requests
2 Plugins installed
0 Page builders
AA WCAG conformance

The measurement history

Every run, including the bad ones

The numbers above are the current ones. These are all of them, in build order, going back to the first set this site ever published. 42 PageSpeed runs across 12 builds, mobile every time, with nothing left out for being unflattering.

Performance score for every recorded PageSpeed run, in build order The score starts at 83 on the first published run, moves between 85 and 99 across the next several builds, and sits at 100 on the most recent runs. Individual runs on the same build are plotted separately where more than one was taken. The full numbers are in the table below this chart. 75 80 85 90 95 100 90, where Google stops calling it green v1.6.0, 2026-09-02: performance 83 1.6.0 v1.7.0, 2026-09-02: performance 85 1.7.0 v1.7.1, 2026-09-02: performance 85 1.7.1 v1.7.2, 2026-09-02: performance 88 1.7.2 v1.8.0, 2026-09-02: performance 100 v1.8.0: Best Practices fell to 96 on this build 1.8.0 v1.8.1, 2026-09-02: performance 100 1.8.1 v1.10.1, 2026-09-02: performance 100 v1.10.1, 2026-09-02: performance 83 v1.10.1, 2026-09-02: performance 96 v1.10.1, 2026-09-02: performance 99 v1.10.1: median of 4 runs 1.10.1 v1.17.0, 2026-09-28: performance 79 v1.17.0, 2026-09-28: performance 83 (2 runs scored this) v1.17.0, 2026-09-28: performance 83 (2 runs scored this) v1.17.0, 2026-09-28: performance 85 (3 runs scored this) v1.17.0, 2026-09-28: performance 85 (3 runs scored this) v1.17.0, 2026-09-28: performance 85 (3 runs scored this) v1.17.0, 2026-09-28: performance 86 v1.17.0, 2026-09-28: performance 98 v1.17.0: median of 8 runs 1.17.0 v1.18.0, 2026-09-28: performance 83 v1.18.0, 2026-09-28: performance 85 v1.18.0, 2026-09-28: performance 98 v1.18.0, 2026-09-28: performance 100 (3 runs scored this) v1.18.0, 2026-09-28: performance 100 (3 runs scored this) v1.18.0, 2026-09-28: performance 100 (3 runs scored this) v1.18.0: median of 6 runs 1.18.0 v1.25.0, 2026-10-07: performance 100 (4 runs scored this) v1.25.0, 2026-10-07: performance 100 (4 runs scored this) v1.25.0, 2026-10-07: performance 100 (4 runs scored this) v1.25.0, 2026-10-07: performance 100 (4 runs scored this) v1.25.0: median of 4 runs 1.25.0 v1.31.1, 2026-10-10: performance 100 1.31.1 v1.32.2, 2026-10-11: performance 84 v1.32.2, 2026-10-11: performance 99 (5 runs scored this) v1.32.2, 2026-10-11: performance 99 (5 runs scored this) v1.32.2, 2026-10-11: performance 99 (5 runs scored this) v1.32.2, 2026-10-11: performance 99 (5 runs scored this) v1.32.2, 2026-10-11: performance 99 (5 runs scored this) v1.32.2, 2026-10-11: performance 100 (7 runs scored this) v1.32.2, 2026-10-11: performance 100 (7 runs scored this) v1.32.2, 2026-10-11: performance 100 (7 runs scored this) v1.32.2, 2026-10-11: performance 100 (7 runs scored this) v1.32.2, 2026-10-11: performance 100 (7 runs scored this) v1.32.2, 2026-10-11: performance 100 (7 runs scored this) v1.32.2, 2026-10-11: performance 100 (7 runs scored this) v1.32.2: median of 13 runs 1.32.2 2026-09-02 2026-10-11
One PageSpeed run Median where a build was run more than once Best Practices 96, the broken build Performance score, mobile. The scale starts at 75. Runs that scored the same on one build are spread sideways so they can be counted. Scroll the chart sideways to see all of it.
Largest paint and first paint, in seconds, for every build where both were recorded Largest paint sits at 3.9 seconds across the first four builds, drops to 1.9 once the cause was found, rises to 4.0 on one later set of runs, and reaches 1.6 on the most recent. First paint drops from 2.3 to around 1.1 early and stays there. The full numbers are in the table below this chart. 0s 1s 2s 3s 4s v1.6.0: largest paint 3.9 s v1.7.0: largest paint 3.9 s v1.7.1: largest paint 3.9 s v1.7.2: largest paint 3.9 s v1.8.0: largest paint 1.9 s v1.8.1: largest paint 1.9 s v1.17.0: largest paint 4 s v1.18.0: largest paint 1.9 s v1.25.0: largest paint 1.9 s v1.31.1: largest paint 1.6 s v1.32.2: largest paint 1.89 s Largest paint v1.6.0: first paint 2.3 s v1.7.0: first paint 1.1 s v1.7.1: first paint 1.3 s v1.7.2: first paint 1.1 s v1.8.0: first paint 1.1 s v1.8.1: first paint 1.1 s v1.17.0: first paint 1.1 s v1.18.0: first paint 1.1 s v1.25.0: first paint 1.1 s v1.31.1: first paint 0.9 s v1.32.2: first paint 1.06 s First paint 1.6.0 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.10.1 1.17.0 1.18.0 1.25.0 1.31.1 1.32.2
Largest paint First paint Seconds, mobile. A break in a line is a build where that figure was not recorded. Scroll the chart sideways to see all of it.

Two things on that first chart are worth saying out loud, because they are the reason it is here rather than a flat line.

The cluster of runs on one build, all different, is the same site measured four times in five minutes with nothing changed between them: 100, then 83, then 96, then 99. Same bytes, same stylesheet, same script, verified rather than assumed. A single PageSpeed run is a sample, not a measurement, and anybody who tells you their score without telling you how many times they ran it is quoting their best one.

The dip in Best Practices is a build that shipped a closing script tag inside a comment, which dumped code onto the page as visible text. The Performance score that day was 100. The audit that caught it was the one nobody brags about.

Every figure as a table, including the source for each run
PageSpeed Insights, mobile, every recorded run in build order
Build Date Perf A11y BP SEO FCP LCP SI Runs taken
1.6.0 2026-09-02 83 100 100 100 2.3 s 3.9 s 4.6 s 1
First real scores published. The weakest numbers this site has ever shown, published on purpose on launch day. The placeholder scores that shipped before this were removed rather than guessed at.
1.7.0 2026-09-02 85 100 100 100 1.1 s 3.9 s 4.5 s 1
Above the fold reveal animation removed. Aimed at the largest paint. It fixed the first paint instead, from 2.3s to 1.1s, and left the largest paint exactly where it was.
1.7.1 2026-09-02 85 100 100 100 1.3 s 3.9 s 4.3 s 1
Grain overlay replaced with a 1.4 KB tile. Also aimed at the largest paint. Moved the speed index instead. Second theory, second miss.
1.7.2 2026-09-02 88 100 100 100 1.1 s 3.9 s 2.7 s 1
Published figures corrected. Speed index halved. The largest paint had still not moved at all across three builds.
1.8.0 2026-09-02 100 100 96 100 1.1 s 1.9 s 1.4 s 1
Analytics moved off the critical path. The first 100, and it was not real. This build shipped a closing script tag inside a comment, which dumped script onto the page as visible text. Best Practices caught it at 96. PageSpeed's own screenshot is what made it visible, not any test here.
1.8.1 2026-09-02 100 100 100 100 1.1 s 1.9 s 1.1 s 1
The bug 1.8.0 shipped, fixed. The real first 100. The cause of the largest paint was named by PageSpeed's own diagnostics panel, not by any of the three theories tried before it: the analytics tag was the only long task on the main thread.
1.10.1 2026-09-02 97.5 100 100 100 not recorded not recorded not recorded 100, 83, 96, 99
Four runs on identical bytes. Nothing on the site changed between the 100 and the 83. Same bytes, same stylesheet, same script, verified rather than assumed. A single PageSpeed run is a sample, not a measurement.
1.17.0 2026-09-28 85 100 100 100 1.1 s 4 s 4.5 s 79, 83, 83, 85, 85, 85, 86, 98
Eight runs, before the headline fix. The slow runs were clean and identical except in two figures: largest paint and speed index, moving together by about 2.5 seconds. First paint, blocking time and layout shift were the same every time.
1.18.0 2026-09-28 99 100 100 100 1.1 s 1.9 s 1.2 s 83, 85, 98, 100, 100, 100
Headline reveal moved from script to CSS. The largest text on the page did not exist visually until a script had been fetched, parsed and run. It is a pure CSS animation now, starting when the stylesheet parses.
1.25.0 2026-10-07 100 100 100 100 1.1 s 1.9 s 1.1 s 100, 100, 100, 100
Four runs inside five minutes, all 100. Four runs inside five minutes, all 100. At this point the slow runs had not reproduced since 1.18.0, and what had been treated as a property of the site looked like a property of the measurement. One did reproduce on 11 October, once in thirteen runs. See the last row: that is what run to run variance looks like, not a second mode.
1.31.1 2026-10-10 100 100 100 100 0.9 s 1.6 s not recorded 1
Industries, trades and the navigation dropdown. Two new pages, a navigation dropdown and roughly two kilobytes more script, and both paint figures came back faster than the ones published.
1.32.2 2026-10-11 100 100 100 100 1.1 s 1.9 s 1.1 s 84, 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100
Thirteen runs, after one of them came back at 84. A single run came back at 84 with a largest paint of 4.02 seconds, which is the signature this site chased for a month in September. Twelve more runs were taken immediately, through the API rather than by hand, and the largest paint moved a total of 28 milliseconds across all twelve. One run in thirteen. The metrics here are the medians of the twelve, and the 84 is the lowest dot on this build.

How to verify this yourself

Do not take my word for it

Run this page through Google PageSpeed Insights. It takes about thirty seconds, and it is the same tool on the same mobile setting the scores above came from. It runs on Google's machines rather than mine, so you get the numbers I got instead of the numbers a fast laptop on good wifi can produce. Chrome's own Lighthouse tab, under F12, checks the same things locally.

Then do it on the site of every other agency you are considering. That comparison will tell you more than any portfolio page, because a portfolio shows you what somebody else paid for and this shows you what they build when it is their own money and reputation.

I did exactly that, at scale, and published the result. I measured 1,137 agency websites through the same tool on the same morning. Not one of them scored 100 across all four categories, and the median scored 58. The raw data and the scripts are attached to that page, so you can check the arithmetic rather than take the number.

While the panel is open, look at the Network tab and count the requests. Then look at the Elements tab, right click the page and choose View Source rather than Inspect. What you see there is what a crawler sees. On a lot of modern marketing sites, that view is nearly empty.

What the numbers come from

Six decisions, each with a cost

No page builder

This site runs a theme written specifically for it. No Elementor, no Divi, no WPBakery, no parent theme, no framework. The CSS that loads is the CSS this site uses.

Two plugins

Gravity Forms for the contact form, and FluentSMTP so those notifications reach an inbox rather than a spam folder. That is the entire list. Analytics, SEO, schema, sitemaps, redirects and image handling all live in the theme, because a plugin for each is how a WordPress site ends up at four megabytes.

No JavaScript framework

No React, no Vue, no jQuery. The whole site ships one small script that handles the menu, the scroll behavior and the table of contents. Everything works with JavaScript disabled.

One third party request

Google Analytics, and that is the complete list. The typefaces are served from this domain rather than from Google Fonts, which removes a DNS lookup, a TLS handshake and a dependency on somebody else staying up. Most marketing sites make twenty to fifty third party requests. Open the network tab on the last few you visited and count.

Server rendered HTML

Every word on this site is in the HTML the server sends. Nothing is injected by script. That matters for search crawlers and it matters more for AI crawlers, most of which do not run JavaScript at all.

A connected schema graph

Structured data as one graph where the entities reference each other, rather than four disconnected snippets from four different plugins contradicting one another.

WCAG AA

Every color pair on this site clears AA contrast at the size it is used. Focus states are visible, headings are in order, and all motion respects the reduced motion setting.

The trade off

What this costs you

A hand built theme means you cannot drag a new section onto a page yourself. That is the genuine downside and it is worth being clear about it.

In exchange you get a site that loads in well under a second, cannot be visually broken by accident, has no license renewals attached to it, and can be handed to any competent developer years from now and understood.

For a business whose website needs to work rather than needs to be constantly rearranged, that trade is worth making. If it is not the right trade for you, that is useful to know before we start rather than after.

Start here

Tell me what you are trying to fix

Send over the site you have now, or the one you wish you had. I will tell you honestly whether I am the right person for it.

info@palmprojects.com