Bulk PageSpeed Auditor: Lighthouse and Core Web Vitals avatar

Bulk PageSpeed Auditor: Lighthouse and Core Web Vitals

Pricing

$8.00 / 1,000 url checkeds

Go to Apify Store
Bulk PageSpeed Auditor: Lighthouse and Core Web Vitals

Bulk PageSpeed Auditor: Lighthouse and Core Web Vitals

Audit a list of URLs with Google's official PageSpeed Insights API. Get Lighthouse scores, lab and real-user Core Web Vitals, and the top issues to fix, one row per URL and device. Failed audits are not charged.

Pricing

$8.00 / 1,000 url checkeds

Rating

0.0

(0)

Developer

Open Data Tools

Open Data Tools

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Bulk PageSpeed Auditor: Lighthouse and Core Web Vitals

This tool checks how fast and how well built a list of web pages is, using Google's official PageSpeed Insights service. For each page you get the four Lighthouse scores (Performance, Accessibility, Best practices and SEO, each out of 100), the main speed measurements, real-visitor Core Web Vitals where Google has them, and a short list of the biggest problems to fix. Paste in your URLs, choose mobile, desktop or both, and you get one row per page that you can sort, compare or export. You pay $0.008 for each page audited successfully on each device type, and failed audits are free.

Who it's for

  • Agencies and freelancers auditing client sites, or a prospect's site before a pitch.
  • Developers and site owners checking many pages at once instead of testing them one by one on the PageSpeed website.
  • SEO teams tracking Core Web Vitals across key landing pages, product pages or templates.
  • E-commerce and content teams comparing their pages with competitors' pages.

Why use it

  • Official Google data: results come from Google's PageSpeed Insights API, the same engine as the PageSpeed Insights website. Your pages are not scraped.
  • Many URLs in one run: add a list of pages and get every result in one table instead of testing them one at a time.
  • Four scores per page: Performance, Accessibility, Best practices and SEO, each from 0 to 100. Leave out the categories you don't need.
  • Lab and real-visitor numbers: lab measurements from a fresh test (such as Largest Contentful Paint and Total Blocking Time), plus Core Web Vitals from real Chrome users when Google has enough data for the page.
  • What to fix first: up to 10 failed checks per page, sorted by the estimated time they would save.
  • Mobile, desktop or both: choose one device type, or run both and get one row for each.
  • No charge for failures: a page that can't be audited gets a row with the error message, and you are not charged for it. You pay $0.008 only for each successful audit. One bad URL never stops the run.
  • Stays within your budget: set a maximum total charge for the run, and it stops auditing new URLs once that limit is reached.

How to use it

  1. Open the Actor in Apify Console and add the pages you want to check under URLs to audit. Each entry must start with http:// or https://.
  2. Choose a Strategy: Mobile (the default), Desktop, or Both. Both gives you two rows per page and costs twice as much.
  3. Optionally untick Categories you don't need. All four are selected by default.
  4. Click Start. Each page takes Google a few seconds to test, so larger lists take a few minutes.
  5. Open the Output tab. The overview shows the URL, device, status, the four scores and the key speed numbers for each page. Rows with status error include the reason. Export everything as JSON, CSV or Excel.
  6. To track scores over time, create a schedule under Schedules (weekly, for example) with the same input, and add an integration such as Google Sheets, Slack, Zapier or Make, or a webhook, to send the results on.

Pricing

You pay $0.008 for each page audited successfully on each device type. Rows with status error are not charged. You can set a maximum total charge for a run, and the run stops auditing new URLs once it is reached.

Example: auditing 100 pages on mobile costs $0.80. Auditing the same 100 pages on both mobile and desktop gives 200 rows and costs $1.60. Running that mobile audit once a week costs about $3.20 over four weeks.

API and reference

This section is for developers and AI agents. It lists every input and output field, an example record and code examples.

Summary

