To automate website audits, run them in two places. Run Lighthouse CI on every deploy, so regressions fail the build before they go live. Run a scheduled job against production that checks speed, SEO and security and reports changes. Use the PageSpeed Insights API for field data, and webhooks so results come to you instead of being polled for.
A manual audit is a snapshot. The site keeps changing after it: a new tracking script goes in, a plugin update drops a security header, a hero image gets replaced with a 4MB PNG. This guide shows how to build audits into your workflow with free tools first, and where a paid audit API fits. If you're not sure what a full audit covers, read what is a website audit. For a quick manual baseline of one thing deploys often break, run the free security headers checker now.
Key takeaways
- Lighthouse CI can run audits on every pull request and fail the build when scores or metrics such as LCP pass a threshold you set.
- The PageSpeed Insights API works without a key, but Google recommends one for automated use, and your daily quota is shown in Google Cloud console.
- Lab tools like Lighthouse cannot measure INP, so pair deploy checks with field data from the Chrome UX Report.
- Webhooks remove the need to poll, but receivers must verify the HMAC signature, reject stale timestamps and deduplicate retried deliveries.
Two kinds of automated audit
| On deploy | On a schedule | |
|---|---|---|
| Catches | Regressions in your own code and templates | Drift: third-party scripts, CMS updates, server and DNS changes |
| Runs against | A local build or staging URL | The live production site |
| Typical tools | Lighthouse CI in GitHub Actions or GitLab CI | PageSpeed Insights API, cron jobs, audit APIs, monitoring |
| Fails how | Blocks the merge or deploy | Sends an alert or opens a ticket |
You want both. Deploy checks only see what changed in your repository. Many slowdowns come from things that never touch it, such as a marketing tag added through Google Tag Manager.
On deploy: Lighthouse CI
Lighthouse CI runs Lighthouse against your build, repeats each URL to smooth out noise, checks the results against assertions, and uploads reports. The getting started guide uses the @lhci/cli package. A minimal GitHub Actions job:
name: Lighthouse CI
on: [pull_request]
jobs:
lhci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: 22.x
- run: npm ci && npm run build
- run: |
npm install -g @lhci/cli@0.15.x
lhci autorun
lhci autorun reads its settings from lighthouserc.js in the repository root:
module.exports = {
ci: {
collect: {
startServerCommand: 'npm run start',
url: ['http://localhost:3000/', 'http://localhost:3000/pricing'],
numberOfRuns: 3,
},
assert: {
assertions: {
'categories:performance': ['warn', { minScore: 0.85 }],
'categories:accessibility': ['error', { minScore: 0.9 }],
'categories:seo': ['error', { minScore: 0.9 }],
'largest-contentful-paint': ['warn', { maxNumericValue: 2500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
},
},
upload: { target: 'temporary-public-storage' },
},
};
Practical advice
- Start with warnings. CI runners are noisy, shared machines, so lab performance scores swing between runs. Use
warnfor performance until you know your normal range. Useerrorfor things that should never regress, such as accessibility, SEO basics and layout shift. - Assert on metrics, not just scores. A score drop can come from scoring changes in a new Lighthouse version. Our post on Lighthouse 13 and PageSpeed Insights changes covers the latest. An LCP threshold of 2.5 seconds means the same thing across versions.
- Know what lab tests can't see. Lighthouse loads a page without real user interaction, so it can't measure Interaction to Next Paint. Total Blocking Time is the usual lab proxy. See Core Web Vitals explained for how the field thresholds work.
- Mind the storage.
temporary-public-storageis public: anyone with a report URL can open it, and it keeps no history. For private reports and build-to-build comparisons, run the open-source LHCI server yourself, or use the filesystem target and keep reports as build artefacts.
On a schedule: the PageSpeed Insights API
The PageSpeed Insights API runs Lighthouse on Google's infrastructure against a public URL. It also returns Chrome UX Report field data for the page and origin when Google has enough real-user traffic. That's the part a CI run can't give you.
curl -s "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://www.example.com/&strategy=mobile&category=PERFORMANCE&key=$PSI_KEY" \
| jq '{
lab_score: .lighthouseResult.categories.performance.score,
lab_lcp_ms: .lighthouseResult.audits["largest-contentful-paint"].numericValue,
field_lcp_p75: .loadingExperience.metrics.LARGEST_CONTENTFUL_PAINT_MS.percentile,
field_inp_p75: .loadingExperience.metrics.INTERACTION_TO_NEXT_PAINT.percentile,
field_overall: .loadingExperience.overall_category
}'
Things to know:
- API key. The API works without a key, but Google recommends one for frequent, automated queries. Create it in Google Cloud console and restrict it to the PageSpeed Insights API.
- Quota. Google's getting-started page doesn't state a figure. Your project's limit is shown in Google Cloud console under APIs & Services, then Quotas. It has commonly been 25,000 queries a day, with a per-minute cap, but check your own project rather than relying on that.
- Field data can be missing. Low-traffic pages often have no URL-level data. Fall back to
originLoadingExperiencefor the site as a whole. - Expect variation. Lab results come from Google's servers and change from run to run. Our explainer on why the PageSpeed score keeps changing covers this. Store results and alert on sustained changes, not single runs.
A simple setup: a nightly cron job (on a server, or a scheduled CI workflow) runs the request for your ten most important URLs, appends the results to a database or sheet, and posts a message to Slack or email when field LCP or the lab score moves past a threshold for three nights running.
Beyond speed: what else to check automatically
Speed is the easiest thing to automate, but deploys and updates break other things as often:
- Security headers removed by a server or CDN change. Run the security headers checker after infrastructure work.
- Status codes and redirects after URL changes. The HTTP status code checker confirms key pages return 200.
- robots.txt and noindex accidentally carried over from staging. That's one of the most damaging and most common launch mistakes. The robots.txt tester catches the first; a full audit catches both.
- Broken links. Covered in our guide to automating broken link checks.
- Email authentication records after DNS moves.
You can script each of these yourself with curl and a few assertions. Or you can use a service that runs the whole audit and hands you the result.
Webhooks: let results come to you
Audits take time, often 20 seconds to a few minutes. Instead of looping "is it done yet?", a webhook lets the audit service send your endpoint an HTTP POST when the job finishes. Any webhook receiver should do four things:
- Verify a signature. The sender signs the body with a shared secret (usually HMAC-SHA256). Recompute it and compare in constant time.
- Reject stale requests. If a timestamp is part of the signed material, refuse anything more than a few minutes old so a captured request can't be replayed.
- Deduplicate. Retries mean the same delivery can arrive twice. Store the delivery ID and ignore repeats.
- Respond fast. Return a 2xx straight away and do the heavy work in a background job.
Our audit API and webhooks
If you'd rather not assemble all of that yourself, MakeItFlow offers a website audit API on the Pro and Agency plans. It runs the same full audit as the dashboard, covering performance, SEO, security, email authentication and DNS. What it provides, as documented in our API reference:
- Bearer-token authentication. Create a token under Account, then API tokens, and send it in the
Authorizationheader. The token is shown once and stored as a hash. - Queue and read scans.
POST /api/v1/scansqueues an audit and returns202with a scan ID.GET /api/v1/scans/{id}?include=checksreturns the full breakdown when the status iscompleted. - Site crawls on Pro and Agency, via
/api/v1/crawls. - Signed webhooks for
scan.completed,scan.failedandbatch.completed. The request includesX-IBMB-Signature,X-IBMB-Timestampand a uniqueX-IBMB-DeliveryID. The signature issha256=plus an HMAC-SHA256 of{timestamp}.{raw body}using your endpoint's secret. Failed deliveries are retried four times with backoff.
Queueing an audit after a production deploy is one request:
curl -X POST https://makeitflow.si/api/v1/scans \
-H "Authorization: Bearer $IBMB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.example.com", "strategy": "mobile", "force": true}'
Without force, a recent audit of the same URL is reused rather than run again. On the receiving end, a Node.js handler verifies the webhook like this:
import crypto from 'node:crypto';
function verify(rawBody, headers, secret) {
const ts = headers['x-ibmb-timestamp'];
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(`${ts}.${rawBody}`)
.digest('hex');
const given = headers['x-ibmb-signature'] || '';
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) <= 300;
return fresh && given.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}
Use the raw request body exactly as received. Re-serialised JSON won't match the signature. API scans count towards the same daily allowance as dashboard scans, and the reference lists the rate limits.
Bulk audits for agencies
On the Agency plan, bulk website audits run up to 100 URLs in one batch, from a pasted list, a CSV upload or POST /api/v1/batches. Each URL gets its own full report. A batch.completed webhook fires when the batch finishes, so you can audit a whole client portfolio after a platform update and get one notification at the end. Our guide to website audits for agencies covers how agencies use this in sales and reporting.
If you don't need an API, Website Monitoring (Starter plan and up) re-scans saved sites daily or weekly and emails you the score change, with no code needed. It's audit monitoring, not uptime monitoring, so pair it with a separate uptime service if you need alerts the moment a site goes down.
A workflow that holds up
Putting it together for a typical small team:
- Pull request: Lighthouse CI with error-level assertions on accessibility, SEO and CLS, and warnings on performance.
- After deploy to production: one API call queues a full audit. The webhook posts the grade to your team chat, and someone looks if it dropped.
- Nightly: PageSpeed Insights API for key URLs, stored to watch field data trends.
- Weekly: scheduled full audits and a link check, reviewed in a short meeting or a single ticket.
Keep the alerts few and meaningful. An automated check that fires every day gets ignored, which is worse than not having it.
FAQ
Is the PageSpeed Insights API free?
Yes. There's no charge for the PageSpeed Insights API within its quota. It works without a key, but Google recommends an API key for automated use, and your project's daily and per-minute limits are shown in Google Cloud console under APIs & Services, then Quotas.
Why do Lighthouse scores differ between CI and PageSpeed Insights?
They run on different hardware, network conditions and locations, and PageSpeed Insights also shows field data from real Chrome users. CI runners are shared machines whose performance varies between runs. Compare each tool with itself over time rather than with the other.
Can Lighthouse CI measure Interaction to Next Paint?
No. INP needs real user interactions, which a lab page load doesn't have. Lighthouse reports Total Blocking Time as a lab proxy. For real INP, use field data from the Chrome UX Report, available through the PageSpeed Insights API, or your own real-user monitoring.
Should a failed audit block a deployment?
Block on things that are clear and stable, such as accessibility errors, missing titles, noindex on production or large layout shift. Lab performance scores are noisy on CI machines, so start them as warnings and only enforce thresholds once you know your normal variation.
How do I verify a webhook is genuine?
Recompute the HMAC signature over the exact raw body, and over the timestamp if the sender includes it, using your shared secret. Compare it with the received signature in constant time. Also reject old timestamps to stop replays, and deduplicate on the delivery ID because retries can send the same event twice.
Which plan includes the MakeItFlow audit API?
The REST API with bearer tokens and signed webhooks is included on Pro and Agency. Site crawls through the API are available on Pro and above, and batches of up to 100 URLs are Agency only. API scans use the same allowance as scans started from the dashboard.
Related reading
- Website Audit API: A Developer Guide to Scans and Webhooks: A developer's guide to using a site audit API: queue scans, poll or use webhooks, verify HMAC signatures, handle rate limits and run crawls and batches safely.
More guides for your industry
Free checklist (PDF)
Free web developers website checklist
31 practical checks for web developers: website speed and mobile, Google Business Profile and reviews, email security, booking and enquiry handling, and AI search visibility. Each one says why it matters, and many link to a free tool that checks it.
Written by the MakeItFlow team
We build the website audit these guides are based on. Every fact is checked against the primary sources listed above and this guide was last reviewed on 27 October 2026 . How we research and check
Check your own site in 30 seconds
Run a free audit covering speed, SEO, DNS, email authentication and security headers — and get a prioritised fix list.