# Bulk PageSpeed & Core Web Vitals Checker: Lighthouse + CrUX (`stellalytics/core-web-vitals-pagespeed-checker`) Actor

Bulk PageSpeed Insights checker: Lighthouse performance, SEO and accessibility scores for many URLs, plus real-user Core Web Vitals (LCP, INP, CLS) from the Chrome UX Report with pass/fail, a 6-month trend and alerts when a page gets worse. Your own free Google API key; demo without one.

- **URL**: https://apify.com/stellalytics/core-web-vitals-pagespeed-checker.md
- **Developed by:** [Abir Riahi](https://apify.com/stellalytics) (community)
- **Categories:** SEO tools, Developer tools
- **Features:** Limited permissions
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 page testeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bulk PageSpeed & Core Web Vitals Checker: Lighthouse scores, CrUX real-user data and trends

**Bulk PageSpeed Insights: test hundreds of pages in one run, and see whether real visitors pass Core Web Vitals.** For every page and device you get the four Lighthouse scores, lab metrics, the real-user (field) LCP, INP and CLS with a pass or fail verdict, a 6-month field-data trend, the biggest fixes, and alerts when a page gets worse since your last run. Made for SEO agencies, web developers and site owners who check speed for many pages or many clients.

It uses Google's **official PageSpeed Insights API and Chrome UX Report (CrUX) API with your own free Google API key**. Google loads each page from its own servers, exactly like pagespeed.web.dev. No scraping, no browser in the Actor, no proxies.

### What you get

One row per URL and device:

| Field | Example | Meaning |
| --- | --- | --- |
| `url`, `strategy` | `https://web.dev/`, `mobile` | The page and the device it was tested as |
| `performanceScore` | `87` | Lighthouse performance score, 0 to 100 |
| `accessibilityScore`, `bestPracticesScore`, `seoScore` | `96`, `100`, `92` | The other Lighthouse scores (the categories you choose) |
| `coreWebVitals` | `passed` | Real-user assessment: `passed`, `failed` or `not enough data` |
| `fieldDataFrom` | `url` | Whether field data is for this exact URL or, when the URL has too little traffic, for the whole site (`origin`) |
| `lcpMs`, `inpMs`, `cls` | `2100`, `150`, `0.04` | 75th-percentile real-user values over the last 28 days |
| `fieldUrl`, `fieldOrigin` | `{ "lcpMs": 2100, "ratings": { "lcp": "good" } }` | Full field data (LCP, INP, CLS, FCP, TTFB) for the URL and the whole site, each rated good, needs improvement or poor |
| `fieldTrend` | `{ "trend": { "lcp": "improving" }, "p75": { "lcp": [2600, …, 2100] } }` | Weekly 75th-percentile history for about 6 months (CrUX History API), and whether each metric is improving, stable or worsening |
| `labLcpMs`, `labFcpMs`, `labTbtMs`, `labCls`, `labSpeedIndexMs`, `labServerResponseMs` | `2900`, `1200`, `180`, `0.02`, `2400`, `120` | Lab metrics from this Lighthouse run |
| `opportunities` | `[{ "title": "Reduce unused JavaScript", "estimatedSavingsMs": { "LCP": 450 } }]` | Up to 5 failed performance audits, biggest estimated saving first |
| `failedSeoAudits`, `failedAccessibilityAudits` | `["Document does not have a meta description"]` | Failed checks in those categories |
| `changes`, `alerts` | `["Core Web Vitals assessment changed from passed to failed."]` | What changed since the last run of the same history |
| `error` | `HTTP 500: Lighthouse returned error: FAILED_DOCUMENT_REQUEST.` | Only on rows Google could not test (never charged) |

A **SUMMARY** record in the run's key-value store gives the pass and fail counts, the average performance score per device, the 10 lowest-scoring pages and every page with an alert. The dataset has four views: Overview, Real-user field data, Fixes and failed checks, and Lab metrics.

#### Sample output

The shape of one row, taken from the free demo run (shortened). The lab scores come from Lighthouse's own sample report of a deliberately slow test page, and the field values are illustrative; with your key, every value is Google's live answer for your URL:

```json
{
  "url": "https://www.your-site.example/",
  "strategy": "mobile",
  "performanceScore": 32,
  "accessibilityScore": 75,
  "bestPracticesScore": 31,
  "seoScore": 75,
  "coreWebVitals": "failed",
  "fieldDataFrom": "url",
  "lcpMs": 2900,
  "inpMs": 180,
  "cls": 0.08,
  "fieldUrl": {
    "ratings": {
      "lcp": "needs-improvement",
      "inp": "good",
      "cls": "good",
      "fcp": "needs-improvement",
      "ttfb": "needs-improvement"
    }
  },
  "labLcpMs": 10885,
  "labTbtMs": 1055,
  "opportunities": [
    {
      "title": "Minimize main-thread work",
      "displayValue": "2.9 s",
      "estimatedSavingsMs": {
        "TBT": 1050
      }
    },
    {
      "title": "Render-blocking requests",
      "displayValue": "Est savings of 860 ms",
      "estimatedSavingsMs": {
        "FCP": 850
      }
    }
  ],
  "failedSeoAudits": [
    "Document does not have a meta description"
  ]
}
```

### Lab data and field data, in one sentence each

- **Lab data** is one Lighthouse test that Google runs now, on a simulated mid-range phone or a desktop. Scores move a few points between runs.
- **Field data** is what real Chrome users experienced over the last 28 days (the Chrome UX Report). It is what Google uses for the Core Web Vitals assessment in Search Console's Core Web Vitals report. Pages with little traffic have none, so the Actor falls back to the whole site's data and says so in `fieldDataFrom`.

### Use cases

- **Bulk site audit:** test every template or top landing page of a site (mobile and desktop) and sort by score.
- **Client reporting for agencies:** one saved task per client on a weekly schedule; alerts tell you which pages slipped.
- **Core Web Vitals monitoring:** the 6-month trend shows whether a release or a new script made real users' LCP or INP worse, before Search Console's report catches up.
- **Competitor benchmarking:** test your pages and your competitors' side by side.
- **Pre- and post-launch checks:** compare scores before and after a redesign with the `changes` field.

### How to use it

1. **Get a free Google API key** (about 2 minutes, no billing account needed): in [Google Cloud Console](https://console.cloud.google.com/apis/credentials), create a project, then **Create credentials → API key**. Enable the [PageSpeed Insights API](https://console.cloud.google.com/apis/library/pagespeedonline.googleapis.com) and, for the trend, the [Chrome UX Report API](https://console.cloud.google.com/apis/library/chromeuxreport.googleapis.com) on that project. We recommend restricting the key to those two APIs.
2. Paste your **URLs** (bare domains get `https://`).
3. Paste the key into **Google API key**. Apify stores it encrypted.
4. Choose **Devices** (mobile, desktop or both) and the **Lighthouse categories**.
5. Run it. For monitoring, add a weekly **schedule**: each run is compared with the previous one.

**Google's limits:** the free default quota is commonly about 25,000 PageSpeed tests per day and 400 per 100 seconds per Google Cloud project (check the Quotas page of your project), and Google documents 150 CrUX queries per minute. Each page takes Google 10 to 60 seconds to test, so 100 pages on one device take roughly 3 to 15 minutes at the default of 6 parallel tests. If your daily quota runs out, the Actor stops cleanly and says so.

### Pricing

- **This Actor:** a small fee per page and device tested (see the Pricing tab), plus Apify's standard start fee of $0.00005 per run. Pages Google could not test are never charged, and demo runs charge only that start fee.
- **Google:** the PageSpeed Insights and Chrome UX Report APIs are free within the limits above.

Set a **maximum cost per run** in Apify, and the Actor stops cleanly when it is reached.

### Automate it: schedules and integrations

- **Weekly monitoring:** in Apify Console, open **Schedules**, create a weekly schedule and add this Actor or a saved task. Use a different **History name** per client so their changes are tracked separately.
- **Send results where your team works:** under the **Integrations** tab you can connect Google Sheets, Slack, email, Make, Zapier, n8n or a webhook.
- **API:** start runs and download results with the Apify API or the official Python and JavaScript clients (see the **API** tab).
- **AI agents (MCP):** connect Claude, Cursor or any MCP client to Apify's MCP server at `https://mcp.apify.com?tools=stellalytics/core-web-vitals-pagespeed-checker`.

### Related Actors

- [Tech Stack & Domain Lookup](https://apify.com/stellalytics/website-domain-intelligence): tech stack, email provider, SPF/DMARC, registrar, domain age, SSL expiry and AI-crawler rules for a list of domains.
- [AI Search Visibility Tracker](https://apify.com/stellalytics/ai-search-visibility-tracker): whether ChatGPT, Perplexity and Claude mention and cite your brand.

### Limitations

- **A Google API key is required for live results.** Google no longer serves PageSpeed Insights requests without a key (we checked: keyless requests get a quota of 0). Google's API terms ask developers to keep their credentials to themselves and not to resell an API as-is, so each user brings their own free key instead of sharing ours.
- Lab scores vary a little between runs, like on pagespeed.web.dev. Use field data and trends for decisions.
- Pages behind a login, or sites that block Google's tester, return an error row (not charged).
- Field data and trends exist only for pages and sites with enough Chrome traffic.
- If a large list would run past the run's timeout, the Actor stops starting new tests a few minutes before it, saves the history and `SUMMARY`, and says so (`stoppedBeforeTimeout`). A test still running at the last minute is dropped and not charged. Raise the timeout in the run options for big lists.

### FAQ

**Can I try it without a key?** Yes. With no key it runs a demo with no per-page charge (only Apify's $0.00005 start fee): one illustrative row built from Lighthouse's own sample report of a deliberately slow test page, with made-up field data, marked `"demo": true`. It does not test your URLs.

**Does it store my API key?** No. The key is a secret input that Apify stores encrypted. The Actor sends it only to Google's APIs, in a request header, never writes it to the log or the dataset, and removes anything that looks like a Google API key from error messages.

**Is personal data collected?** No. The Actor sends the URLs you give it to Google and saves Google's aggregated test results. CrUX field data is anonymous and aggregated across many users.

**Can I use the data in client reports?** Yes. Field data comes from the Chrome UX Report, which Google publishes under CC BY 4.0: credit "Chrome UX Report by Google" when you republish it. The `SUMMARY` record includes that attribution line.

**Is this affiliated with Google?** No. PageSpeed Insights, Lighthouse, Chrome and Core Web Vitals are Google's names and are used only to say which APIs and metrics the Actor uses.

**Why does a page show `fieldDataFrom: origin`?** That URL has too little Chrome traffic for its own field data, so the result shows the whole site's data instead.

### Support

Open an issue on the Issues tab. Fixes for broken runs are a priority.

# Actor input Schema

## `urls` (type: `array`):

Pages to test, one per line. Bare domains get https:// added. Each URL and device is one PageSpeed test. At most 2,000 URLs per run.

## `googleApiKey` (type: `string`):

Your own free Google API key with the PageSpeed Insights API enabled (and the Chrome UX Report API for field-data trends). Create one in Google Cloud Console under APIs & Services, Credentials. No billing account is needed. Leave empty for a free demo on a sample report. The key is sent only to Google.

## `strategies` (type: `array`):

Test as a mobile phone, a desktop, or both. Each device is a separate test and result row.

## `categories` (type: `array`):

Scores to compute. Performance is always included.

## `includeTrend` (type: `boolean`):

Add the weekly 75th-percentile history of real-user LCP, INP, CLS, FCP and TTFB from the CrUX History API (about 6 months), and whether each is improving or worsening. Needs the Chrome UX Report API enabled for your key. Free.

## `trackChanges` (type: `boolean`):

Remember each page's results in a named key-value store in your Apify account and report changes and alerts (for example Core Web Vitals now failing, or a score drop of 10 points) on the next run. Made for scheduled runs.

## `historyName` (type: `string`):

Keep separate histories for different schedules or clients. Letters, digits, '-' and '\_'.

## `maxConcurrency` (type: `integer`):

How many PageSpeed tests run at once. Google's free default quota is about 400 tests per 100 seconds and 25,000 per day per Google Cloud project.

## Actor input object example

```json
{
  "urls": [
    "https://web.dev/",
    "https://developer.chrome.com/"
  ],
  "strategies": [
    "mobile"
  ],
  "categories": [
    "performance",
    "accessibility",
    "best-practices",
    "seo"
  ],
  "includeTrend": true,
  "trackChanges": true,
  "historyName": "default",
  "maxConcurrency": 6
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "https://web.dev/",
        "https://developer.chrome.com/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("stellalytics/core-web-vitals-pagespeed-checker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "urls": [
        "https://web.dev/",
        "https://developer.chrome.com/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("stellalytics/core-web-vitals-pagespeed-checker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "https://web.dev/",
    "https://developer.chrome.com/"
  ]
}' |
apify call stellalytics/core-web-vitals-pagespeed-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stellalytics/core-web-vitals-pagespeed-checker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Ljc203aDkG0XGLmTh/builds/VhIyGbzfyCKnZgmi1/openapi.json
