# PageSpeed Insights Batch Monitor (`automation-lab/pagespeed-insights-monitor`) Actor

Run batch PageSpeed Insights checks, normalize Lighthouse and available field metrics, and flag performance regressions against previous audits.

- **URL**: https://apify.com/automation-lab/pagespeed-insights-monitor.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## PageSpeed Insights Batch Monitor

Run **PageSpeed Insights** checks for a list of public pages and receive normalized Lighthouse scores, lab metrics, available Chrome UX Report field data, optimization opportunities, and timestamped regression deltas.

The Actor tries Google's PageSpeed Insights v5 API first. If anonymous quota is exhausted or the API is unavailable, it automatically runs Lighthouse in headless Chrome. That fallback keeps scheduled website performance monitoring useful without requiring a Google API key.

### What does PageSpeed Insights Batch Monitor do?

For every URL and selected device strategy, the Actor:

1. validates that the target is a public HTTP or HTTPS page;
2. requests a PageSpeed Insights report;
3. retries only temporary API failures with bounded backoff;
4. falls back to autonomous Lighthouse when allowed;
5. normalizes API and fallback reports into one output shape;
6. stores the latest result for that URL and device;
7. compares the new result with the previous stored result;
8. saves one charged dataset item.

A result includes performance, accessibility, best-practices, and SEO scores when those categories are requested. It also includes common lab metrics such as Largest Contentful Paint, Total Blocking Time, Cumulative Layout Shift, and Speed Index.

### Who is it for?

This Actor is useful for:

- developers checking performance before and after a deployment;
- SEO teams auditing mobile and desktop pages in a batch;
- agencies monitoring client landing pages;
- product teams watching Core Web Vitals-related regressions;
- QA teams adding performance checks to release workflows;
- data teams exporting normalized audits to a warehouse;
- operators scheduling repeat checks with Apify Tasks.

Choose it when you need structured records and repeat comparisons rather than an interactive one-page report.

### Why use this PageSpeed checker?

#### Batch input

Submit up to 100 real public URLs and select mobile, desktop, or both.

#### One stable schema

PageSpeed API and local Lighthouse results use the same fields, so downstream integrations do not need two parsers.

#### Automatic regression context

Repeated runs compare each URL/device pair with its previous stored result. The output shows score-point changes, lab-metric percentage changes, threshold-crossing regressions, and improvements.

#### Credential-free fallback

A Google API key is optional. Headless Lighthouse provides lab data when PageSpeed API quota is unavailable.

#### Field data when available

When the Google API returns Chrome UX Report coverage, the Actor includes URL-level or origin-level field metrics. It does not invent field data on fallback runs.

### What data does it return?

| Field | Meaning |
| --- | --- |
| `url` | Requested normalized URL |
| `finalUrl` | Final page after redirects |
| `strategy` | `mobile` or `desktop` |
| `source` | `pagespeed-api` or `lighthouse-fallback` |
| `checkedAt` | Timestamp reported by Lighthouse |
| `lighthouseVersion` | Audit engine version |
| `scores` | Category scores from 0 to 100 |
| `labMetrics` | Synthetic Lighthouse metrics and units |
| `fieldMetrics` | Available Chrome UX Report metrics, otherwise `null` |
| `fieldDataScope` | Exact `url`, `origin`, or `null` |
| `opportunities` | Up to 10 optimization opportunities |
| `regression` | Changes from the previous stored audit |
| `warnings` | Bounded Lighthouse warnings |

Each dataset item represents one URL and one device strategy.

### Getting started

1. Open the Actor input page.
2. Add one or more public URLs.
3. Choose `mobile`, `desktop`, or both.
4. Keep all Lighthouse categories selected for a complete audit.
5. Optionally provide a Google API key with PageSpeed Insights API access.
6. Leave **Use Lighthouse fallback** enabled for resilient lab metrics.
7. Click **Start**.
8. Open the **Audit results** dataset view.
9. Run the same input again to populate `regression`.

The first check has `regression: null` because no earlier baseline exists.

### Input parameters

#### `urls`

Required array of 1–100 public HTTP(S) pages. Duplicate strings are removed. URLs containing credentials, localhost names, or private-network addresses are rejected.

#### `strategies`

Device profiles to test. Default: `mobile`.

Allowed values:

- `mobile`
- `desktop`

Selecting both produces two results per URL.

#### `categories`

Lighthouse categories to calculate:

