Core Web Vitals Alerts: Score Drops Since Last Run avatar

Core Web Vitals Alerts: Score Drops Since Last Run

Pricing

from $3.50 / 1,000 url checkeds

Go to Apify Store
Core Web Vitals Alerts: Score Drops Since Last Run

Core Web Vitals Alerts: Score Drops Since Last Run

Check a list of page URLs with Google PageSpeed Insights on your own free API key and get the score, LCP, CLS and INP, plus an alert mode that only returns and bills the URLs whose performance regressed since your last run.

Pricing

from $3.50 / 1,000 url checkeds

Rating

0.0

(0)

Developer

Adriana Voss

Adriana Voss

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Share

Find out which of your pages got slower since the last check, before Google or your customers do. Give it a list of page URLs and your own free Google API key. For each URL it runs Google PageSpeed Insights (Lighthouse) and returns the performance score plus LCP, CLS and TBT, with INP, LCP and CLS from real Chrome users where Google has enough traffic data. Turn on monitoring and run it on a schedule: it remembers the last numbers per URL and only returns, and only bills, the URLs whose score or Core Web Vitals got worse.

Who uses it: SEO and web teams watching key landing pages after every release, agencies keeping an eye on client sites, and e-commerce owners who want a ping when a theme or app update slows the shop down.

You bring the key. This actor never contains, stores or shares a Google key. You paste your own into the secret "Your Google API key" field; it is used only for your run. A free key takes about 10 minutes to create (Google Cloud Console, APIs and Services, Credentials, then enable the PageSpeed Insights API) and covers up to 25,000 checks a day. Without a key the actor still runs: every URL comes back as a free NEEDS_KEY row that tells you where to get one.

Related actors: for a one-off technology check of a site use Tech Stack Lookup.

How to use

  1. In the Apify Console. Open the actor page and click Start — the urls field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
  2. Via the API. Call it directly with a POST request — no Console needed once you have an API token:
    curl "https://api.apify.com/v2/acts/accountable_eel~core-web-vitals-regression-alerts/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"urls":["https://example.com"]}'
  3. On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.

Input

{
"urls": [
"https://example.com"
]
}

