Bulk PageSpeed Insights & Core Web Vitals Checker avatar

Bulk PageSpeed Insights & Core Web Vitals Checker

Pricing

from $1.60 / 1,000 pagespeed measurements

Go to Apify Store
Bulk PageSpeed Insights & Core Web Vitals Checker

Bulk PageSpeed Insights & Core Web Vitals Checker

Google PageSpeed Insights (Lighthouse) for many URLs: performance, accessibility, SEO scores, LCP, CLS, TBT, real-user Core Web Vitals (CrUX), top fixes, budgets and regression alerts. No API key needed. $2 per 1,000 measurements, failed free.

Pricing

from $1.60 / 1,000 pagespeed measurements

Rating

0.0

(0)

Developer

Yukai Lin

Yukai Lin

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

2 days ago

Last modified

Share

What does Bulk PageSpeed Insights & Core Web Vitals Checker do?

Paste a list of URLs, get one row per page and device with Lighthouse scores, lab metrics, real-user Core Web Vitals and the biggest fix, at $2 per 1,000 measurements ($0.002 each). Failed or timed-out measurements, pages that cannot be loaded, invalid URLs and measurements skipped after a quota stop are free. No start fee, no API key needed.

It runs Google PageSpeed Insights (Lighthouse) on a whole list of URLs and gives you one clean row per page and device, ready for a spreadsheet, a dashboard or an alert:

  • 🚦 Lighthouse scores (0-100): performance, accessibility, best practices and SEO, in one measurement.
  • ⏱️ Lab metrics: First Contentful Paint, Largest Contentful Paint, Total Blocking Time, Cumulative Layout Shift, Speed Index and Time to Interactive.
  • 👥 Real-user Core Web Vitals from the Chrome UX Report (CrUX): LCP, INP, CLS, FCP and TTFB at the 75th percentile, each rated FAST / AVERAGE / SLOW, and the overall Core Web Vitals PASSED / FAILED assessment, for the URL or (when it has too little traffic) for its whole site.
  • 🔧 Top opportunities: the biggest fixes Lighthouse found (e.g. "Reduce unused JavaScript ~0.8 s") with the estimated time saved.
  • 📱 Mobile, desktop or both in one run.
  • ✅ Performance budgets: set a minimum score, a maximum LCP / CLS / TBT / INP or "Core Web Vitals must pass"; every row gets passed and failedChecks.
  • 📉 Regression alerts for scheduled runs: each URL is compared with the previous run (previousScore, scoreChange, regressed), and "Only output regressions" returns just the pages that got slower.
  • 📄 CSV file with the main columns.

No API key needed: measurements run on our capacity. You can add your own free Google API key if you want Google to be called directly with it.

Why this Actor?

  • Everything in one row: four Lighthouse scores, six lab metrics, real-user Core Web Vitals for the URL and the site, and the top fixes. Most PageSpeed Actors return the performance score and a few lab metrics only.
  • Built for monitoring: budgets with pass/fail, run-to-run comparison and a regressions-only output make a daily or weekly schedule an alert, not a pile of data.
  • $2 per 1,000 measurements, failed ones free: a page Lighthouse cannot load costs nothing (several Store Actors charge for it or fail the run).
  • Keeps working when Google is busy: if Google's PageSpeed service cannot measure a page, the run falls back to our own Lighthouse servers (same Lighthouse engine, no real-user data).

Real results (4 October 2026)

