Back to devlogs
Typescript · Tools · Terminal Application

Building Safi Studio Scanner, a website audit tool that runs in the terminal

/ / 2 min read

How I built an open take on closed site auditors: 93 checks across 15 categories, a fast crawler, a themed HTML report, and an npm SDK. One runtime dependency at the core.

Safi Studio Scanner terminal report showing a website health score and audit categories
On this page

Why I built it

Most website auditors are closed, paid, and run only as a hosted service. I wanted one I could run from my own terminal, script into other projects, and change the rules on when I disagreed with them. So I built Safi Studio Scanner.

It crawls a site, audits every page against 93 rules across 15 categories, and exports one report as HTML, Markdown, or JSON.

What it checks

Fifteen categories run from fetched HTML and headers, no browser needed: Core SEO, content, links, images, structured data, security, crawlability, URL structure, social media, internationalization, legal, analytics, E-E-A-T, and a static slice of performance. Turn on the browser and it adds a full axe-core accessibility audit and real Core Web Vitals.

The decisions I care about

Keep the core tiny. The whole engine runs on one runtime dependency, cheerio, for HTML parsing. Everything heavy is optional. Playwright and the axe-core audit load lazily, only when you pass --browser. If you want Core Web Vitals without a local browser at all, a Google PageSpeed Insights provider runs Lighthouse on Google's side and hands back the numbers.

Crawl fast. A small concurrency pool fetches several pages at once with a breadth-first walk over same-origin links, capped by max pages and depth. No queue library, about ten lines of code.

Make rules cheap to add. Every rule is one small object with an id, a category, a severity, and a run(context) function. A registry collects them into one array, so a new rule is one file and one import. That is the path from a starter set toward broader coverage, one category at a time.

Score it honestly. Findings are weighted by severity into a health score per category and overall. I tuned the overall to be harsh, so a weak category pulls the headline number down instead of hiding in an average.

One file for the report. The HTML export is a single self-contained file with inline CSS and a dark and light toggle, styled in my own warm editorial theme. Findings group by category, then by rule, each one an expandable row that shows the issue, how to fix it, and which pages have it.

It is also an SDK

The CLI is a thin wrapper over a library, so the same engine imports into other projects. It installs straight from GitHub and exposes plain functions:

import { audit, auditToHtml, auditScore } from "safi-studio-scanner";

const report = await audit("https://example.com");
const html = await auditToHtml("https://example.com");
const score = await auditScore("https://example.com");

A project that never sets browser: true never pays for Chromium.

License

It ships under the PolyForm Noncommercial License. Free to use, copy, modify, and share for any noncommercial purpose, including personal and hobby projects. Commercial use is not permitted.

What is next

More static categories (mobile, local SEO, site integrity), CI-friendly exit codes with a score threshold, and tightening the broken-link checker so anti-bot blocks stop reading as broken links.

FAQ

Frequently asked

93 rules across 15 categories, including Core SEO, content, links, images, structured data, security, crawlability, URL structure, social media, internationalization, legal, analytics, E-E-A-T, and Core Web Vitals.

No for the core static checks, which use a fast HTML parser. Accessibility and Core Web Vitals use an optional headless browser, or Google PageSpeed Insights with no local browser at all.

Yes. It installs from GitHub as an npm package and exposes functions like audit(url) and auditToHtml(url), so you can run audits from your own code, not just the terminal.

It is free for any noncommercial use, including personal and hobby projects. Commercial use is not permitted under the PolyForm Noncommercial License.

Following along? Let's talk.

Start a conversation →