PageSpeed Insights API rate limits and quota exceeded errors
You sent one request too many and got this back:
Quota exceeded for quota metric 'Queries' and limit 'Queries per day' of
service 'pagespeedonline.googleapis.com' for consumer 'project_number:...'
That's HTTP 429. The quota belongs to a Google Cloud project — the one behind your API key. It is not per key and not per IP address. Google publishes no number for it in the PageSpeed Insights documentation. Every figure you find in a blog post is somebody's snapshot of their own console. The number that applies to you is on your project's quota page, and nowhere else.
Which limit did you hit?
The 429 body carries more than the message. Here is the part that matters, from a keyless request I sent on 2 September 2026:
{
"error": {
"code": 429,
"status": "RESOURCE_EXHAUSTED",
"details": [{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "RATE_LIMIT_EXCEEDED",
"metadata": {
"quota_metric": "pagespeedonline.googleapis.com/default",
"quota_unit": "1/d/{project}",
"quota_limit": "defaultPerDayPerProject",
"quota_limit_value": "0",
"consumer": "projects/583797351490"
}
}, {
"@type": "type.googleapis.com/google.rpc.Help",
"links": [{
"description": "Request a higher quota limit.",
"url": "https://cloud.google.com/docs/quotas/help/request_increase"
}]
}]
}
}
Read quota_unit first. It tells you the window.
| Field | What it tells you |
|---|---|
quota_unit |
the window — 1/d/{project} is a daily limit |
quota_limit |
the limit ID to search for in the Cloud console |
quota_metric |
the metric row on the quota page |
consumer |
which project the request counted against |
The pages I found for this error quote the message and stop there. That block is the difference between a wait of a minute and a wait until tomorrow.
Do I still need an API key?
Yes. Google's getting-started page says only that a key "is recommended for
frequent, automated queries", which reads like a suggestion. Google's own discovery
document disagrees with it: there, key is "Required unless you provide an OAuth
2.0 token."
Trust the discovery document. Keyless requests all count against one anonymous
project, 583797351490, and look again at quota_limit_value above. It is 0. The
shared quota isn't drained — it's set to zero, so a keyless request fails on the
first try rather than the thousandth. The same project number turns up in a
bubblewrap bug report from May 2026 and in OpenPanel's help page. Get a key.
So what is the actual quota?
I could not verify a single figure against a Google source, and I looked hard. Five numbers circulate instead.
| Figure | Where it comes from |
|---|---|
| 25,000/day, 1 request/second | a KNIME node's docs, marked "as of September, 2015" |
| 25,000/day, 100 per 100 seconds | a 2016 Google Groups post |
| 25,000/day, 1,500 per minute | a different poster in the same 2016 thread |
| 25,000/day, 240 per 4 minutes | a developer log from October 2022 |
| 25,000/day, 240 per minute | DebugBear, updated December 2025 |
Normalise the second column and most of that disagreement goes away. One a second, 100 per 100 seconds and 240 per 4 minutes are the same rate written three ways: 60 a minute. DebugBear's 240 a minute is four times it. The 2016 figure of 1,500 a minute is twenty-five times it, and its author called the limit bursty and averaged.
The daily number is the only thing all five agree on. A 2021 bug report caught the
other half of the error string: limit 'Queries per minute'. So the short window is
named per minute somewhere in the quota system, whatever its value is.
Read yours instead. In the Google Cloud console, open APIs & Services → PageSpeed Insights API → Quotas, and find the metric named in your error payload. That page shows the limit and your usage against it. It is the only figure that is both current and yours.
Retries: what works, and what wastes your afternoon
Google's own API design guidance covers this case. AIP-194 lists
RESOURCE_EXHAUSTED as generally non-retryable: "Retries therefore may not be
expected to work for several hours." Exponential backoff against a daily quota is a
loop that burns your CI minutes and changes nothing.
So branch on the window, not on the status code.
There's one more failure that no quota page explains. One developer ran roughly one request a second and hit 500 errors in valleys. They arrived every 450 to 500 requests and lasted about five minutes. Requests for a different origin succeeded while the stalled job kept failing. But those went out on a second key, so the experiment doesn't separate the origin from the key. It's a single report from October 2022 and I have found no Google documentation of it. Treat it as a reason to spread one origin's requests over time, not as a rule.
When PSI stops being the right tool
Be honest about the shape of your problem before you reach for a replacement. Three of these aren't us.
| You need | Reach for | The catch |
|---|---|---|
| Real-user field data, at scale | CrUX API — 150 queries/minute per project, documented and free | Origin and page level only, no lab report, 28-day window |
| Historical field data for many origins | CrUX on BigQuery, back to 2017 | SQL, a Cloud account and a card, free only to the BigQuery free tier |
| Lighthouse on every commit, no quota at all | Lighthouse CI — Google's own, Apache-2.0 | You run the machines, and your numbers move when the runner does |
| Lab runs from a location you choose | A hosted Lighthouse API, ours included | Somebody's fleet, somebody's limits |
If you audit one site on every push, Lighthouse CI is the tool for it and the
software costs nothing. You hit the limit when you test many URLs. You also hit it
when you need the run to come from a place Google won't let you pick. The v5
runPagespeed method takes seven parameters of its own, and not one of them is a
location.
That last case is what we built. Lightscore runs the same Lighthouse engine from a region you name, on a pinned Lighthouse version, and hands back the full JSON and HTML report. It measures Core Web VitalsGoogle’s three headline UX metrics: LCP (load), INP (responsiveness), CLS (stability). in the lab, so it is not a substitute for CrUX field data — different question, different tool. And we have limits too: the free one-URL tool limits new audits per IP address per hour, and its page says so.
Common questions
What does "Quota exceeded for quota metric 'Queries'" mean?
Your Google Cloud project has used its allowance for the PageSpeed Insights API. The API returns HTTP 429 with the status RESOURCE_EXHAUSTED. The quota belongs to the project behind your API key, not to your key and not to your IP address. Requests without a key all count against one anonymous project, whose daily limit is zero.
What is the PageSpeed Insights API rate limit?
Google does not state it in the PageSpeed Insights documentation. Third-party pages give five different short-window figures, from 1 request a second to 240 a minute, all against the same 25,000 a day. Three of the five are the same rate written three ways. The only figure that applies to your project is the one on its quota page in the Google Cloud console.
Do I need an API key for the PageSpeed Insights API?
In practice, yes. Google's getting-started page says only that a key is recommended for frequent, automated queries, but the API's discovery document calls it required. On 2 September 2026 a keyless request returned 429 on the first try. The anonymous project's daily limit is 0.
Can I pay for more PageSpeed Insights quota?
The 429 response links to Google's generic quota-increase page, so you can file a request. Google publishes no paid tier for this API. Plan for the free quota rather than around a raise.