Getting started
Install
npm install safi-studio-scanner
Node 18 or newer. The package is ESM only, so your project needs "type": "module" in package.json, or you import it dynamically from CommonJS.
The core install pulls in one dependency, cheerio. Nothing else.
Your first audit
import { audit } from "safi-studio-scanner";
const report = await audit("https://example.com");
console.log(report.score); // overall 0-100
console.log(report.pagesScanned); // how many pages were crawled
console.log(report.categories); // score, pass, fail, warn per category
By default it crawls up to 20 pages, 5 at a time, 3 levels deep from the start URL, and runs every static rule. Nothing is written to disk unless you write it.
Write a report to disk
The one-line helpers render the report for you.
import { writeFile } from "node:fs/promises";
import { auditToHtml, auditToMarkdown } from "safi-studio-scanner";
await writeFile("report.html", await auditToHtml("https://example.com"));
await writeFile("report.md", await auditToMarkdown("https://example.com"));
The HTML is one self-contained file: inline styles, no external assets, no build step. Open it in a browser or email it.
Just the number
import { auditScore } from "safi-studio-scanner";
const score = await auditScore("https://example.com");
if (score < 80) process.exit(1);
Audit a single page
Set maxPages to 1 and the crawl stops at the URL you gave it.
const report = await audit("https://example.com/pricing", { maxPages: 1 });
Pick your categories
// Only these two.
await audit("https://example.com", { only: ["core-seo", "security"] });
// Everything except the two that make extra network requests.
await audit("https://example.com", { skip: ["links", "images"] });
Category names are the first half of a rule id. The full list is in the rule catalog.
Add the rendered checks
Accessibility and Core Web Vitals need a rendered page. Either install a local browser:
npm install playwright @axe-core/playwright
npx playwright install chromium
const report = await audit("https://example.com", { browser: true });
Or use Google PageSpeed Insights and install nothing:
const report = await audit("https://example.com", {
psiKey: process.env.PSI_KEY,
psiMaxPages: 5,
});
Both paths are covered in rendered checks.
Read the findings
const report = await audit("https://example.com");
for (const page of report.pages) {
const problems = page.findings.filter((f) => f.status === "fail");
console.log(`${page.url}: ${page.score}/100, ${problems.length} failures`);
for (const f of problems) {
console.log(` [${f.severity}] ${f.title}: ${f.message}`);
if (f.fix) console.log(` fix: ${f.fix}`);
}
}
Next