Lighthouse & PageSpeed Audit: Bulk Core Web Vitals
Pricing
from $25.00 / 1,000 page auditeds
Lighthouse & PageSpeed Audit: Bulk Core Web Vitals
Run Google's open-source Lighthouse in Chrome on many URLs, without a PageSpeed API key. Get performance, accessibility, best-practices and SEO scores, LCP, CLS and TBT, top fixes, and alerts to Slack, Discord or a webhook when a score drops.
Pricing
from $25.00 / 1,000 page auditeds
Rating
0.0
(0)
Developer
Plainsource
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Security
Limited permissionsShare
What this Actor does
Lighthouse Page Speed Monitor runs Google's open-source Lighthouse (version 13.5.0) in Chrome for a list of URLs and returns one row per URL and device with:
- Performance, accessibility, best-practices and SEO scores (0 to 100)
- Lab metrics: Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), Total Blocking Time (TBT), First Contentful Paint (FCP), Speed Index and Time to Interactive (TTI)
- The top performance opportunities with their estimated savings
- The accessibility and SEO audits that failed
- The final URL after redirects and the Lighthouse version
- Optionally, a link to the full HTML or JSON Lighthouse report
It does not use the PageSpeed Insights API, so there is no Google API key to set up and no daily quota. Lighthouse runs inside the Actor.
It also works as a monitor. Every run saves the scores per URL and device, and the next run compares against them. When a score drops by more than the points you set, or LCP gets slower by more than the percentage you set, the row is marked regressed and the Actor can post a message to Slack, Discord or any webhook.
How it works
- Each URL is checked first: it must be a public http or https address, its robots.txt must allow it, and every redirect is checked the same way.
- Lighthouse loads the page in a fresh Chrome with the mobile or desktop settings that PageSpeed Insights also uses: an emulated Moto G Power on slow 4G for mobile, a 1350×940 screen on a fast connection for desktop, with simulated throttling.
- URLs are audited one at a time, so audits do not compete for the CPU.
- First run: the row status is
baselineand the scores are saved. - Later runs: the row status is
okorregressed, withscoreChanges(points up or down per category),lcpChangePercentand the previous scores.
Scores are saved in a key-value store named plainsource-lighthouse-page-speed-monitor-state in your Apify account, grouped by Watch list name. Use a different watch list name for each task so separate lists keep separate history. The last 30 audits per URL and device are kept there.
Accuracy: lab scores vary
Lighthouse lab scores move between runs even when nothing on the page changed. Network timing, server response time, ads and A/B tests all play a part. A performance score that moves 3 to 5 points between runs is normal; on pages with many scripts it can move more.
To get steadier numbers:
- Set Lighthouse runs per URL to 2 or 3. The row then reports the median run, chosen the way Lighthouse recommends (the run closest to the median FCP and TTI), and lists every run's performance score in
runPerformanceScores. - Keep the alert threshold at 10 points or more for performance.
- Compare runs of this Actor with each other. Scores also depend on the machine: on pages with heavy JavaScript, CPU speed changes TBT and the performance score.
What we measured in our tests (mobile, performance score):
| Page | Lighthouse CLI on a fast laptop (2 runs) | This Actor on Apify, 8 GB | This Actor on Apify, 4 GB |
|---|---|---|---|
| nodejs.org/en | 87, 88 | 75 | 54 |
| bbc.com/news | 59, 69 | 28 | 13 |
| wikipedia.org | 100, 100 | not run | 92, 100 |
Apify assigns CPU in proportion to memory, so the 8 GB default gives Chrome about two CPU cores, the minimum Lighthouse's own documentation recommends. With 4 GB (about one core) script-heavy pages score clearly lower, because the browser and Lighthouse share the core. Accessibility and SEO scores were the same as in the laptop runs for the pages we compared. Best practices can differ when a page loads different ads or third-party scripts per visit (bbc.com/news: 54 on the laptop, 77 on Apify).
Input
The only required field is URLs to audit. All settings:
| Field | Default | What it does |
|---|---|---|
URLs to audit (urls) | none | Full page URLs. Duplicates are removed. Up to 1,000 per run. |
Device (formFactor) | mobile | mobile, desktop, or both (two audits per URL). |
Categories (categories) | all four | Any of performance, accessibility, best-practices, seo. |
Lighthouse runs per URL (runsPerUrl) | 1 | 1 to 3. With more than one, the median run is reported. Each run is charged. Applies only when performance is in the categories; otherwise one run is made. |
Opportunities to list (maxOpportunities) | 5 | 0 to 20 performance opportunities per row, biggest saving first. |
Save the full report (saveReport) | none | none, html, json or both. The report is saved in the run's key-value store and linked from the row. |
Watch list name (stateKey) | default | Scores are saved and compared per watch list. Renaming starts a fresh baseline. |
Alert when a score drops by (scoreDropThreshold) | 10 | Points. Any category that drops this much marks the row regressed. |
Alert when LCP rises by (lcpIncreasePercent) | 25 | Percent. LCP must also be at least 100 ms slower. |
Webhook URL (webhookUrl) | empty | An https URL that gets a POST when at least one page regressed. |
Webhook format (webhookFormat) | json | json (the regressed rows without the opportunity and failed-audit lists), slack or discord (a readable message). |
Also notify about pages that failed (notifyOnErrors) | false | Also send the message when pages could not be audited, and list them. |
Respect robots.txt (respectRobotsTxt) | true | Skips pages the site's robots.txt disallows. Turn off only for sites you own or may test. |
Timeout per Lighthouse run (timeoutSecs) | 90 | 60 to 300 seconds. A run that takes longer is reported as failed and not charged. |
Example input that audits three pages on mobile and desktop, three runs each, and posts regressions to Slack:
{"urls": ["https://www.example.org/", "https://www.example.org/pricing", "https://www.example.org/blog/"],"formFactor": "both","runsPerUrl": 3,"saveReport": "html","stateKey": "example-site","scoreDropThreshold": 10,"lcpIncreasePercent": 25,"webhookUrl": "https://hooks.slack.com/services/XXX/YYY/ZZZ","webhookFormat": "slack"}
Output
One row per URL and device in the dataset. This is a real row from a test run on Apify (8 GB, first audit of this URL):
{"url": "https://nodejs.org/en","formFactor": "mobile","status": "baseline","performance": 75,"accessibility": 100,"bestPractices": 100,"seo": 100,"lcpMs": 3655,"cls": 0.029,"tbtMs": 568,"fcpMs": 1255,"speedIndexMs": 1255,"ttiMs": 3655,"regressions": [],"scoreChanges": null,"lcpChangePercent": null,"previousScores": null,"previousLcpMs": null,"previousAuditedAt": null,"opportunities": [{"id": "unused-javascript","title": "Reduce unused JavaScript","displayValue": "Est savings of 250 KiB","lcpSavingsMs": 1200,"savingsKiB": 250},{"id": "render-blocking-insight","title": "Render-blocking requests","displayValue": "Est savings of 140 ms","lcpSavingsMs": 150,"fcpSavingsMs": 150},{"id": "legacy-javascript-insight","title": "Legacy JavaScript","displayValue": "Est savings of 14 KiB"}],"failedAccessibilityAudits": [],"failedSeoAudits": [],"finalUrl": "https://nodejs.org/en","lighthouseVersion": "13.5.0","runs": 1,"runPerformanceScores": [75],"reportUrl": null,"reportJsonUrl": null,"blockedRequests": 0,"benchmarkIndex": 3274,"warnings": [],"auditedAt": "2026-10-26T20:24:56.084Z","error": null}
On a later run, a regressed row has the reasons in regressions, for example "Accessibility dropped 6 points (100 to 94)" and "LCP rose 140% (0.60 s to 1.44 s)", and scoreChanges such as {"performance": -1, "accessibility": -6, "bestPractices": 0, "seo": 0}.
Field notes:
failedAccessibilityAuditsandfailedSeoAuditslist up to 15 failed audits each, as{ id, title, elements }, whereelementsis the number of page elements or items the audit flagged.- Opportunity savings are Lighthouse's own estimates:
lcpSavingsMs,fcpSavingsMs,tbtSavingsMs,clsSavingsandsavingsKiBappear when Lighthouse gives them. benchmarkIndexis Lighthouse's CPU benchmark for the machine that ran the audit. Lighthouse warns when it is below 1000.blockedRequestscounts requests the page tried to make to private or local addresses, which the Actor stops (see below).warningsholds Lighthouse's own run warnings and notes from the Actor.
status is one of:
baseline: first audit under this watch list, scores savedok: compared with the previous run, nothing dropped past your thresholdsregressed: seeregressionsfailed,site_blocked,not_allowed,skipped: the reason is inerror
The run also writes a summary to the OUTPUT record of its key-value store, with counts per status and the list of regressed pages.
Pricing
You pay per event, not for compute time:
| Event | Price |
|---|---|
| Run start | $0.002 per GB of run memory, so $0.016 per run at the default 8 GB |
| Page audited | $0.025 per Lighthouse run of one URL on one device |
both devices count as two audits per URL, and Lighthouse runs per URL multiplies the count: 10 URLs on mobile and desktop with 3 runs each are 60 audits. Not charged: pages that failed, timed out, were blocked, or were not allowed by robots.txt. Webhook messages and saved reports have no event price.
Example: 20 URLs on mobile, one run each, once a day, costs about 30 × (0.016 + 20 × 0.025) = $15.48 a month.
If a run reaches the maximum cost you set, the remaining URLs are marked skipped and their saved scores are kept.
Scheduling and alerts
- Schedule: create a task with your URLs, then add it to a schedule in Apify Console (Schedules, then Create new). Each run compares with the previous one.
- Slack: create an incoming webhook in Slack, paste its URL into Webhook URL, and set the format to Slack message.
- Discord: in the channel settings, open Integrations, then Webhooks, then New Webhook, and copy the URL. Set the format to Discord message.
- Other apps: send JSON to Zapier, Make or n8n, or use the task's Integrations tab in Apify Console.
The webhook is called only when at least one page regressed (or, with Also notify about pages that failed, when a page failed). Page-derived text is escaped, so a page cannot ping a whole Slack or Discord channel.
Limits and good manners
- One URL at a time. Lighthouse needs the CPU to itself, so audits run one after another. In our tests most audits took 8 to 30 seconds; very heavy pages can take a minute or reach the timeout.
- Memory: 8 GB by default (two CPU cores). 4 GB works and costs less per minute, but script-heavy pages score lower (see the accuracy table), and our 4 GB test run peaked at 3.4 GB of memory.
- Robots.txt is respected by default. If a site sets a
Crawl-delay, audits of that site are spaced by it. Chrome's user agent ends withPlainsourceLighthouseMonitor/1.0 (+https://apify.com/fernandosord/lighthouse-page-speed-monitor). - No proxies, logins or bot-check workarounds. Pages that require a login or block automated visitors are reported as
site_blockedand are not charged. LinkedIn, Facebook, Instagram, X and TikTok pages are not audited, because their terms forbid automated access. - Private networks are refused. URLs on private or local addresses (such as
localhost,10.x.x.x,[::ffff:7f00:1]or names that resolve to them) are refused, including through redirects. While Lighthouse runs, all of Chrome's traffic goes through a filter inside the Actor that resolves every host itself and stops requests to private and local addresses, so a page cannot reach them through a JavaScript redirect, fetch, XHR, iframe, image, websocket or worker either. - Pages only. PDFs, images and other files are reported as
failed; Lighthouse audits HTML pages. - Lab data only. This Actor does not return Chrome UX Report field data (real-user metrics), which comes from Google's API.
FAQ
Why is my score different from PageSpeed Insights? Both run Lighthouse with the same mobile and desktop settings, but on different machines and from different locations, and each run varies. Use 3 runs per URL for steadier numbers and compare this Actor's runs with each other. The accuracy section above shows what we measured.
Why does the performance score change when I changed nothing? That is normal lab variance (see above). Raise Alert when a score drops by, or use 2 or 3 runs per URL so the median smooths it out.
Can I see the full Lighthouse report? Set Save the full report to html. Each row gets a reportUrl with the same report Chrome DevTools shows.
I got site_blocked. Can you get around it? No. The site refused automated visitors, and this Actor respects that. Audit pages you own, or ask the site owner to allow the user agent above.
How do I start over? Change the Watch list name. The next run saves a new baseline.
Can I call it from code or an AI agent? Yes. Use the Apify API or the Apify MCP server with the same input. For example, with the API client: client.actor("fernandosord/lighthouse-page-speed-monitor").call({ urls: [...] }).
Lighthouse is developed by Google and published under the Apache 2.0 licence. This Actor is not made by or affiliated with Google.
Found a bug or need an option? Open an issue on this Actor's Issues tab.