CrawlPodScan your site

AI Readiness Engine

ContentAnalyzer.audit(), added in ai-visibility 0.6.0, scores a page across six weighted categories broken into 30 named checks — replacing a single flat number with a structured breakdown of exactly why a page scores what it does. It's the engine behind npx ai-visibility audit and lint.

audit() vs. analyze()

ContentAnalyzer.analyze() — the original v0.5.0 engine, described on the scoring methodology page — is unchanged and still exported. audit() is additive, not a replacement: nothing about analyze()'s signature or seven dimensions changed when audit() shipped.

analyze() — v0.5.0audit() — v0.6.0
ShapeFlat 7-dimension score6 weighted categories → 30 named checks
Issue detailFree-text issues[] with a fix stringStructured AuditIssue[] with id, severity, score_impact
CLI commandanalyzeaudit / lint

Prefer audit() for anything new — analyze() remains mainly for its --min-score multi-file filtering in the older analyze CLI command. See the migration guideif you're moving existing code from one to the other.

The six categories

CategoryKeyWeightWhat it checks
Crawlabilitycrawlability0.20Whether AI crawlers can discover and fetch the page at all: robots.txt AI-crawler rules, llms.txt, ai.txt, sitemap discoverability, response time, JavaScript dependency.
Structurestructure0.20Heading hierarchy, semantic HTML landmarks, content-to-noise ratio, answer front-loading, FAQ/How-to patterns.
Entity SignalsentitySignals0.20Organization and Person schema, product/service entity relationships, sameAs links, machine-readable pricing.
Citation ReadinesscitationReadiness0.15Fact density, sourced statistics, unique/original data, comparison content, external authoritative references.
Contentcontent0.15Snippability, topical depth, freshness signals, multi-format support (text/tables/lists).
Authorityauthority0.10Author attribution, About/Team signals, contact information, trust signals, external mention readiness.

Weights sum to exactly 1.0, enforced by a test against the package's own CATEGORY_WEIGHTS. Full weight rationale (why crawlability/ structure/entity signals sit at 0.20 and authority at 0.10) lives on the scoring methodology page — the same reasoning applies to both engines.

Crawlability is a gate, not just a differentiator. A hard AI-crawler block — noindex, or a robots.txt disallowing every known AI crawler — zeroes overallto 0 regardless of every other category's score. Individual categories still report their own scores in that case, so the rest of the report stays useful; only overall reflects that a fully blocked page has zero AI visibility no matter how well-structured it is.

The 30 checks and severity

Each category's score is the equal-weighted average of its own named checks (5 per category on average). Every failed or partially failed check produces an AuditIssue:

interface AuditIssue {
  id: string              // matching check id, e.g. "entity-organization-schema"
  category: AuditCategoryKey
  severity: "critical" | "warning" | "suggestion"
  title: string
  description: string
  impact: string
  score_impact: number    // points lost on that check's own 0-100 scale
}
  • critical ● — the page is fundamentally invisible or blocked to AI crawlers, or missing a foundational entity signal (no Organization schema at all, pricing text with no machine-readable Offer schema).
  • warning ▲ — a significant gap that measurably reduces AI citation/discovery likelihood.
  • suggestion ○ — an optimization opportunity.

result.issues is sorted critical → warning → suggestion (ties broken by score_impact, worst first). The default CLI report shows only the top 10 under "WHY YOU MAY BE INVISIBLE TO AI"; --json and --verbose both surface every issue and every individual check score.

CLI: audit and lint

npx ai-visibility audit https://example.com
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
AI VISIBILITY AUDIT
https://example.com/
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Overall AI Readiness: 54/100

CRAWLABILITY         ████████░░ 77
STRUCTURE            ███████░░░ 69
ENTITY SIGNALS       ████░░░░░░ 44
CITATION READINESS   █████░░░░░ 51
CONTENT              ███░░░░░░░ 33
AUTHORITY            ███░░░░░░░ 34

Issues: 20 total
● 1 Critical   ▲ 8 Warnings   ○ 11 Suggestions

WHY YOU MAY BE INVISIBLE TO AI

● No Organization schema found
▲ Few semantic HTML landmarks
▲ No author/Person schema or byline found
▲ No contact information found
▲ Very low fact density
▲ No comparison content detected
▲ No H2/H3 subheadings found
▲ No sitemap.xml discoverable
○ No sameAs links to social profiles

audit --dir ./out scans a local build directory instead of fetching a live URL; lint is a CI-friendly shorthand for audit --dir . --fail-under 50. Both live on the CLI reference, which also covers --json, --verbose, and the opt-in --fail-under CI gate.

Reading a result programmatically

ContentAnalyzer.audit()
import { ContentAnalyzer } from "ai-visibility"

const analyzer = new ContentAnalyzer()
const result = await analyzer.audit(html, {
  robotsTxt: fetchedRobotsTxtContent,    // optional
  hasLlmsTxt: true,                      // optional
  hasAiTxt: false,                       // optional
  hasSitemap: true,                      // optional
  responseTimeMs: 340,                   // optional
})

result.overall            // 0-100
result.categories.content // { key, label, weight, score, checks: [...] }
result.issues              // AuditIssue[], sorted critical -> warning -> suggestion

Called with just analyzer.audit(html), the crawlability checks can only see the page's own <meta name="robots"> tag — they can't see robots.txt, llms.txt, ai.txt, sitemap presence, or response time without being told. ai-visibility audit <url> and audit --dir both supply this context automatically; calling audit() directly in your own code should too, for a fully accurate crawlability score.

AuditResult also carries two deprecated fields, score and dimensions, for consumers migrating from the old AIReadabilityScore shape — see the migration guide for the mapping. Both log a one-time warning on read, never on JSON.stringify(), so audit --json output is unaffected.

See the scoring methodology page for the full weight rationale and the published scoring-weights.json (schemaVersion 2, which carries both this six-category system and the legacy seven dimensions side by side), and the full report pipeline for how audit combines with brand measurement, citations, and competitor analysis in one command.