Local runs on the production backend, 4 October 2026 (times include start-up):

  • 13 well-known sites + 1 dead domain + 1 typo, mobile and desktop (28 measurements): 22 measured and charged ($0.044), 6 failed for free, 1 invalid input free, 4 min 47 s with 4 in parallel. Google measured 18 (12-64 s each); for amazon.com and github.com Google could not finish, so our Lighthouse server in Taiwan measured them (26-139 s). nytimes.com and etsy.com block Lighthouse and the dead domain does not resolve: page_failed, not charged.
  • What it found: news.ycombinator.com 100 / 100, wikipedia.org 98 (mobile), apple.com 53 mobile vs 94 desktop, bbc.com 30 on mobile with a lab LCP of 12.5 s, yet real users pass Core Web Vitals there; stripe.com, shopify.com and web.dev fail Core Web Vitals on mobile. With the budgets "score ≥ 50, LCP ≤ 4 s, Core Web Vitals must pass", 12 rows passed and 10 failed, each with its failedChecks.
  • 5 pages, mobile, with comparison: 33 s, $0.01. The same 5 pages a minute later with "Only output regressions" and a 5-point threshold: 3 rows (python.org 82 → 74, apple.com 65 → 56, web.dev 46 → 35), 2 stable pages left out. Lighthouse scores move this much between back-to-back runs, which is why the default threshold is 10 points: a third run with 10 points returned 0 rows (all 5 stable).

Use cases

  • SEO audits at scale: score every template or top landing page of a site (or of a client list) on mobile and desktop in one run.
  • Core Web Vitals monitoring: a weekly schedule with "Compare with the previous run" and "Only output regressions" tells you which pages got slower after a release.
  • Performance budgets in CI or QA: fail a release check when the home page drops below 80 or LCP goes over 2.5 s (passed: false, failedChecks).
  • Competitor benchmarks: compare your speed and real-user experience with competitors' pages.
  • Agency reporting: CSV with scores, Core Web Vitals and the top fix per page, ready for Google Sheets or Looker Studio.

How to use it

  1. Paste your URLs (or bare domains) under URLs, paste text, or upload / link a .txt or .csv file. One per line, or separated by commas, semicolons or tabs; quotes and brackets pasted around a link are removed. One page is measured and charged once per device, however it is spelled: a.com, https://www.a.com/, https://a.com/?utm_source=x and https://a.com/#x are the same page (the first spelling is measured, without the #fragment and tracking parameters such as utm_*, gclid, fbclid; SUMMARY.duplicatesMerged). http:// and https://, and different paths or other query parameters, stay separate pages.
  2. Choose the Device: mobile (what Google uses for ranking), desktop or both.
  3. Optional: set performance budgets (minimum score, maximum LCP, CLS, TBT, INP, "Core Web Vitals must pass").
  4. Optional, for schedules: turn on Compare with the previous run (and Only output regressions), then create an Apify schedule.
  5. Run it. Results appear in the dataset (tabs: PageSpeed results, All Lighthouse scores, Real-user Core Web Vitals, Changes, Errors) and in PAGESPEED.csv.

A Google measurement takes 10-50 seconds per page; with 4 in parallel a run does about 10-15 pages per minute.

Input example

{
"urls": ["https://www.python.org/", "https://example.com/"],
"strategy": "both",
"minPerformanceScore": 50,
"maxLcpMs": 4000,
"requireCoreWebVitals": true
}

Output example

{
"type": "measurement",
"input": "https://www.python.org/",
"url": "https://www.python.org/",
"finalUrl": "https://www.python.org/",
"strategy": "mobile",
"performanceScore": 72,
"performanceRating": "needs-improvement",
"accessibilityScore": 75,
"bestPracticesScore": 96,
"seoScore": 92,
"fcpMs": 2859,
"lcpMs": 5318,
"tbtMs": 0,
"cls": 0,
"speedIndexMs": 4890,
"ttiMs": 5318,
"coreWebVitals": "PASSED",
"fieldDataScope": "url",
"fieldLcpMs": 1236,
"fieldInpMs": 88,
"fieldCls": 0,
"fieldFcpMs": 1168,
"fieldTtfbMs": 531,
"fieldData": {
"url": { "lcpMs": 1236, "lcpCategory": "FAST", "inpMs": 88, "inpCategory": "FAST", "cls": 0, "clsCategory": "FAST", "fcpMs": 1168, "fcpCategory": "FAST", "ttfbMs": 531, "ttfbCategory": "FAST", "coreWebVitals": "PASSED", "overallCategory": "FAST" },
"origin": null
},
"topOpportunity": "Reduce unused JavaScript (~750 ms)",
"opportunities": [
{ "id": "unused-javascript", "title": "Reduce unused JavaScript", "savingsMs": 750, "savingsBytes": 60458 },
{ "id": "unused-css-rules", "title": "Reduce unused CSS", "savingsMs": 560, "savingsBytes": 131404 }
],
"passed": false,
"failedChecks": ["lcpMs 5318 > 4000"],
"source": "google",
"lighthouseVersion": "13.5.0",
"durationSecs": 15.1,
"measuredAt": "2026-10-03T17:51:16.672Z",
"success": true,
"charged": true
}

