ChimeraMiND Data
Home / Guides / Bulk Core Web Vitals
SEO & site audits

Check Core Web Vitals and PageSpeed scores for hundreds of URLs at once

Run Google PageSpeed Insights over a whole URL list and get one flat row per page — Lighthouse scores, LCP, CLS, INP, TBT, real-user field data, a Core Web Vitals pass/fail and the biggest fixes.

pagespeed.web.dev is perfect for one page. It is painful for a site migration with 300 templates, an agency checking 50 client homepages every month, or a sales team that wants to open with "your mobile site fails Core Web Vitals". This guide shows how to run Google PageSpeed Insights over an entire list of URLs and get one flat row per URL and device — the same numbers Google shows you, ready for a spreadsheet — for $5 per 1,000 results.

What you get

Each row combines two kinds of data that PageSpeed Insights reports:

  • Lab data — a fresh Lighthouse run on Google's servers: performanceScore (0–100), optional seoScore, accessibilityScore and bestPracticesScore, plus lcpMs, cls, tbtMs, fcpMs, speedIndexMs, ttiMs and ttfbMs.
  • Field data — real Chrome users over the trailing 28 days from the Chrome UX Report, in fieldData (lcpMs, cls, inpMs, fcpMs, ttfbMs, overallCategory), when the site has enough traffic to be included.

On top of that you get passesCoreWebVitals (field LCP ≤ 2500 ms, CLS ≤ 0.1 and INP ≤ 200 ms), a labGrade (good, needs-improvement, poor) and topOpportunities — up to five failed Lighthouse audits with their estimated savings, biggest first. A real row from a recorded run:

Archived example · 15 days old. This is a snapshot, not current data.run s4cvBCaBblPEpy46H · 2026-10-03
{
  "url": "https://apify.com/",
  "finalUrl": "https://apify.com/",
  "strategy": "mobile",
  "performanceScore": 35,
  "accessibilityScore": null,
  "bestPracticesScore": null,
  "seoScore": null,
  "lcpMs": 16894,
  "cls": 0,
  "tbtMs": 1835,
  "fcpMs": 2701,
  "speedIndexMs": 9369,
  "ttiMs": 34446,
  "ttfbMs": 15,
  "fieldData": {
    "lcpMs": 2463,
    "cls": 0.01,
    "inpMs": 385,
    "fcpMs": 2326,
    "ttfbMs": 1383,
    "overallCategory": "AVERAGE"
  },
  "passesCoreWebVitals": false,
  "labGrade": "poor",
  "topOpportunities": [
    {
      "id": "unused-javascript",
      "title": "Reduce unused JavaScript",
      "savingsMs": 2550
    },
    {
      "id": "unminified-css",
      "title": "Minify CSS",
      "savingsMs": 0
    },
    {
      "id": "unused-css-rules",
      "title": "Reduce unused CSS",
      "savingsMs": 0
    }
  ],
  "lighthouseVersion": "13.5.0",
  "fetchedAt": "2026-10-03T15:18:52.669Z",
  "error": null,
  "scrapedAt": "2026-10-03T15:19:28.193Z"
}

Before you start: the free API key

PageSpeed Insights has a shared anonymous quota that is almost always exhausted. Runs of up to 5 URLs work without a key on a demo quota so you can try the tool immediately. For anything bigger, create a free PageSpeed Insights API key in Google Cloud (no billing required; Google allows 25,000 requests per day) and paste it into Google PageSpeed Insights API key. Without one, rows come back with an HTTP 429 in error and empty metrics rather than failing the run.

Step-by-step

  1. Open the tool and paste the pages into URLs to audit, one full URL per line — the exact pages you care about, not just the homepage.
  2. Paste your API key.
  3. Choose the Device strategy: mobile is what Google uses for ranking; both returns two rows per URL.
  4. Add extra Lighthouse categories (seo, accessibility, best-practices) if you want those scores too.
  5. Keep Max concurrency at 2–3 and click Start. Expect roughly 10–30 seconds per URL and device, a few in parallel.