One page URL per line (https:// is added if missing). Each URL is one Google PageSpeed Insights run, so a long list takes a few minutes. Needs your own free Google API key below. Accepted formats: https://example.com, www.example.com/pricing, https://shop.example.com/products/best-seller.

Alert thresholds. Mobile scores jitter by a few points between identical runs, so a change only counts once it clears a tolerance band you control: the performance score must drop by "Alert when the score drops by" points (default 5), and LCP, CLS or INP must move into a worse Google band (LCP 2500/4000 ms, CLS 0.1/0.25, INP 200/500 ms) and get at least "Alert when LCP, CLS or INP worsen by" percent worse (default 20). INP comes from real-user data, so it is only compared when Google has it for the URL on both runs.

Monitoring. With "Only return URLs that regressed since the last run" on, the first run stores a baseline for each URL (returned and billed once). Later runs return and bill only URLs that regressed; URLs that held steady or improved come back as free STABLE / IMPROVED rows with urlCount 0. The memory lives in a named key-value store of this actor on your account, one record per URL and device. A URL that fails to measure never overwrites its baseline.

One check takes 10 to 30 seconds (Google runs a real Lighthouse test), so 50 URLs take a few minutes. A page Google cannot load is retried by the platform, which can cost a few of your own quota units.

Output

One row per URL. Numbers Google does not have are null, never 0 (a page with a real CLS of 0 shows 0). Real-user fields (inpMs, fieldLcpMs, fieldCls, fieldCategory) are null for pages without enough Chrome traffic. Every row carries the page address and a reportUrl to Google's own report.

queryfoundstatuspageUrlstrategyperformanceScorelcpMsclstbtMsinpMsfieldLcpMsfieldClsfieldCategorymonitorStatusregressedregressionspreviousScorepreviousLcpMspreviousClspreviousInpMspreviousCheckedAtreportUrlurlCountscrapedAt
https://example.comtrueOK<performance score (0-100)><lcp, lab (ms)><cls, lab><tbt, lab (ms)><inp, real users (ms)><lcp, real users (ms)><cls, real users><previous lcp, lab (ms)><previous cls, lab><previous inp (ms)>1970-01-01T00:00:00.000Z

A URL that could not be measured comes back as a row with "found": false and a status: NEEDS_KEY (no key, a malformed key, a rejected key, or the PageSpeed Insights API not enabled for the key's project), BAD_FORMAT, NOT_FOUND (Lighthouse could not load the page), BLOCKED (your Google quota is used up) or REQUEST_FAILED. Those rows are never charged.

Pricing

Pay-per-event. A flat per-run fee covers session/proxy warmup; you're billed per item only when data is actually found and returned — see .actor/pay_per_event.json for exact prices. A miss is never charged.

What is billed. One url-checked event per URL measured. A URL that could not be measured, a NEEDS_KEY row and, in monitoring mode, a quiet STABLE or IMPROVED row are never charged. The Google API call itself runs on your own key and your own Google quota (25,000 checks a day, 240 a minute); Google does not charge for it.

Example runs

These three runs use no key, so they are free and show exactly what a first test returns.

1. One URL, no key.

{ "urls": ["https://example.com"] }
{ "query": "https://example.com", "found": false, "status": "NEEDS_KEY", "message": "No Google API key was supplied, so nothing was measured for this URL. Create a free key in Google Cloud Console (APIs and Services, Credentials), enable the PageSpeed Insights API, then paste it into the \"Your Google API key\" field. It takes about 10 minutes and is free up to 25,000 checks a day.", "scrapedAt": "2026-10-11T22:44:39.476Z" }

2. A list with a bare domain and a typo. www.example.org/pricing gets the same NEEDS_KEY row as above (https:// is added for you); not a url gets "status": "BAD_FORMAT" with the message "This does not look like a page URL. Use a full address such as https://example.com/pricing." Both are free.

{ "urls": ["https://example.com", "www.example.org/pricing", "not a url"] }

3. Monitoring switched on, still no key. Nothing is measured and nothing is remembered, so your later keyed run is still a clean first baseline.

{ "urls": ["https://example.com"], "onlyNewSinceLastRun": true, "deltaName": "landing-pages" }

With your key

One URL with a key and monitoring on, a real run on https://example.com (mobile). The first monitoring run stores the baseline, so the previous* fields are null:

{ "urls": ["https://example.com"], "googleApiKey": "<your key>", "onlyNewSinceLastRun": true }
{
"query": "https://example.com", "found": true, "status": "OK", "scrapedAt": "2026-10-11T22:45:19.267Z",
"pageUrl": "https://example.com/", "strategy": "mobile",
"performanceScore": 100, "lcpMs": 754, "cls": 0, "tbtMs": 0,
"inpMs": 87, "fieldLcpMs": 1049, "fieldCls": 0, "fieldCategory": "FAST",
"monitorStatus": "BASELINE", "regressed": null, "regressions": null,
"previousScore": null, "previousLcpMs": null, "previousCls": null, "previousInpMs": null, "previousCheckedAt": null,
"reportUrl": "https://pagespeed.web.dev/analysis?url=https%3A%2F%2Fexample.com", "urlCount": 1
}

On a later run the same URL comes back like this only if it got worse, for example "monitorStatus": "REGRESSED", "regressions": ["performance score 92 to 78", "LCP 2000 ms to 3100 ms"], with the earlier numbers in the previous* fields.

FAQ

Why do I need my own key? Google gives the shared, keyless project no quota for this API, and a key of your own keeps your usage, your quota and your Google account separate from everyone else's. The actor never reads, stores or returns the key beyond your own run input.

Mobile or desktop? Mobile by default, which is the profile Google ranks on. Desktop and mobile keep separate monitoring memories.

Why did my score change when nothing changed? Lab scores are a simulation and move a few points run to run. That is why alerts need a drop of 5 points by default; raise it for noisy pages.

Why is INP empty? INP is a real-user number. Google only publishes it for URLs with enough Chrome traffic.

Does it check pages behind a login? No. Google must be able to open the URL without signing in.

Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

curl "https://api.apify.com/v2/acts/accountable_eel~core-web-vitals-regression-alerts/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-X POST \
-H "Content-Type: application/json" \
-d '{"urls":["https://example.com"]}'

n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~core-web-vitals-regression-alerts/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"urls":["https://example.com"]} (swap in an expression from an earlier node for a real value).

Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~core-web-vitals-regression-alerts/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"urls":["{{URL}}"]}, mapping the row's URL into the urls array.

MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "core web vitals monitor" — the agent will find and run this actor.