← All articles

[ Blog ]

July 9, 2026

9 min read

PageSpeed Insights API 429 Fix (Get Credible Scores)

Anonymous PageSpeed Insights API always returns 429? Here's the fix — how to get accurate, citable before/after Lighthouse scores for a redesign pitch.

PerformancePageSpeedLighthouseCore Web VitalsMeasurement
PageSpeed Insights API 429 Fix (Get Credible Scores)

If you've been calling the PageSpeed Insights API anonymously and it always returns 429, you're not doing anything wrong — you've just hit a quota that was never designed for what you're using it for. I ran into this while trying to build the single most useful slide in any redesign pitch: a real, citable before/after performance number. The anonymous API rate-limited me into nothing, and my backup plan — running Lighthouse locally — gave me numbers that swung so hard I couldn't trust them either. Here's what was actually happening, and the fix that finally produced scores I could put in front of a client without flinching.

Why the PageSpeed Insights API always returns 429

The instinct when you get rate-limited is to assume it's a per-day, per-key quota you've burned through. It isn't, if you're calling it anonymously (no API key, or a key with no billing set up). The PSI API's free tier quota is shared globally across every anonymous caller, not allocated per user or per day. You're not competing with your own request history — you're competing with every script, cron job, and CI pipeline on the internet hitting the same public endpoint. On a bad hour, the pool is already exhausted before your first request lands. Getting a key from Google Cloud Console raises your ceiling, but it doesn't fix the underlying problem: an API response is still just a JSON blob of numbers. It has no visual weight in a pitch deck, and a client can't independently re-run it in thirty seconds to check your math. Even a working API call is the wrong tool for this particular job.

Why local npx lighthouse gives a different score every run

So I dropped the API and ran Lighthouse locally instead:

npx lighthouse https://example.com --view

First run: Performance 66. Second run, same URL, nothing changed: Performance 91. Third run: 98. Same page, same code, three wildly different verdicts. This isn't a bug — it's what Lighthouse is designed to do when you point it at your own laptop.

Local Lighthouse throttles the page through your machine's actual CPU and network stack to simulate a mid-tier mobile device. That means your score is a function of whatever else your machine happens to be doing at that instant — Chrome tabs, Slack indexing in the background, a Docker container spinning up, your Wi-Fi hiccuping for two seconds. The throttling model applies a multiplier on top of your real hardware, so any noise on your machine gets amplified into a completely different Performance number. It's also usually pessimistic relative to a clean lab environment, because your dev laptop is rarely as idle as it feels. A local Lighthouse run is a legitimate diagnostic tool for finding what's slow — it's a terrible instrument for proving to someone else that you made something faster, because the "before" and "after" runs aren't comparable to anything, including each other.

The fix: drive pagespeed.web.dev, not the API

The actual fix isn't a smarter script — it's switching instruments entirely. pagespeed.web.dev is the same PageSpeed Insights engine, but run through Google's own hosted infrastructure instead of your laptop or the rate-limited anonymous API tier. Two things make it the right tool for a before/after claim:

  1. It's Google's number, not yours. The gauges are rendered by Google's servers, on Google's network, with Google's throttling profile — a client can screenshot-verify it, or paste your URL in and get the same number themselves. That's the credibility a JSON API response or a local terminal output can never have.
  2. It's stable enough to compare, as long as you control for the variables that move it. Run it back-to-back, same time window, same page state, and the swing is dramatically smaller than local Lighthouse's CPU-throttled chaos.

The workflow that actually produces a defensible before/after:

  1. Open pagespeed.web.dev, paste the old site's URL, run it, and let it fully settle (mobile tab, since that's what most traffic and most Core Web Vitals judgments are based on).
  2. Element-screenshot the gauge row — the smallest region containing all four category scores (Performance, Accessibility, Best Practices, SEO). Not a full-page screenshot with browser chrome; just the gauges, tight and legible.
  3. Repeat for the new site, same device tab, ideally within the same session so nothing about Google's infrastructure has drifted between runs.
  4. Put both screenshots side by side. That pairing — same instrument, same settings, same day — is what turns "we made it faster" into a claim someone can actually verify.

The rule underneath all of this: measure old and new with the same instrument, and pick the instrument the other person can independently re-run. Never mix a local Lighthouse "before" with a hosted PSI "after" — you're not measuring the redesign anymore, you're measuring the difference between two throttling models, and any credible reviewer will spot it.

A note on what actually improves

Be honest about where the score movement will actually show up. An old site that's already reasonably built often scores close to 100 on SEO and Best Practices already — there's rarely much headroom there, and claiming a dramatic "SEO score" win when it went from 92 to 100 is not the story. The real, defensible wins on a redesign are almost always Performance and Accessibility — those are the categories where a bloated old template genuinely has room to fall, and where deliberate engineering genuinely moves the needle. Frame the pitch around the two categories where the number actually means something.