- `performance`
- `accessibility`
- `best-practices`
- `seo`

An unrequested score is returned as `null`, preserving a predictable schema.

#### `usePageSpeedApi`

Default: `true`. Requests Google's v5 endpoint first, which can include Chrome UX Report field metrics.

#### `apiKey`

Optional secret Google API key. The Actor sends it only to Google's API. It is not written to logs, datasets, or comparison state.

#### `lighthouseFallback`

Default: `true`. Runs Lighthouse in headless Chrome if the API is disabled, rate-limited, or otherwise unavailable.

#### `cacheTtlMinutes`

Default: `15`. Reuses only a recent successful API response for an immediate repeat check. Set it to `0` when every scheduled run must request fresh API data.

#### `regressionThreshold`

Default: `5`. A category score drop of at least this many points is a regression. A lab metric increase of at least this percentage is also a regression because higher timing values are worse.

#### `maxItems`

Maximum URL/device records saved, from 1 to 200. The Actor stops before scheduling additional audits after this limit.

### Example input: batch mobile audit

```json
{
  "urls": [
    { "url": "https://www.apify.com/" },
    { "url": "https://crawlee.dev/" }
  ],
  "strategies": ["mobile"],
  "categories": ["performance", "accessibility", "best-practices", "seo"],
  "maxItems": 2
}
```

### Example input: mobile and desktop comparison

```json
{
  "urls": [{ "url": "https://www.apify.com/" }],
  "strategies": ["mobile", "desktop"],
  "cacheTtlMinutes": 0,
  "regressionThreshold": 5,
  "maxItems": 2
}
```

### Example output

Values vary as pages, network conditions, Lighthouse, and Chrome change.

```json
{
  "url": "https://www.apify.com/",
  "finalUrl": "https://apify.com/",
  "strategy": "mobile",
  "source": "lighthouse-fallback",
  "checkedAt": "2026-01-15T12:00:00.000Z",
  "lighthouseVersion": "13.4.1",
  "scores": {
    "performance": 92,
    "accessibility": 96,
    "bestPractices": 100,
    "seo": 91
  },
  "labMetrics": {
    "firstContentfulPaint": { "value": 820, "unit": "millisecond", "displayValue": "0.8 s" },
    "largestContentfulPaint": { "value": 1350, "unit": "millisecond", "displayValue": "1.4 s" },
    "totalBlockingTime": { "value": 40, "unit": "millisecond", "displayValue": "40 ms" },
    "cumulativeLayoutShift": { "value": 0.02, "unit": "unitless", "displayValue": "0.02" }
  },
  "fieldMetrics": null,
  "fieldDataScope": null,
  "opportunities": [],
  "regression": null,
  "warnings": []
}
```

### How regression monitoring works

The default key-value store keeps one state record per normalized URL and strategy. A state record contains the latest normalized audit and, when applicable, a recent successful API response.

On the next run with the same storage:

- score changes are calculated in points;
- lab metric changes are calculated as percentages;
- score decreases are treated as worse;
- timing and layout-shift increases are treated as worse;
- changes crossing `regressionThreshold` receive readable labels.

For recurring monitoring, create an Apify Task and schedule it. Reusing the Task's storage preserves the comparison baseline. If you intentionally replace or purge the key-value store, the next result starts a new baseline.

### How much does it cost to monitor website performance?

Pay-per-event pricing has a **$0.005 run start** and one `item` event for each saved URL/device audit. The BRONZE item price is **$0.064477**; higher-volume tiers decrease through six distinct price levels.

At the BRONZE rate:

| Workflow | Results | Charge calculation |
| --- | ---: | --- |
| One URL, mobile | 1 | One start + one item event |
| Five URLs, mobile | 5 | One start + five item events |
| Ten URLs, mobile + desktop | 20 | One start + twenty item events |
| Twenty-five URLs, mobile + desktop | 50 | One start + fifty item events |

Multiply the active item tier by the result count, then add the one-time start price. The active tier for your account and platform pricing details determine the final charge. API field data, opportunities, and regression fields do not trigger separate events.

### Scheduling a recurring monitor

1. Save a successful Actor input as an Apify Task.
2. Set `cacheTtlMinutes` below the schedule interval, or use `0`.
3. Run the Task once to create a baseline.
4. Add an hourly, daily, or weekly schedule.
5. Add a webhook for successful or failed runs.
6. Read `regression.regressions` in your automation.
7. Notify your team only when the array is non-empty.