Sends each input URL to the Google PageSpeed Insights API v5 (https://www.googleapis.com/pagespeedonline/v5/runPagespeed) and writes one dataset row per URL and strategy. Each row contains the Lighthouse category scores (0 to 100), lab metrics, Chrome UX Report (CrUX) p75 field metrics when available, and up to 10 failed audits sorted by estimated savings. The Actor does not fetch the pages itself. Failed audits become status: "error" rows and are not charged. They do not fail the run unless no audit succeeded at all (for example when the shared daily quota is used up), in which case the run ends as Failed with the reason in the status message. SUMMARY is still saved.

Input

FieldTypeDefaultDescription
startUrlsarrayrequiredURLs to audit, as {"url": "..."} objects (plain strings are also accepted). Only http and https URLs on a public domain or public IP address are valid. Exact duplicates are removed. An invalid URL produces an error row without calling the API. An empty list fails the run.
strategymobile, desktop, bothmobileLighthouse device profile. both produces two rows per URL, each charged.
categoriesstring[]all fourAny of performance, accessibility, best-practices, seo. Scores for unselected categories are null.
maxConcurrencyinteger51 to 20. Number of PageSpeed API requests in parallel. Values outside the range are clamped.
apiKeystring (secret)noneOptional. A Google API key with the PageSpeed Insights API enabled. Leave empty to use the key configured on the Actor, which is shared and limited to 1,000 audits per run; if Google's shared daily quota runs out, the run stops and asks you to add your own key.

Output

One dataset row per URL and strategy.

FieldTypeDescription
urlstring or nullURL as given in the input. null if an entry had no url value
finalUrlstring or nullURL after redirects, as reported by Lighthouse. null on error rows
strategystringmobile or desktop
fetchedAtstringISO 8601 UTC time of the audit (time of the attempt on error rows)
performanceScoreinteger or null0 to 100
accessibilityScoreinteger or null0 to 100
bestPracticesScoreinteger or null0 to 100
seoScoreinteger or null0 to 100
lcpMsnumber or nullLab Largest Contentful Paint, ms
fcpMsnumber or nullLab First Contentful Paint, ms
clsScorenumber or nullLab Cumulative Layout Shift
tbtMsnumber or nullLab Total Blocking Time, ms
speedIndexMsnumber or nullLab Speed Index, ms
ttiMsnumber or nullLab Time to Interactive, ms
fieldLcpMsnumber or nullCrUX p75 Largest Contentful Paint, ms. null when Google has no field data
fieldInpMsnumber or nullCrUX p75 Interaction to Next Paint, ms
fieldClsScorenumber or nullCrUX p75 Cumulative Layout Shift
fieldOverallCategorystring or nullCrUX overall rating: FAST, AVERAGE or SLOW
topIssuesobject[]Up to 10 failed Lighthouse audits (score below 0.9), sorted by savingsMs descending (a missing saving counts as 0), then by score ascending, then by id. The metric audits behind the lab fields (LCP, TBT and so on) are left out because they are measurements, not fixes. Empty on error rows
topIssues[].idstringLighthouse audit ID, for example render-blocking-insight or unused-css-rules
topIssues[].titlestringAudit title
topIssues[].scorenumberAudit score, 0 to 1
topIssues[].displayValuestring or nullLighthouse summary, for example Est savings of 128 KiB
topIssues[].savingsMsnumber or nullEstimated time saving, ms. Taken from the audit's overall savings, or else the largest time-based metric saving (CLS savings are ignored). null if Lighthouse gives none
statusstringok or error
errorMessagestring or nullReason when status is error, otherwise null

Example record from a real run (Apify run on 21 October 2026, mobile). Values are as returned, except that topIssues is trimmed to the first 3 of its 10 entries. Lighthouse puts a non-breaking space before units in displayValue, shown here as \u00a0:

{
"url": "https://www.python.org",
"finalUrl": "https://www.python.org/",
"strategy": "mobile",
"fetchedAt": "2026-10-21T06:17:41.491Z",
"performanceScore": 83,
"accessibilityScore": 75,
"bestPracticesScore": 100,
"seoScore": 92,
"lcpMs": 3953,
"fcpMs": 2721,
"clsScore": 0.003,
"tbtMs": 9,
"speedIndexMs": 2721,
"ttiMs": 3953,
"fieldLcpMs": 1270,
"fieldInpMs": 88,
"fieldClsScore": 0,
"fieldOverallCategory": "FAST",
"topIssues": [
{
"id": "render-blocking-insight",
"title": "Render-blocking requests",
"score": 0,
"displayValue": "Est savings of 2,590\u00a0ms",
"savingsMs": 2600
},
{
"id": "unused-css-rules",
"title": "Reduce unused CSS",
"score": 0,
"displayValue": "Est savings of 128\u00a0KiB",
"savingsMs": 620
},
{
"id": "unused-javascript",
"title": "Reduce unused JavaScript",
"score": 0,
"displayValue": "Est savings of 59\u00a0KiB",
"savingsMs": 450
}
],
"status": "ok",
"errorMessage": null
}

The run's default key-value store gets a SUMMARY record with ok (integer), error (integer), keyless (boolean, true if the run had no API key at all) and stoppedEarly (string or null, "maximum total charge reached" when the charge limit stopped the run).

Charge limit: when a charge reports that the run's maximum total charge has been reached, no new audits start. URLs not yet started are skipped and get no row. Audits already in progress at that moment finish and their rows are saved.

Error handling: invalid URLs fail without an API request. This includes missing URLs, schemes other than http and https, localhost, hosts without a dot, reserved names (.invalid, .test, .localhost, .example, .local, .internal) and private or reserved IP addresses. HTTP 429, 500, 502, 503 and 504 responses are retried, up to 4 attempts in total. The wait follows the API's Retry-After header (capped at 60 seconds), or else 2, 4 and 8 seconds. Two cases are not retried: a 429 for the daily quota, and a "Lighthouse returned error" message, which means the page itself failed to load. Other API errors also give an error row straight away.

Pricing details

Pay per event: url-checked at $0.008, charged once for each row with status: "ok", so once per URL per strategy. Rows with status: "error" are not charged. The run stops starting new audits once the user's maximum total charge is reached.

Usage

Apify API (synchronous run, returns dataset items):

curl -X POST "https://api.apify.com/v2/acts/opendata-tools~bulk-pagespeed-auditor/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"startUrls": [
{"url": "https://example.com"},
{"url": "https://www.python.org"}
],
"strategy": "mobile",
"categories": ["performance", "seo"]
}'

