You can't fix what you don't measure. Most teams check page speed occasionally — run Lighthouse on the homepage, feel good, move on. Meanwhile, three product pages and two blog posts are loading in 4+ seconds and quietly tanking conversion.
Here's a script that checks every page you care about, flags the slow ones, and can run automatically every week in GitHub Actions.
What the SnapAPI analyze endpoint returns
The /v1/analyze endpoint runs a real Chromium browser against any URL and returns structured data — including load_time_ms, which is the time from request start to networkidle (fully loaded, no pending requests).
// npm install snapapi-sdk
const { SnapAPI } = require('snapapi-sdk');
const client = new SnapAPI(process.env.SNAPAPI_KEY);
const data = await client.analyze('https://yoursite.com/pricing');
console.log(data.load_time_ms); // e.g. 2341
console.log(data.word_count); // e.g. 1847
console.log(data.technologies); // ["React", "Vercel", "Cloudflare"]
console.log(data.primary_cta); // "Start free trial"
One call. Real browser. No Lighthouse CLI, no Puppeteer setup, no browser binary in CI.
The monitoring script
// page-performance-monitor.js
// Checks a list of pages and flags any with load_time > threshold.
// Usage: SNAPAPI_KEY=key node page-performance-monitor.js
const { SnapAPI } = require('snapapi-sdk');
const fs = require('fs');
const client = new SnapAPI(process.env.SNAPAPI_KEY);
const THRESHOLD = 3000; // ms — flag any page over 3 seconds
const PAGES = [
{ url: 'https://yoursite.com', label: 'Homepage' },
{ url: 'https://yoursite.com/pricing', label: 'Pricing' },
{ url: 'https://yoursite.com/features', label: 'Features' },
{ url: 'https://yoursite.com/blog', label: 'Blog index' },
// add more...
];
async function checkPage({ url, label }) {
try {
const data = await client.analyze(url, { screenshot: false });
return {
label, url,
load_ms: data.load_time_ms,
word_count: data.word_count,
technologies: data.technologies,
primary_cta: data.primary_cta,
slow: data.load_time_ms > THRESHOLD,
};
} catch (err) {
return { label, url, error: err.message, slow: false };
}
}
async function main() {
console.log(`Checking ${PAGES.length} pages (threshold: ${THRESHOLD}ms)...\n`);
const results = await Promise.all(PAGES.map(checkPage));
const slow = results.filter(r => r.slow);
const errors = results.filter(r => r.error);
// Print results table
console.log('Page'.padEnd(20), 'Load (ms)'.padEnd(12), 'Words'.padEnd(8), 'Status');
console.log('-'.repeat(60));
for (const r of results) {
const status = r.error ? '⚠ ERROR' : r.slow ? '🔴 SLOW' : '✅ OK';
const load = r.error ? 'N/A' : String(r.load_ms);
console.log(r.label.padEnd(20), load.padEnd(12), String(r.word_count || '').padEnd(8), status);
}
console.log(`\n${slow.length} slow page(s), ${errors.length} error(s)`);
// Save JSON results for GitHub Actions / Slack
const output = { checked_at: new Date().toISOString(), results, slow_count: slow.length };
fs.writeFileSync('performance-results.json', JSON.stringify(output, null, 2));
if (slow.length > 0) process.exit(1); // fail CI if slow pages found
}
main().catch(err => { console.error(err.message); process.exit(1); });
Sample output:
Checking 4 pages (threshold: 3000ms)...
Page Load (ms) Words Status
------------------------------------------------------------
Homepage 1842 1204 ✅ OK
Pricing 2341 987 ✅ OK
Features 3891 2103 🔴 SLOW
Blog index 4102 3847 🔴 SLOW
2 slow page(s), 0 error(s)
Add it to GitHub Actions
# .github/workflows/page-speed.yml
name: Weekly Page Speed Check
on:
schedule:
- cron: '0 9 * * 1' # Every Monday at 9am
workflow_dispatch: # Also allows manual trigger
jobs:
check-speed:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm install snapapi-sdk
- name: Run page speed check
run: node page-performance-monitor.js
env:
SNAPAPI_KEY: ${{ secrets.SNAPAPI_KEY }}
- name: Post to Slack if slow pages found
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: '{"text": "⚠️ Slow pages detected in weekly speed check. Check the Actions log."}'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Now every Monday at 9am, the workflow runs. If any page exceeds 3 seconds, the step fails and Slack gets a message. Fix the page, push, see the green check.
What else the analyze endpoint gives you
load_time_ms is one field. The full response is useful for page health audits beyond just speed:
| Field | What it tells you |
|---|---|
word_count |
Content depth — blog posts under 300 words rarely rank |
technologies |
Tech debt signal — 5+ marketing pixels? Check your bundle |
primary_cta |
Is the CTA present after a deploy? Assert it in CI |
navigation |
Did a nav item disappear? Catch it before users do |
forms |
Sign-up form still rendering on the pricing page? |
You can write assertions for any of these alongside the speed check:
// Assert the pricing page CTA is still there after deploy
if (!data.primary_cta || !data.primary_cta.toLowerCase().includes('free')) {
console.error('FAIL: Pricing page CTA missing or changed');
process.exit(1);
}
Compared to running Lighthouse manually
| This script | Manual Lighthouse | |
|---|---|---|
| Setup | npm install snapapi-sdk |
CLI install + Chrome config |
| Run all pages | Promise.all() |
One at a time |
| CI integration | 10 lines of YAML | Custom Docker image |
| Structural data (CTA, nav) | Included | Not available |
| Screenshot | Optional param | Separate run |
| Cost | Free tier: 100 pages/month | Free |
The main difference: this gives you real browser load time plus structural page health in one call. Lighthouse gives you more granular network waterfall data. Use both if you need the waterfall; use this if you need automated monitoring across many pages.
Free API key
100 calls/month, no credit card, active in 30 seconds.
Top comments (0)