The run also writes a SUMMARY record (status, measurements, average score, sources used, budgets passed/failed, regressions, failures by errorType, cost plan) and PAGESPEED.csv.

What the fields mean

  • performanceScore, accessibilityScore, bestPracticesScore, seoScore: Lighthouse category scores, 0-100 (90+ is good, 50-89 needs improvement, under 50 is poor; performanceRating).
  • fcpMs, lcpMs, tbtMs, cls, speedIndexMs, ttiMs: lab metrics from this Lighthouse run (an emulated mid-range phone on slow 4G for mobile). Lab data has no INP.
  • coreWebVitals: the real-user assessment from the Chrome UX Report: PASSED when LCP, INP and CLS at the 75th percentile are all "good" (2.5 s, 200 ms, 0.1), FAILED otherwise, null when Google has no real-user data for the page or site.
  • fieldDataScope: url (data for this page) or origin (the page has too little traffic, so the whole site's data is shown). fieldLcpMs, fieldInpMs, fieldCls, fieldFcpMs, fieldTtfbMs: 75th percentiles; fieldData has every metric with its FAST / AVERAGE / SLOW category.
  • topOpportunity and opportunities: the biggest suggested fixes with estimated time (savingsMs) and bytes saved.
  • passed, failedChecks: only when you set a budget, e.g. ["performanceScore 30 < 50", "lcpMs 9134 > 4000"].
  • change (new, stable, improved, regressed), previousScore, scoreChange, regressed, regressionReason: only with "Compare with the previous run".
  • source: google (Google PageSpeed Insights), google (your key), or lighthouse-tw / lighthouse-us (our own Lighthouse servers in Taiwan or the US, used when Google could not measure the page; fallbackReason says why).
  • success, charged, errorType (page_failed, timeout, quota_exceeded, invalid_api_key, not_measured, backend_error, backend_unavailable, invalid_input), error.

How much does it cost?

EventPriceWhen
PageSpeed measurement$2.00 / 1,000 ($0.002 each)one URL measured on one device with a performance score, plus the other scores, lab metrics, real-user Core Web Vitals and top fixes

Free: failed or timed-out measurements, pages Lighthouse cannot load, measurements skipped after a quota stop, invalid URLs. No start fee. "Both" devices = 2 measurements per URL. The extra Lighthouse categories, opportunities, budgets, comparison and CSV cost nothing more. Larger Apify plans get the usual volume discount (Silver 10%, Gold and above 20%).

Monitoring: with "Only output regressions" every URL is still measured and charged (the measurement is the work); stable pages are just left out of the dataset and listed in SUMMARY.comparison.notShown.

Example: 200 pages on mobile and desktop every week = 400 measurements = $0.80 a week.

For comparison (Apify Store, 4 October 2026): dev00/Google-PageSpeed-Insights-api $0.002 per result (64 users in the last 30 days), seemuapps/google-pagespeed-insights $0.008, automation-lab/website-lighthouse-seo-audit $0.014, perryay $0.015, neverempty $0.015, nexgendata/page-speed-analyzer $0.02, nexgendata/google-lighthouse-checker $0.10, onescales/website-speed-checker $0.10; constant_quadruped/lighthouse-auditor is a flat monthly rental.

Control your cost

  • Maximum URLs caps the input; the run logs the worst case (URLs × devices × $0.002) at the start.
  • When the next measurement could pass your maximum charge per run, the run stops (SUMMARY.status: LIMIT_REACHED, SUMMARY.notProcessed).
  • Every row has charged: true or false; free rows say "(not charged)". If Apify restarts the run, pages already measured are not measured or charged again.

Use it from code

curl -X POST "https://api.apify.com/v2/acts/tidytools~pagespeed-insights-bulk/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls":["https://www.python.org/","https://example.com/"],"strategy":"both"}'

