The situation
A B2B services client with 900 published pages on WordPress was stuck. Mobile LCP sat at 4.8 seconds, INP at 340ms, and the site ran 41 plugins — several of which had been installed years earlier for a campaign that ended. Core Web Vitals had been red for eleven consecutive months, and organic traffic had declined 12% year on year despite new content.
The publisher had tried plugin-based optimisation twice. Both attempts improved lab scores temporarily and neither moved field data.
Step one: a pre-launch baseline you can defend
Before touching anything we captured a complete baseline: a full crawl of all 900 URLs with status, canonical, word count and internal link count; Search Console performance export for the previous sixteen months; current rankings on 1,200 tracked keywords; and Core Web Vitals field data per template type.
This is the step that migrations skip and then regret. Without a baseline you cannot tell whether a traffic change after launch is a migration problem or normal fluctuation — and you will spend months guessing.
- 900 URLs crawled with status codes, canonicals and internal link counts.
- 16 months of Search Console query data exported.
- 1,200 tracked keywords with position history.
- Per-template CrUX data for the six main template types.
Step two: architecture decisions
We chose Next.js with static generation plus incremental revalidation for editorial content, and server rendering only for the search and account areas. Content moved to Sanity as a headless CMS so the editing experience stayed simple while the delivery layer became completely static.
Crucially, we preserved the URL structure exactly. Not one URL changed. The URLs were already clean, descriptive and hyphenated, and rewriting them would have added risk with no benefit.
Step three: the image pipeline
Images accounted for 68% of page weight — 3.4MB on the average page. We converted the archive to AVIF with WebP fallback, generated responsive variants, added explicit dimensions to every image, and moved originals to a CDN-backed object store.
That single change reduced average page weight from 3.4MB to 640KB and dropped LCP from 4.8s to 2.4s before any other work.
| Metric | Before | After images only | After all work |
|---|---|---|---|
| Average page weight | 3.4 MB | 640 KB | 410 KB |
| Mobile LCP (p75) | 4.8s | 2.4s | 1.3s |
| INP (p75) | 340ms | 296ms | 112ms |
| Total blocking time | 1,840ms | 780ms | 90ms |
Step four: the parts that were harder than expected
Three issues emerged that are worth knowing about in advance. First, the old site had 140 internal links pointing to URLs that had been redirected years earlier — a chain we had to flatten to prevent equity loss on every crawl.
Second, the plugin stack had injected schema markup into templates we did not migrate, so we had to rebuild structured data deliberately across all six template types rather than inheriting it.
Third, the search functionality depended on a WordPress plugin with no equivalent — we replaced it with Algolia, which turned out to be a significant user-experience improvement as well as a technical one.
The results after six months
There was no traffic dip. This is unusual and it came directly from preserving the URL structure and flattening redirect chains before launch.
Organic sessions grew 184% over six months as the recovered performance made previously stalled pages competitive. Twelve pages that had been on page two for over a year moved onto page one within eleven weeks of launch — pages whose content had not changed at all. The only variable was speed and indexation health.
- No organic traffic loss at any point post-launch.
- Mobile LCP 4.8s → 1.3s (-73%).
- INP 340ms → 112ms.
- Organic sessions +184% in six months.
- Indexed pages 74% → 98%.
- Hosting cost reduced 41% despite better performance.
Key takeaways
- Capture a full crawl, query and ranking baseline before any migration.
- Preserve URL structure unless there is a compelling reason to change it.
- Fix redirect chains and consolidate internal links before launching, not after.
- Image pipelines usually deliver the single largest performance gain available.

Bilal Ahmed
Head of Engineering
Oversees web and application development, with a focus on Next.js, TypeScript and performance engineering.
