Abdulkader Safi

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

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.

Share
Safi Studio Scanner terminal report showing a website health score and audit categories

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.

Last updated 17 Aug 2026 · filed under Typescript, tools, terminal application, seo, website audit

Every entry on this project

2 build notes, in order

Including the ones where nothing worked. You are on part 1.

Read the series →

FAQ

Frequently asked questions

What does Safi Studio Scanner check?

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.

Do I need a browser to run it?

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.

Can I use it inside my own project?

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.

Is it free to use commercially?

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

Written by

Abdulkader Safi

Senior & Lead Software Engineer

Lead engineer at DSRPT, from Lebanon and based in Kuwait. I write about the tools and bugs from real client work, with the numbers I measured.

About me → GitHub LinkedIn

Need this kind of work done on your project?

Start a project →

Keep reading

More from Safi Studio Scanner

All 2 entries →
  • The Safi Studio Scanner social card: 94 checks, one score, every page, set over a register of 94 tally marks.
    Safi Studio Scanner

    · part 2 of 2

    Safi Studio Scanner 1.0.2: a report that carries numbers

    The audit engine could tell you a check failed and nothing else, so there was nowhere to put a number. 1.0.2 adds a measurements channel, a streaming API so you can watch a crawl work, and a documentation site. Plus the head-parsing bug that made my social card invisible.