Python (pip install apify-client):

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("opendata-tools/bulk-pagespeed-auditor").call(run_input={
"startUrls": [
{"url": "https://example.com"},
{"url": "https://www.python.org"},
],
"strategy": "both",
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item["status"] == "ok":
print(item["url"], item["strategy"], item["performanceScore"], item["lcpMs"])
else:
print(item["url"], item["strategy"], "error:", item["errorMessage"])

JavaScript (npm install apify-client):

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('opendata-tools/bulk-pagespeed-auditor').call({
startUrls: [
{ url: 'https://example.com' },
{ url: 'https://www.python.org' },
],
strategy: 'desktop',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) console.log(item.url, item.status, item.performanceScore, item.topIssues.length);

For recurring audits, create an Apify schedule with a fixed input and attach a webhook on ACTOR.RUN.SUCCEEDED to receive results.

Limits

  • Results come from Google's API, so Lighthouse scores vary a little from run to run, as they do on the PageSpeed Insights website.
  • Google can only test pages it can reach from the public internet. Pages behind a login, on a private network or blocking Google's tester return an error row.
  • Each PageSpeed API request times out after 150 seconds (retries can add more). The default run timeout is 30 minutes, so very long lists may need a longer timeout or to be split into several runs.
  • Field data (field* fields) comes from the Chrome UX Report and is null for pages without enough real-visitor traffic.

FAQ

Do I need my own Google API key?

No. Leave PageSpeed API key empty and the Actor uses its own key. If you have a Google API key with the PageSpeed Insights API enabled, you can enter it, and requests then count against your own Google quota.

Why do some rows have status error?

The row's errorMessage gives the reason, for example an invalid or private URL, a page Google could not load, Google's daily quota being used up, or Google's API being busy after all retries. Error rows are not charged.

Why are the field data columns empty?

Real-visitor data comes from Google's Chrome UX Report, which only covers pages with enough Chrome traffic. Newer or low-traffic pages have no field data, so those fields are null. The lab scores and measurements are still filled in.

Does it crawl my site to find pages?

No. It audits exactly the URLs you give it. Add every page you want checked to URLs to audit.

What happens when my maximum total charge is reached?

The run stops starting new audits. Pages already being tested finish and are saved, the rest are skipped with no row, and the run's SUMMARY record shows stoppedEarly. Run again with the skipped URLs to finish the list.

Why is Both twice the price?

Mobile and desktop are separate Lighthouse tests with separate results, so each device type gives its own row and its own $0.008 charge. A page audited on both costs $0.016.

Issues and feature requests: use the Issues tab.