DEV Community

Cover image for How I built a website audit tool that costs $0.03/audit in AI
Jethro May
Jethro May

Posted on

How I built a website audit tool that costs $0.03/audit in AI

I just shipped AuditZap, an AI-powered website audit tool. Instead of writing a launch post, I wanted to share some of the interesting technical decisions behind it.

The architecture

A user submits a URL. The API validates it, creates an audit row in Postgres, pushes a job to BullMQ, and returns immediately. The client polls every 3 seconds. A separate worker process picks up the job, crawls the site with Puppeteer, runs 24 checks, calls Claude for fix instructions, and writes the results back to the database.

The worker is a standalone Node.js process — it doesn't import anything from the Next.js app. PM2 runs both.

Making AI affordable at $0.03/audit

The trick: batch everything into a single API call. All failed and warning checks are collected, then sent to Claude in one prompt. The prompt includes the CMS detection result so the fix instructions are platform-specific (WordPress, Shopify, Webflow, etc.).

I considered calling the AI per-check, but that would have been ~$0.15-0.20/audit with 24 checks. Batching reduced it to a single input/output pair.

Pure function checks

Every check is a pure function: takes crawl data, returns a structured result. No side effects, no database calls, no API calls. This makes them trivially testable — 583 tests run in under 5 seconds with no Docker, no database, no Redis.

// Example: missing meta description check
const missingMeta = pages.filter(
  (p) => !p.metaDescription || p.metaDescription.trim() === ''
)
results.push({
  checkName: 'Missing meta description',
  category: 'critical',
  status: missingMeta.length > 0 ? 'fail' : 'pass',
  details: missingMeta.length > 0
    ? `${missingMeta.length} of ${pages.length} crawled URLs are missing a meta description.`
    : `All ${pages.length} crawled URLs have a meta description.`,
})
Enter fullscreen mode Exit fullscreen mode

Free tools as lead gen

I exposed 9 of the 24 checks as free, standalone tool pages. Each uses a lightweight crawler (fetch + HTML parsing, no Puppeteer) that runs in ~1-2 seconds. No signup, no database writes. Every tool page is an SEO landing page targeting long-tail queries like "free broken link checker" or "free meta description checker".

Self-hosting on Hetzner

Two CX23 boxes (2 vCPU, 4GB RAM each) at roughly $10/mo total. One for production, one for staging. Postgres and Redis run in Docker. DeployHQ handles auto-deploys on push.

I considered Vercel but the combination of Puppeteer (needs a real browser), BullMQ (needs persistent Redis), and background workers made self-hosting the better fit.

The stack

Next.js 16 (App Router), TypeScript strict, Drizzle ORM + Postgres 16, BullMQ + Redis 7, Puppeteer Core + @sparticuz/chromium, Claude Sonnet, Lemon Squeezy, Resend, Tailwind CSS 4 + shadcn/ui.

If you want to try it: auditzap.io. The free tools page lets you run individual checks without signing up.

Happy to answer questions about any of the technical decisions.

Top comments (0)