How to actually hit high scores on a static site

Getting the "after" screenshot to look good isn't luck — it comes from a short list of decisions that consistently move Performance and Accessibility, in roughly this order of impact:

  • Self-host your fonts and preload them. A Google Fonts <link> costs you an extra DNS lookup, connection, and round trip before the font file even starts downloading — and until it arrives, you either get invisible text or a layout shift when it swaps in. Self-hosting the woff2 files and preloading them removes that entire chain:

    <link
      rel="preload"
      href="/fonts/inter-var.woff2"
      as="font"
      type="font/woff2"
      crossorigin
    />
    

    This is one of the single biggest, cheapest fixes for both Cumulative Layout Shift and Largest Contentful Paint on a text-heavy page.

  • Don't opacity-gate the hero behind your animation library before first paint. If your hero section renders at opacity: 0 and waits for a GSAP timeline (or any JS) to fade it in, you've just delayed your Largest Contentful Paint until after hydration and script execution — on a throttled mobile CPU, that's real, measurable seconds. Let the hero paint immediately in its final visual state, then animate secondary elements in around it. I go deeper into this trade-off in Core Web Vitals for animation-heavy sites — motion and a good LCP aren't in conflict, but only if you sequence them correctly.

  • Preload the LCP image explicitly. Whatever image or hero element the browser identifies as the Largest Contentful Paint candidate should be preloaded, not left to the browser's default discovery order:

    <link rel="preload" as="image" href="/hero.webp" fetchpriority="high" />
    

    Pair it with fetchpriority="high" on the <img> tag itself so the browser doesn't deprioritize it behind other requests.

  • Fix heading order. This one is pure Accessibility score and costs nothing: one <h1> per page, no skipped levels (an <h2> should never jump straight to an <h4>), and headings used for actual document structure rather than picked for font size. Lighthouse's accessibility audit checks this directly, and it's a five-minute fix on most templates.

None of these require a framework migration or a rebuild — they're the difference between a page that looks fast in a screenshot and one that actually earns the score.

PSI API vs local Lighthouse vs pagespeed.web.dev

PSI API (anonymous)Local npx lighthousepagespeed.web.dev UI
QuotaShared globally, frequent 429sNone (runs on your machine)Effectively unlimited for manual use
Stability run-to-runN/A (can't get a response)Poor — swings 20-30+ points on identical pagesGood — consistent enough to compare
What it measuresGoogle's lab data, if it respondsYour laptop's CPU/network, throttledGoogle's hosted lab environment
Citability to a clientLow — a raw JSON blobLow — a terminal number nobody else can reproduceHigh — a client can re-run it themselves
Best useAutomated CI budgets (with a real API key)Local debugging of what's slowBefore/after proof for a pitch or report

Take this to your redesign pitch

The whole point of this exercise is a slide that survives scrutiny: two gauge screenshots, same instrument, same day, one dim and one glowing green. That's a stronger argument than any paragraph of claims about "optimized performance." If you're evaluating whether a redesign is worth the investment in the first place, I've written about the business case separately in the hidden cost of a slow website — and if you'd rather have someone run this whole measurement-and-fix process for you, that's exactly the kind of work covered on the services page.

FAQ

How do I get accurate before/after Lighthouse scores?

Run the old and new versions of the site through the same instrument, in the same session, and compare the gauge outputs directly rather than isolated numbers. pagespeed.web.dev is the most practical choice because it's stable enough to compare and independently verifiable by whoever you're presenting to — screenshot the full gauge row for both.

Why is my Lighthouse score different every run?

Local Lighthouse throttles your CPU and network to simulate a mobile device, using your machine's actual hardware as the baseline. Background processes, thermal throttling, and network jitter all shift that baseline, so identical pages can score 20-30 points apart between runs. It's a diagnostic tool, not a benchmark instrument.

Local Lighthouse vs PageSpeed Insights — which should I trust?

Use local Lighthouse (npx lighthouse --view) to diagnose what's slow during development — it's fast and convenient for iteration. Use the hosted pagespeed.web.dev UI when you need a number to show someone else, because it's stable and reproducible on their end too.

How do you actually prove a website performance improvement to a client?

Same instrument, same settings, old site and new site measured back-to-back, presented as paired gauge screenshots rather than a claimed percentage. The client should be able to paste your URL into the same tool and get the same result you showed them.

pagespeed.web.dev vs npx lighthouse — what's the real difference?

Both run the Lighthouse engine under the hood, but pagespeed.web.dev executes it on Google's hosted infrastructure with a consistent environment, while npx lighthouse executes locally, throttled through your own machine's variable CPU and network conditions. For anything you need to show or defend to someone else, use the hosted version.