Why the migration was a high risk
I knew this was a high‑risk project. Full site migrations like this CMS change, front‑end change, design change are exactly where you see cases of 40–60% traffic loss when redirects, structure, and rendering aren’t planned properly.
For this client in particular, the risk profile looked like this:
1,246 indexable URLs across research, markets, regions, and reports.
Around 74,600 organic sessions/month and 1,420 organic conversions/month.
382 research articles, 146 market insight pages, 88 country/region pages, 41 report landing pages, and 63 gated asset pages.
74 redirect issues, 61 internal broken links, 18 canonical conflicts, 29 crawlability issues, and 14 metadata gaps on the legacy WordPress build.
If we got the migration wrong, we were realistically looking at a potential loss of tens of thousands of monthly organic sessions and hundreds of conversions.
The main risks I planned around were:
Losing rankings on high‑value research and country pages.
Breaking international visibility in key regions.
Orphaning hundreds of backlinks from industry publications and partners.
Deploying a Next JS front end that search engines couldn’t fully render.
Redesigning high‑intent pages in a way that changed or diluted search intent.
Losing attribution on report downloads and lead forms during the cutover.
Because organic search was driving roughly 65–70% of their inbound demand, I treated SEO as the main risk register for the project.
Baseline and planning: treating SEO as a risk register
Before we touched any code, I built a detailed quantitative baseline of the existing WordPress site and turned it into a migration risk register.
Content and URL inventory
I crawled the entire site and exported from WordPress, GA4, and Google Search Console:
1,246 indexable URLs.
1,182 URLs already indexed in Google.
74,600 average monthly organic sessions (3‑month average).
51,300 average monthly organic users.
1,420 average monthly organic conversions.
Top 250 landing pages by organic sessions.
Top 150 pages by assisted conversions.
420 core research/report URLs identified as strategically important.
Backlink data showing ~1,900 referring domains, with 240 URLs carrying significant link equity.
I also exported:
All existing title tags, meta descriptions, and canonical tags.
XML sitemaps and robots rules.
Existing hreflang or regional signals.
Risk scoring
I then scored each URL on:
Organic sessions (0–5).
Conversions (0–5).
Backlinks (0–5).
Regional importance (0–5).
Technical fragility (0–5).
That gave each page a risk score from 0–25. The distribution looked roughly like this:
Tier 1 (score 16–25) → 196 URLs (about 15.7% of the site)
These drove around 58% of organic traffic and 71% of organic conversions.Tier 2 (score 8–15) → 428 URLs (about 34.3% of the site)
These accounted for roughly 28% of organic traffic and 20% of conversions.Tier 3 (score 0–7) → 622 URLs (about 50% of the site)
These produced only about 14% of organic traffic and less than 9% of conversions.
This risk register became the backbone of the migration plan and dictated where I put the most attention and QA.
Choosing the new architecture: Next Js + Contentful
The client’s requirements were clear:
Faster delivery of dense research pages globally.
More flexible layouts for charts, datasets, and long‑form analysis.
Structured, reusable content models for research, markets, and countries.
Better editorial workflows for a team of 12+ analysts and editors across time zones.
I recommended:
Next JS as the front end, so we could control performance and interactivity.
Contentful as the headless CMS to model content types (reports, markets, regions, datasets) properly.
From an SEO perspective, I made a few non‑negotiable decisions:
Use SSR/SSG (server‑side rendering or static generation) for all Tier 1 and Tier 2 landing pages so Google and other engines see complete HTML.
Preserve the existing URL structure for at least 80–90% of Tier 1 URLs to minimize “stress” on rankings.
Mirror critical SEO fields from WordPress into Contentful models: titles, slugs, summaries, canonical slugs, categories, and market/region tags.
I explicitly ruled out a pure SPA approach for SEO‑critical content. For a site with 1,200+ URLs, relying on client‑side rendering alone would have significantly increased crawl and rendering r
Phase 1: Content pruning and IA redesign without traffic drop
Rather than “starting fresh,” I used the numbers from the risk register to prune safely.
What I pruned
From the 622 Tier 3 pages, I identified:
90 outdated reports with <10 organic sessions/month and no backlinks.
60 low‑value news posts with zero organic traffic over 12 months.
40 thin glossary/definition pages that duplicated stronger, more authoritative content.
25 duplicated or near‑duplicate market updates targeting the same keywords.
In total, I marked around 215 URLs for consolidation or retirement, which reduced the live indexable URL count target from 1,246 to around 1,030–1,050 after migration.
For each candidate, I checked:
12‑month organic sessions (0–5 visits/month).
Any backlinks (most had 0 referring domains).
Conversions (most had none).
Overlap with existing Tier 1/Tier 2 pages.
Anything with meaningful traffic or links was never hard‑deleted. Instead, it was redirected into a stronger canonical page, often a topic hub.
IA changes with numbers
We re‑organised the content into clear, measurable structures:
Research hub pages: 12 core hubs (Upstream, Midstream, LNG, Energy Transition).
Market sections: 18 commodity/segment markets (Brent, WTI, Natural Gas).
Country/region pages: 72 active countries and 16 broader regional aggregates.
Reports: 41 main report landing pages, all mapped to Contentful content types.
This reduced “flat” navigation and clarified where each of the 1,000+ resulting URLs belonged in the overall structure.
Phase 2: SEO migration design — making risk mitigation the centerpiece
I then designed the migration itself around industry best practice for large WordPress site moves.
1. URL mapping and redirect strategy
The redirect map became a single source of truth. It contained:
All 1,246 original WordPress URLs.
A mapped target for each, with:
Status: migrated / consolidated / retired.
New Next JS/Contentful URL.
Risk tier (1–3).
Redirect type (301).
Final numbers:
Approx. 860 URLs retained their existing URL paths (or extremely close variants).
170 URLs had controlled path changes (updated to more logical/hierarchical slugs).
215 URLs were consolidated/retired with redirects to hubs or updated reports.
On the technical side:
We implemented 312 direct 301 redirects where URLs changed or content was consolidated.
We cleaned up 41 legacy redirect chains, flattening them into direct old→new mappings.
We verified the absence of redirect loops and ensured 0 endpoints returned 302 for permanent moves.
Given that misconfigured redirects are one of the top causes of migration traffic loss, these numbers were critical for me.
2. Metadata, canonicals, schema
For Tier 1 and Tier 2 URLs (around 624 pages):
100% of title tags were preserved or improved.
100% of meta descriptions were set eliminating the 14 missing/weak entries from WordPress.
All 18 canonical conflicts were corrected so each canonical referred to the final, canonical Next JS URL.
I re‑implemented or refined schema on 80 key report/research pages where structured data made sense.
This ensured that the signals search engines had learned over years were not lost in the redesign.
3. International & regional signals
For the 88 country/region pages:
Each got a dedicated Next JS route (no collapsing or random merging).
We maintained region‑specific page titles and content.
We documented hreflang plans for future enhancements and ensured that no country page was silently demoted or removed.
This mattered because country and region pages together were responsible for roughly 22–25% of organic sessions.
Phase 3: Contentful build and SEO‑first implementation
While the dev team built the Next JS front end, I stayed embedded to keep the implementation aligned with our SEO plan.
Technical choices with numbers
All Tier 1 and Tier 2 pages (624 URLs) were implemented as SSR/SSG routes.
Only lower‑risk Tier 3 pages (400 URLs after pruning) used simpler client‑side rendering patterns where appropriate (e.g., some tools or internal utilities).
For performance, we lowered the median LCP on key templates from 3.8–4.2 seconds on WordPress to a target of <2.5 seconds in Next JS, based on staging tests.
In Contentful, I worked with the client’s content team to:
Create 6 main content models (Report, Article, Market, Country, Dataset, Landing Page).
Enforce SEO fields as required on 100% of Report and Article entries.
Migrate around 650 core content entries (Tier 1 and Tier 2) with full SEO data.
Phase 4: Pre‑launch SEO quality assurance live vs staging comparison
Once the build hit “feature complete,” I ran a full SEO QA on staging.
Coverage and parity
For the 196 Tier 1 URLs and 428 Tier 2 URLs:
100% existed in staging with their new Next JS templates.
100% of Tier 1 and >95% of Tier 2 had content parity within acceptable bounds (same or better copy, headings, and assets).
Issues I caught and fixed on staging:
11 pages missing meta descriptions.
7 pages with incorrect canonical targets.
6 internal links pointing to old WordPress paths.
3 report templates where the main content block did not render under JS‑off tests.
2 pages with schema that needed updating to match the new structure.
I also validated that staging remained fully blocked from indexing, avoiding any risk of duplicate URLs being picked up early.
Phase 5: Controlled go‑live and immediate risk checks
When we were confident, we executed a controlled go‑live.
Launch with measurements
On launch day:
I ran a final crawl of the WordPress site (all 1,246 URLs with status codes and metadata).
We deployed the Next JS + Contentful site.
We applied the 312 301 redirects and verified a sample of 100+ old URLs behaved correctly.
We checked that robots.txt was open for the new site, and no indexable templates shipped with a noindex tag.
We refreshed XML sitemaps to include 1,030–1,050 final URLs, then submitted in GSC.
We validated GA4 and key events:
Report downloads.
Trials/subscription requests.
Contact/demo forms.
At this point, the starting line for monitoring was:
Organic: 74,600 sessions/month, 51,300 users/month, 1,420 conversions/month.
Indexation: 1,182 URLs in Google.
Issues: WordPress issues resolved; Next JS site launched clean.
Phase 6: Planning for traffic drop and 90‑day recovery
I assumed some volatility; the question was how much, how long, and where.
KPIs and thresholds
I set explicit thresholds:
Sitewide: A sustained drop of more than 15–20% over 4+ weeks would trigger deeper intervention.
Section‑level (regions, markets, reports): A sustained drop of more than 25% in a section’s organic sessions or conversions would trigger investigation and remedial actions.
Dashboards tracked:
Organic sessions and users by:
Sitewide.
Section (Research, Markets, Countries, Reports).
Region grouping.
Rankings for 150 priority keywords and 40 high‑value keyword clusters.
Coverage/indexation for the final 1,030–1,050 URLs.
404 errors and redirect hits.
Conversion rates per section.
Core Web Vitals metrics across templates.
Recovery
If thresholds were hit, my plan included:
Checking redirect and canonical integrity for affected groups.
Verifying content parity and search intent alignment.
Adding or improving internal links from high‑authority hubs.
Enhancing affected pages with additional data, FAQs, or related content if warranted.
Using GSC URL Inspection and Performance reports to identify whether impressions and queries had shifted.
This way, if there was a problem at week 4 or week 6, we weren’t improvising; we were executing a predefined playbook.
Phase 7: 90‑day post‑launch monitoring — what actually happened
Days 1–30: Mild volatility
In the first 30 days after launch:
Organic sessions averaged 72,900 (2.3% below the 74,600 baseline).
Organic users averaged 50,100 (2.3% down from 51,300).
Organic conversions averaged 1,388 (2.3% down from 1,420).
Core Web Vitals pass rate jumped from 38% to 71% on key templates.
Average load time for long research pages improved from around 5.6 seconds to 3.1 seconds.
This was exactly in the “small acceptable dip” range I had projected.
During this period, I:
Fixed 8 unexpected 404s from obscure legacy URLs.
Adjusted 3 redirect targets to more relevant destinations.
Added internal links into 20 underperforming articles from stronger hubs.
Days 31–60: Stabilisation and small uplift
By days 31–60:
Organic sessions averaged around 75,800, slightly above the original 74,600 baseline.
Organic conversions averaged 1,460–1,480, roughly 2–4% up from 1,420.
Engagement metrics (time on page, scroll depth) improved on several key report templates.
The section‑level view showed:
Research hub traffic up by 5–7%.
Country/region pages roughly flat (±2% around baseline).
Long‑tail legacy posts fluctuating more, but within acceptable noise.
No section hit the 25% drop threshold that would have triggered heavy remediation.
Days 61–90: Consolidated growth
By days 61–90:
Organic sessions averaged 78,400 per month (5.1% above the 74,600 baseline).
Organic users grew to 54,600 (6.4% increase).
Organic conversions rose to an average of 1,534 per month (8.0% increase).
Indexed URLs settled around 1,214, comfortably close to the final target range.
Core Web Vitals pass rate stabilised around 88% on the main templates.
Average load time for research pages dropped further to 2.8 seconds.
By the 90‑day mark, we weren’t just “recovered” we were clearly ahead of where we started, with better performance, cleaner structure, and more stable rankings.
What this means for future clients
From my perspective, the most important part of this project wasn’t the technology stack; it was the planning and risk management:
I treated the migration as an SEO risk register first, a redesign second.
I audited and scored all 1,246 URLs before making changes.
I used a detailed 1:1 redirect map with 312 301s and zero redirect chains in the final state.
I designed the Next JS and Contentful architecture so that 624 high‑ and medium‑risk pages were server‑rendered and fully crawlable.
I assumed some traffic volatility, set numeric thresholds, and monitored performance daily for 90 days.
The result is that the client moved from an aging WordPress monolith to a modern Next JS + headless CMS stack without suffering a significant traffic drop, and with measurable gains by the end of the first quarter post‑launch.


