← ALL FIELD NOTES

LOG 016 · TECHNICAL · 2023-03-01

Took the webapp's Lighthouse score from the 20s to 95 for an SEO push

2 min read

Situation

Goodpods is a podcast discovery and listening platform, and I worked on its Next.js webapp. The client wanted more organic search traffic, so they hired an SEO marketing team to audit the product. One of the audit’s requirements was a Core Web Vitals score over 90. At the time our Lighthouse score was 20 to 30, so we had to find ways to greatly optimise page load times.

Task

I took on the performance work on the webapp: getting the podcast, episode, leaderboard and profile pages fast enough to meet the score the SEO team required.

Action

I started with server-side rendering, where each page was awaiting its data fetches one after another. I changed the SSR code to queue the requests as promises and run them in parallel, a small change that gave a significant performance improvement across those page types.

Next I looked at who the fast path actually serves. Over 99% of our traffic was logged out, which is the same traffic search crawlers and new visitors generate. The pages were server-rendered, but the client was refetching the same data on load anyway. I reworked hydration so guest users are served entirely from the SSR payload with no client refetch, and only logged-in users refetch.

Then I cut what the browser had to download and run. I split code with dynamic imports so pages only load the JavaScript they actually need, and loaded AVIF versions of images first.

For the final stretch of tuning, preloads and script loading, I was strict about testing one change at a time. At one point I deliberately reverted a preload change I had just made so the next change could be measured on its own, rather than guessing which of two stacked changes moved the score.

Result

The Lighthouse score went from 20-30 to 95, clearing the SEO team’s target of 90. Our average search ranking improved from 25th to 18th, and we saw over 1000 click-throughs per week from organic search. Skipping the guest refetch also removed a redundant request from over 99% of page loads, saving a lot of load on the backend.