Performance engineering
Faster for your customers, not for the testing tool you ran
We work from field data: what your real visitors experience on their own devices and connections, per template, at the 75th percentile where the published thresholds are actually assessed.
That usually leads somewhere unwelcome. The largest cost on most ecommerce pages is the third-party scripts nobody is allowed to question, so we cost each one in milliseconds and let you make the trade with numbers in front of you.
- Judged on real visitors, not a simulated load
- A budget in place before we leave
The problem
Why speed projects stall
Most stores have already had a go at this. A plugin was installed, a score went up, and nothing changed for customers. Four reasons, and the first one accounts for most of the wasted effort.
Optimising the test instead of the store
A lab tool run on the homepage, from one location, on a fast connection. The number improves and the people on mid-range phones on mobile networks never notice.
A score treated as the goal
Effort spent moving a composite number that no customer experiences, while the metric that actually tracks their experience sits untouched.
Third-party scripts declared out of scope
The theme gets refactored to perfection around a tag manager loading eleven vendors. The largest cost on the page was the one nobody was allowed to question.
Gains that quietly reverse
Six months later an app, a hero video and a new consent banner have arrived, and the store is back where it started because nothing was watching.
We work from what your actual visitors experience, on the hardware and connections they actually use, and treat a page-weight budget as something you keep rather than something you achieve once.
Which numbers actually count
There is no shortage of performance metrics and most of them are diagnostic rather than meaningful. Three are the ones Google publishes as Core Web Vitals, and they are the three worth holding a store to, because they correspond to things a customer can feel: how long until the page looks ready, how long until it answers a tap, and whether it moves under their thumb.
| Metric | Good | What a customer experiences |
|---|---|---|
| LCP, Largest Contentful Paint | 2.5 seconds or less | How long before the product image and price are actually there to look at |
| INP, Interaction to Next Paint | 200 milliseconds or less | Whether tapping a size, a filter or add-to-cart responds or appears ignored |
| CLS, Cumulative Layout Shift | 0.1 or less | Whether the button moves as they reach it, which is how people add the wrong variant |
Two details in how those are assessed change the work more than the thresholds themselves. They are measured at the 75th percentile, not the average, which means the target is the experience of your slower quarter rather than your typical visitor. And they are segmented across mobile and desktop, so a store can pass comfortably on desktop and fail on the devices most of its customers use.
One correction worth making, because it is still in a lot of documentation and a lot of proposals. First Input Delay is retired. INP replaced it as a stable Core Web Vital in 2024, and it is a much harder metric to pass: FID measured only the delay before processing started, while INP measures the whole way through to the next paint. Stores that comfortably passed FID routinely fail INP, and nothing about them changed.
Why your score and your customers disagree
The most common confusion in this work is between two kinds of data that look interchangeable and are not. Lab data comes from a simulated load: one page, one device profile, one location, no cookies, no consent state, nobody logged in. Field data comes from real visitors on real devices doing real things.
Both are useful and they answer different questions. Lab data is reproducible, which makes it the right tool for diagnosis and for comparing a change against the version before it. Field data is what Core Web Vitals are actually assessed on, which makes it the only thing that tells you whether the store is passing.
They disagree for reasons that are entirely predictable once you look. A lab run does not have a consent banner in the state a real visitor triggers. It does not carry a cart, or a logged-in session, or a personalisation script deciding what to render. It runs one URL, while your traffic is spread across templates with very different weights. And it runs on a simulated mid-tier device, which is a guess at the median handset rather than a measurement of yours.
So the working rule here is simple: field data decides whether there is a problem and whether it is fixed, and lab data is how we find out why. A report that only contains lab numbers is a report about a page that nobody visited.
What we build
What the work covers
Measurement first
- Field data as the verdict, per template and split by device, because a store can pass on desktop and fail where its customers are
- Lab profiling as the diagnosis, run on real device profiles and throttled connections rather than on a fast desktop
- The 75th percentile as the target, which is the slower quarter of your traffic rather than the comfortable middle
The third-party layer
- Every tag costed individually in milliseconds, so removing one becomes a commercial decision with a number attached
- Tag manager audited for what is still firing, which is reliably more than anyone expects
- Consent and personalisation scripts examined specifically, since both run early and block what a customer sees
The store itself
- Images sized, formatted and prioritised, with the one that matters on a product page never lazily loaded
- Render-blocking work in the head removed or deferred, and JavaScript scoped to the templates that need it
- Liquid and PHP refactored where a template is doing work per request that it could do once
Keeping it
- A written budget in numbers: JavaScript per template, image weight, permitted third-party origins
- A check that runs on the templates that matter and reports when the budget is exceeded
- A verdict route for new apps, so the next install is a question with an answer rather than a surprise
Where the time actually goes on a store
After the measurement, the causes are unglamorously consistent. Ecommerce stores are slow for a small number of reasons, and they are rarely the ones a redesign proposal is built around.
- Third-party scripts: analytics, chat, reviews, personalisation, consent, and a tag manager that has become a place things get added to and never removed from
- Images: too large, wrong format, and the one that matters most on a product page loaded lazily when it should not be
- Render-blocking work in the head, which delays everything the customer sees regardless of how fast the rest is
- JavaScript that runs on every page whether or not that page needs it, which is where INP is usually lost
- Server response, which on WordPress is uncacheable cart and checkout traffic, and on Shopify is usually a theme doing too much work per request
The first item is normally the largest and is the one most often ruled out of scope before the work starts. Each of those tools was bought by somebody, and questioning them is a commercial conversation rather than a technical one. We cost them individually in milliseconds so that the conversation can happen with numbers in it, because the alternative is refactoring a theme to perfection around eleven vendors nobody has audited since they were installed.
On WooCommerce the server side deserves its own attention, since cart, checkout and account pages cannot be cached and therefore hit PHP and the database every single time. That is a different problem from a slow theme and it is covered properly on our WooCommerce page.
How it runs
How the work runs
Measure, attribute, change one thing at a time, then leave something that notices when it reverses.
- 1
Baseline from real visitors
Field data per template, split by device, established before anything is touched. Without a baseline every subsequent claim is an assertion, including ours.
- Field data per template, not site-wide
- Mobile and desktop assessed separately
- The 75th percentile as the target, not the average
- 2
Attribute the cost
Lab profiling to find out where the time goes, with every third-party tag costed individually so the expensive ones can be discussed as the commercial decisions they are.
- Each tag costed in milliseconds
- Blocking work in the head identified
- Findings ordered by cost, not by ease
- 3
Change, one at a time
Applied in order of cost, on staging, measured after each. Bundling changes makes a regression impossible to attribute, and something always regresses.
- One change per measurement
- Nothing tried first on the live store
- Each change independently reversible
- 4
Budget and handover
Field data re-read after the change has been live long enough to be real, then a written budget and an automated check handed over, so the next app install meets a number rather than an opinion.
- Verified on field data, not on a lab rerun
- Budget written in numbers
- A check in place before we leave
What we will not promise you
This category is sold on two claims that we will not make, and it is worth saying which and why before any work is agreed.
The first is a score. A composite performance score is a diagnostic summary, weighted by whoever built the tool, and it is not a thing your customers experience. It is also trivially gameable in ways that do not help anybody: defer enough, lazy-load enough, and the number improves while the page feels worse. We report against the published thresholds instead, on field data, per template, because those correspond to something real.
The second is revenue per millisecond. You will have seen the studies, and they are real studies of other people’s stores, with other catalogues, other customers and other baselines. Applying somebody else’s elasticity to your store produces a forecast with the shape of evidence and none of the substance. If you want to know what speed is worth on your store specifically, that is measurable, and it is an experiment rather than a citation: ship the change to half your traffic and read the difference. That is A/B test development, and it is the only honest way to get the number.
What we will commit to is the part that is actually within an engineer’s control: measuring what your visitors experience rather than what a lab reports, naming what each cost is buying you so the trade is yours to make, and leaving a budget in place so the gains do not quietly reverse.
Staying fast after we leave
A performance engagement that ends with a fast store and no mechanism has bought you about six months. Stores regress for entirely ordinary reasons: an app is installed, a campaign adds a hero video, a new consent tool arrives, somebody adds a font.
So the last piece of work is always the same. A budget written down in numbers rather than intentions: how much JavaScript a template may load, how heavy the hero image may be, how many third-party origins are allowed. Then a check that runs on the templates that matter and tells somebody when the budget is exceeded, while the change is still fresh enough to be reversed cheaply.
It is unglamorous, and it is the difference between a project and a change. It also converts every future app decision into a question with an answer, which is worth more than the initial fix on most stores.
Where this sits
This is speed bought on its own, on a store you already have, and it is deliberately the cheap answer to several questions that get asked expensively.
It sits under Shopify development and applies equally to WordPress, since the measurement is identical and only the causes differ. If you have been told the fix is a rebuild, headless commerce is where we argue that speed is usually the weakest reason to change architecture. And if the goal behind the speed goal was conversion, a store audit often finds larger friction than a second of load time.
The answers to your questions.
Largest Contentful Paint at 2.5 seconds or less, Interaction to Next Paint at 200 milliseconds or less, and Cumulative Layout Shift at 0.1 or less. Two things about how they are assessed matter as much as the numbers: they are measured at the 75th percentile rather than the average, so the target is your slower quarter of visitors, and they are segmented across mobile and desktop, which is why a store can pass comfortably on desktop while failing on the devices most of its customers actually use.
No. FID is retired, and Interaction to Next Paint replaced it as a stable Core Web Vital in 2024. This matters more than a name change: FID only measured the delay before the browser began processing an interaction, while INP measures the whole way through to the next paint. Stores that passed FID comfortably routinely fail INP without anything about them having changed. If a proposal you have been sent still talks about FID, it was written against a standard that no longer applies.
Because they are different kinds of data. A lab test simulates one page load on one device profile from one location, with no consent state, no cart and nobody logged in. Core Web Vitals are assessed on field data from your real visitors across real templates and devices. Both are useful for different jobs: field data decides whether you have a problem and whether it is fixed, lab data is how you find out why. A report containing only lab numbers is a report about a page nobody visited.
Usually to a point, and it is worth knowing where that point is before agreeing scope. Third-party scripts are typically the single largest cost on an ecommerce page, and a theme refactored to perfection around eleven vendors will still be slow. We cost each tag individually in milliseconds so it becomes a commercial decision with a number attached rather than a technical argument. Plenty of them turn out to be duplicated, dormant or firing on templates that never needed them, and those come out with no loss at all.
We will not give you that number, and be careful with anyone who does. The published studies are real studies of other people’s stores with other catalogues, customers and baselines, and applying someone else’s elasticity to yours produces a forecast with the shape of evidence and none of the substance. What speed is worth on your store is genuinely measurable, but it is an experiment rather than a citation: ship the change to half your traffic and read the difference.
With a budget and a check, which is the part most engagements skip. Stores regress for ordinary reasons: an app is installed, a campaign adds a hero video, a consent tool arrives, someone adds a font. So the work ends with numbers written down, how much JavaScript a template may load, how heavy the hero may be, how many third-party origins are allowed, and an automated check that reports when they are exceeded while the change is still fresh enough to reverse cheaply.
Passing the test and still feeling slow?
Tell us the store, the platform and which template matters most commercially. We will read what your real visitors are getting and say what is actually costing you the time.
Get the real numbers read ↗