Run Bulk Core Web Vitals & PageSpeed Audit on Apify →

Call it from code

import json
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"]) run = client.actor("webdatatools/core-web-vitals-audit").call(run_input=json.loads("{\n "urls": [\n "https://apify.com\",\n "https://example.com\"\n ],\n "strategy": "mobile",\n "categories": [\n "performance",\n "seo"\n ]\n}"))

for item in client.dataset(run["defaultDatasetId"]).iterate_items(): print(item)

import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN }); const run = await client.actor('webdatatools/core-web-vitals-audit').call({ "urls": [ "https://apify.com", "https://example.com" ], "strategy": "mobile", "categories": [ "performance", "seo" ] }); const { items } = await client.dataset(run.defaultDatasetId).listItems(); console.log(items);

curl -X POST "https://api.apify.com/v2/acts/webdatatools~core-web-vitals-audit/run-sync-get-dataset-items" 
-H "Authorization: Bearer $APIFY_TOKEN"
-H "Content-Type: application/json"
-d '{"urls":["https://apify.com","https://example.com"],"strategy":"mobile","categories":["performance","seo"]}'

Recipes

Pre- and post-migration comparison

Export one URL per page template (home, category, product, article, landing page) before a redesign and run the audit. Run the same list after launch and diff performanceScore, lcpMs and cls per URL. Regressions show up per template instead of as a vague "the site feels slower".

Weekly regression watch

Schedule the run for your 20–50 most valuable pages. Point a webhook or the Google Sheets integration at the dataset and alert when labGrade drops to poor or passesCoreWebVitals flips to false. Lab scores move a few points between runs, so alert on thresholds, not on every change.

Prospecting with a concrete opener

Agencies run a list of prospect homepages overnight, filter rows where passesCoreWebVitals is false, and quote the first item of topOpportunities ("Reduce unused JavaScript — about 2 s of savings") in the outreach email. Feeding the list from another tool's dataset works through inputDatasetId.

How much does it cost?

Apify planPer resultPer 1,000
Free plan$0.005$5
Starter$0.004$4
Scale$0.0035$3.50
Business$0.003$3
Enterprise$0.003$3
Enterprise+$0.003$3

Primary event rates from a catalog snapshot; this is not the total price of a run. Additional charge events and Actor Start fees may apply; start fees can scale with memory. Check the Actor's Pricing tab on Apify for all events, conditions and current plan-specific rates, and set a maximum run budget before starting.

One row is one URL on one device, so strategy: "both" doubles the count. The Lighthouse work happens on Google's servers, which keeps platform usage tiny. Set Maximum cost per run in Apify and the tool trims the list to what the budget covers.

How it compares

Option Good at Watch out for
This tool Hundreds of URLs per run, flat rows, field + lab data, schedule and API access, pay per row Needs your free PSI key beyond 5 URLs; lab scores vary run to run like any Lighthouse test
pagespeed.web.dev Quick one-off check with visual report One URL per click, no export, no history
Lighthouse CLI on your machine Full report, any URL including staging Your hardware and network skew the numbers; no CrUX field data unless you query it separately
Monitoring subscriptions Dashboards, alerts, long-term trends Monthly seats whether or not you run checks

FAQ

Why is fieldData null for my site?

The Chrome UX Report only covers origins with enough real Chrome traffic. Smaller sites get lab data only, and passesCoreWebVitals is then null, because INP cannot be measured in a lab run.

Why did the score change between two runs?

Lighthouse is a live measurement on shared hardware, so performance scores move a few points from run to run. Treat field data as the stable truth and lab data as directional.

Which device should I test?

Mobile, unless you have a specific reason. Google uses mobile performance for ranking, and mobile scores are usually the lower of the two.

Is my API key safe?

The key field is a secret input in Apify, hidden in the Console and logs. The key only needs the PageSpeed Insights API enabled; restrict it to that API in Google Cloud.

Can I check pages behind a login or on localhost?

No. PageSpeed Insights fetches the URL from Google's servers, so the page must be publicly reachable.

Related tools

Workflows