With AI agents (MCP): connect Apify's MCP server (https://mcp.apify.com?tools=tidytools/pagespeed-insights-bulk) to Claude, Cursor or any MCP client and ask, for example, "Do these 20 landing pages pass Core Web Vitals on mobile, and what is the biggest fix for each?". Minimal input: {"urls": ["https://example.com/"], "strategy": "mobile"}. Failed items are not charged and carry an errorType.

Limitations

  • Lighthouse scores vary by a few points between runs (network, server load, ads). For monitoring, the default regression threshold is 10 points; real-user Core Web Vitals (28-day averages) are steadier.
  • Real-user data needs traffic: Google only publishes Chrome UX Report data for pages and sites with enough Chrome visitors. Small sites get coreWebVitals: null. INP exists only in real-user data.
  • Our Lighthouse fallback has no real-user data and measures from Taiwan or Phoenix, US, at about 1 minute per page (at most 2 at a time), so its scores can differ from Google's.
  • Some sites block Lighthouse (bot protection, geo-blocks) or never finish loading: those measurements fail with page_failed and are free. A domain that does not exist, a blank error page and a PDF also end as free page_failed rows.
  • An error page that renders is measured: like pagespeed.web.dev, a mistyped URL that shows a styled "404 not found" page (e.g. on github.com) gets scores and is charged. Check finalUrl and your list if a score looks odd.
  • URL or site data: real-user data on the backend route is either the URL's or the site's (not both); with your own Google API key you get both.
  • Daily capacity: the included capacity is shared; if it runs out, the run falls back to our own Lighthouse servers, and stops with a free not_measured row for the rest only if those cannot measure either. With your own free Google key you get 25,000 measurements per day.

FAQ

Does the Actor collect usage data? The Actor sends one anonymous usage counter per run (input type, item count range, outcome) to improve the tool; no URLs, content or account data.

Do I need a Google API key? No. Leave "Your Google API key" empty. If you add your own free key (Google Cloud console, enable the PageSpeed Insights API), Google is called directly with it; the price is the same.

Why is the lab LCP slow but Core Web Vitals PASSED? Lab metrics come from one Lighthouse run on an emulated slow phone; Core Web Vitals come from real Chrome users over 28 days, usually on faster devices and networks. Google uses the real-user data for ranking; the lab data shows what to fix.

Is this the same as pagespeed.web.dev? Yes: with source "auto" or "google" it is the same Google PageSpeed Insights API that powers pagespeed.web.dev, run for every URL in your list.

What happens if I make a mistake in the input? Nothing is measured and nothing is charged: the run ends normally (not as "failed") with one free row, errorType: "invalid_input", that says what to fix (no URLs, an unknown device or source, a threshold that is not a number, a Google API key that does not look like one). A single bad line in a list (not a web address, an ftp:// link, a number, or a private or local address such as localhost, 127.0.0.1 or 192.168.x.x, which Google cannot load) becomes its own free invalid_input row, nothing is sent for it, and the other URLs are measured. Through the API, yes/no options also accept "true"/"false", "yes"/"no" and 1/0, and device, source and categories are read in any case ("Desktop", "SEO, best practices"); a number option that is not a number uses its default and is listed in SUMMARY.inputNotes.

What if Google's quota runs out or my API key is wrong? The run stops cleanly: the page that hit the limit gets a free quota_exceeded (or invalid_api_key) row, every URL after it a free not_measured row that says what to do (add your own free Google API key, or fix the key), and measurements already done keep their rows and charges.

Do you respect robots.txt? Google's and our Lighthouse servers load each page the way a visitor's browser would; the Actor itself fetches only the API and your URL-list files, and measures only public pages you list.

Can I check many pages of one site? Yes, paste or upload the list. To find a site's pages first, run Sitemap URL Extractor and feed its URLs here.

How do I get alerts when a page gets slower? Turn on "Only output regressions", create an Apify schedule (daily or weekly), and add an Apify integration (email, Slack, webhook) that fires when the dataset is not empty.