Lighthouse scores naturally vary. Use a threshold that avoids alerts for insignificant noise.

### Integration ideas

#### Release gate

Run a small URL list after deployment. Fail your downstream workflow if a performance score drops beyond your chosen threshold.

#### SEO reporting

Export mobile and desktop score histories to a spreadsheet or BI tool. Keep lab and field data separate because they measure different populations.

#### Agency portfolio

Use one Task per client or site group so comparison state remains easy to manage.

#### Slack or email alert

Use an Apify webhook, Make, or Zapier to inspect each result and send regression labels to the responsible team.

#### Data warehouse

Load the default dataset through its API. Use `url`, `strategy`, and `checkedAt` as the audit identity.

### Run with the Apify API

Replace `YOUR_TOKEN` with an Apify API token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~pagespeed-insights-monitor/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [{"url": "https://www.apify.com/"}],
    "strategies": ["mobile"],
    "maxItems": 1
  }'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/pagespeed-insights-monitor').call({
  urls: [{ url: 'https://www.apify.com/' }],
  strategies: ['mobile', 'desktop'],
  maxItems: 2,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/pagespeed-insights-monitor').call(run_input={
    'urls': [{'url': 'https://www.apify.com/'}],
    'strategies': ['mobile'],
    'maxItems': 1,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with Apify MCP

Add this Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/pagespeed-insights-monitor"
```

#### Claude Desktop

Add this server configuration to Claude Desktop:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/pagespeed-insights-monitor"
    }
  }
}
```

#### Cursor

Add the same HTTP MCP server URL in **Cursor Settings → MCP** and enable the `automation-lab/pagespeed-insights-monitor` tool.

#### VS Code

Add the HTTP MCP server URL to your VS Code MCP configuration, then start the `apify` server from the MCP panel.

Example prompts:

- “Run a mobile PageSpeed audit for apify.com and summarize the slowest lab metric.”
- “Compare mobile and desktop performance for this release URL.”
- “Run my saved monitoring input and list only threshold-crossing regressions.”

### Accuracy and interpretation tips

- Lab data is a synthetic test, not a promise of every user's experience.
- Field data describes real Chrome users but appears only when Chrome UX Report coverage is sufficient.
- URL-level field data may fall back to origin-level field data; check `fieldDataScope`.
- Mobile and desktop use different emulation and throttling profiles.
- Compare like with like: same URL, strategy, categories, and similar run environment.
- Treat small score changes as noise rather than a release failure.
- A redirect can change `finalUrl` while the state key remains based on the requested URL.

### Limits and failure behavior

- Up to 100 input URLs and 200 output records are accepted per run.
- Audits run sequentially to keep browser memory and target load bounded.
- A PageSpeed API 429 does not trigger repeated quota-consuming requests; fallback begins immediately.
- Temporary API 5xx responses receive at most two retries with jittered backoff.
- Private and local network targets are blocked to reduce SSRF risk.
- Pages requiring login are unsupported because the Actor does not accept cookies or credentials.
- A page can deny headless Chrome, time out, or fail Lighthouse; terminal audit errors fail the run instead of silently returning an empty dataset.
- Field metrics are `null` on local Lighthouse fallback results.
- The Actor does not send alerts by itself; use schedules and integrations.

### Troubleshooting

#### Why is `source` set to `lighthouse-fallback`?

The anonymous PageSpeed API often has no shared quota. The fallback is expected and still returns complete Lighthouse lab metrics. Provide your own enabled API key if you need available Chrome UX Report field data.

#### Why is `fieldMetrics` null?

Either the result used local Lighthouse, or Chrome UX Report does not have enough real-user data for that URL or origin.

#### Why is `regression` null?

The URL/device pair has no previous result in the current key-value store. Run the same Task again without replacing its storage.

#### Why did the Actor reject my URL?

Only resolvable public HTTP(S) pages are supported. Localhost, credentials in URLs, and private-network destinations are intentionally rejected.

#### Why do scores differ from a browser report?

Lighthouse version, hardware, network throttling, cookies, geography, page changes, and device strategy can affect scores. Compare trends from consistent scheduled inputs rather than expecting identical values across environments.

#### How can I reduce runtime?

Request only the strategy and categories you need, keep batches focused, and provide an API key if Google grants it sufficient quota. Each local fallback starts an isolated Chrome audit for reliability.

### Legality

Audit only public pages you are authorized to test. Respect website terms, access policies, and reasonable request rates. Do not use the Actor to probe private infrastructure or bypass authentication.

PageSpeed and Lighthouse results may influence engineering decisions, but accessibility, SEO, and security still require appropriate specialist testing. Store API keys as Actor input secrets and rotate exposed credentials.

### Related automation

This Actor is intentionally usable on its own. Apify Schedules, Tasks, webhooks, Make, Zapier, and dataset integrations provide the recurring and alerting workflow without requiring another Actor.

Only Automation Lab Store Actors are linked as related products. No same-portfolio Actor is currently required to produce or interpret these results.

### FAQ

#### Does it scrape pagespeed.web.dev?

No. It uses the underlying official PageSpeed Insights API when available and runs Lighthouse directly as a stable autonomous fallback.

#### Do I need a Google API key?

No for lab metrics. A key with PageSpeed Insights API quota improves access to field data and avoids anonymous quota exhaustion.

#### Can I monitor multiple domains?

Yes. Put pages from multiple public domains in `urls`, subject to the input and result limits.

#### Can I audit both mobile and desktop?

Yes. Select both strategies; that creates two item events per URL.

#### Does it return Core Web Vitals?

It returns Lighthouse lab equivalents and available Chrome UX Report field metrics, including LCP, CLS, and INP when the API supplies them. It clearly separates lab and field values.

#### Does it keep full history?

The dataset from each run is your timestamped history. The key-value state keeps the latest comparison record per URL/device pair, not an unlimited duplicate history.

#### Can I change the alert threshold?

Yes. Set `regressionThreshold` from 1 to 100. The same number is used as score points and lab-metric percentage.

#### Are failed audits charged as items?

No. The item event is emitted only after a valid normalized record is pushed. The one-time start event still applies.

#### Is the output suitable for CSV or Excel?

Top-level fields export normally, while nested scores, metrics, opportunities, and regression details are represented as structured JSON values. JSON is best for preserving all details.

# Actor input Schema

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

Public HTTP(S) pages to check. Duplicates are removed. Local and private-network addresses are rejected.

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

Run a mobile audit, desktop audit, or both. Each URL/strategy pair creates one result.

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

Categories to calculate. Unselected category scores are returned as null.

## `usePageSpeedApi` (type: `boolean`):

Uses Google's v5 API for lab and available field data. If quota is unavailable, the Actor can fall back to local Lighthouse.

## `apiKey` (type: `string`):

Optional key with PageSpeed Insights API access. It is sent only to Google's API and is never included in output or logs.

## `lighthouseFallback` (type: `boolean`):

Run headless Lighthouse autonomously when the PageSpeed API is disabled, rate-limited, or unavailable. Field metrics are null on fallback results.

## `cacheTtlMinutes` (type: `integer`):

Reuse a successful PageSpeed API response for an immediate repeated check. Set 0 for every run to request fresh data.

## `regressionThreshold` (type: `integer`):

Minimum score-point drop or lab-metric percentage increase that is labeled as a regression.

## `maxItems` (type: `integer`):

Maximum URL/strategy results to save, after input deduplication.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://www.apify.com/"
    },
    {
      "url": "https://crawlee.dev/"
    }
  ],
  "strategies": [
    "mobile"
  ],
  "categories": [
    "performance",
    "accessibility",
    "best-practices",
    "seo"
  ],
  "usePageSpeedApi": true,
  "lighthouseFallback": true,
  "cacheTtlMinutes": 15,
  "regressionThreshold": 5,
  "maxItems": 10
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing one record per URL and device strategy.

## `state` (type: `string`):

Key-value store containing the latest result and bounded API cache for each URL and strategy.

# 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": [
        {
            "url": "https://www.apify.com/"
        },
        {
            "url": "https://crawlee.dev/"
        }
    ],
    "strategies": [
        "mobile"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/pagespeed-insights-monitor").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": [
        { "url": "https://www.apify.com/" },
        { "url": "https://crawlee.dev/" },
    ],
    "strategies": ["mobile"],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/pagespeed-insights-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    {
      "url": "https://www.apify.com/"
    },
    {
      "url": "https://crawlee.dev/"
    }
  ],
  "strategies": [
    "mobile"
  ],
  "maxItems": 10
}' |
apify call automation-lab/pagespeed-insights-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/pagespeed-insights-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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