CrawlPodScan your site

CLI reference

npx ai-visibility audit <url> scores a live page or local build directory against the same seven-dimension content analyzer described on the scoring page, and --fail-under <n>turns it into a CI gate. Every command and flag below was run directly against the installed 0.5.0 binary's --help output and, for audit/lint, against a real URL and a real local directory — not copied from the README.

Install and invoke

npx ai-visibility <command>          # no install required
# or
npm install -D ai-visibility && npx ai-visibility <command>

Global flags, from ai-visibility --help:

Usage: ai-visibility [options] [command]

Options:
  -V, --version          output the version number
  -q, --quiet            suppress the CrawlPod footer and other non-essential output
  -h, --help              display help for command

audit — the headline command

Fetches a live URL, or scans a local build directory with --dir, and scores every HTML file it finds against the same ContentAnalyzer the package exports programmatically:

Usage: ai-visibility audit [options] [url]

Arguments:
  url               URL to audit (fetches the live page)

Options:
  --dir <path>      Audit a local build directory instead of a live URL
  --json            Output results as JSON
  --fail-under <n>  Exit with a non-zero code if any score is below this
                    threshold (0-100) — for CI
  -h, --help        display help for command

Real output, run against a plain HTML fixture with a thin body and no structured data:

npx ai-visibility audit --dir ./fixture
🤖 ai-visibility audit

❌ fixture/index.html — 35/100
   Answer placement: 20  Fact density: 25  Headings: 100  E-E-A-T: 0  Snippability: 30  Schema: 0  Crawler access: 100
   🔴 No substantive paragraph found after H1
      Fix: Add a clear, direct answer or description in the first paragraph immediately after your H1
   🔴 Very low fact density: 0.0 facts per 100 words (target: 4-6)
      Fix: Add specific numbers, dates, statistics, or measurable claims to support your content
   🔴 No JSON-LD structured data found
      Fix: Add JSON-LD schema markup using SchemaBuilder from ai-visibility
   ... and 4 more issues

──────────────────────────────────────────────────
Scanned: 1
Average score: 35/100
Passing (≥80): 0 / 1

Powered by CrawlPod — https://crawlpod.com

--fail-under is opt-in — there is no implicit default threshold for audit, unlike lint below. Passing it flips the exit code without changing the report:

npx ai-visibility audit --dir ./fixture --fail-under 80
(same report as above, plus:)

❌ Below threshold: at least one score is under 80

exit: 1

For a live URL, audit also best-effort fetches robots.txt and checks for llms.txt at the same origin (local files, for --dir) to feed the crawlerAccessibilitydimension — a failed or missing fetch is treated as "unknown", never a hard error. --json returns the same shape ContentAnalyzer.analyze() returns programmatically, one entry per file/URL scanned:

npx ai-visibility audit https://example.com --json
{
  "file": "https://example.com/",
  "score": 50,
  "result": {
    "overallScore": 50,
    "breakdown": {
      "answerFrontLoading": 95,
      "factDensity": 25,
      "headingStructure": 100,
      "eeatSignals": 0,
      "snippability": 30,
      "schemaCoverage": 0,
      "crawlerAccessibility": 100
    },
    "issues": [ /* { type, severity, message, fix } */ ],
    "recommendations": [ /* string[] */ ]
  }
}

lint — the CI-friendly shorthand

A thin wrapper around the same audit core with defaults tuned for build-time use — this is the build-time GEO linter, not a separate implementation:

Usage: ai-visibility lint [options]

(shorthand for: audit --dir . --fail-under 50)

Options:
  --dir <path>      Directory to lint (default: ".")
  --json            Output results as JSON
  --fail-under <n>  Exit with a non-zero code if any score is below this
                    threshold (0-100) (default: "50")
  -h, --help        display help for command

Unlike audit, lint gates by default — running it with no flags against the same thin fixture above exits 1 because 35 is under the default threshold of 50.

Wiring it into CI

Both audit --fail-under and lint exit non-zero on failure, so either drops into a CI step directly:

.github/workflows/ci.yml
- name: GEO lint
  run: npx ai-visibility lint --dir ./out --fail-under 60

Run the build directory your framework actually emits (./out for a Next.js static export, ./dist for Vite, etc.) — pointing it at source files instead of build output audits pre-render markup, not what a crawler will actually receive.

robots and llms — top-level aliases

New in 0.5.0: flatter top-level aliases for the two most common generate subcommands. generate robots/generate llms/generate schema still work unchanged — see generate below.

Usage: ai-visibility robots [options]

Options:
  --out <path>       Output path (default: "./public/robots.txt")
  --preset <preset>  allow-all | block-training | block-all
  --block-training   Shorthand for --preset block-training (deprecated, kept for back-compat)
  --sitemap <url>    Sitemap URL to include
  -h, --help         display help for command

Usage: ai-visibility llms [options]

Options:
  --out <path>          Output path (default: "./public/llms.txt")
  --site-name <name>    Site name (default: "My Site")
  --description <desc>  Site description (default: "A website")
  --base-url <url>      Base URL (e.g. https://mysite.com)
  -h, --help            display help for command

--preset block-all is new in 0.5.0 too, alongside the existing allow-all/block-training — it maps to RobotsGenerator.blockAll(), a control mechanism for site owners who want every known AI crawler blocked, not a recommendation either way. See the generators API reference for the underlying class.

--quiet

Every command accepts a global -q/--quiet, new in 0.5.0. Without it, non-JSON output ends with a one-line, dimmed "Powered by CrawlPod" footer — no color, no upsell block. With --quiet, the footer (and other non-essential output) is gone entirely; verified by running the same audit both ways and diffing the output.

generate — pre-existing subcommands

generate, init, analyze, and logs predate 0.5.0 and are unchanged by it (except generate robots gaining the same --preset flag as the new top-level robots alias, since they share one implementation):

Usage: ai-visibility generate [options] [command]

Commands:
  robots [options]  Generate robots.txt with AI crawler rules
  llms [options]    Generate llms.txt for AI model indexing
  schema [options]  Generate JSON-LD schema markup

Usage: ai-visibility generate schema [options]

Options:
  --type <type>      Schema type: faq | product | article | org | person (default: "article")
  --out <path>       Output path (optional, prints to stdout if not set)
  --name <name>      Name/headline
  --price <price>    Price (for product schema)
  --author <author>  Author name
Usage: ai-visibility init [options]

Options:
  --dir <path>        Project directory (default: ".")
  --site-name <name>  Your site name
  --site-url <url>    Your site URL (e.g. https://myapp.com)
  --block-training    Block training bots (CCBot, GPTBot) while allowing search bots

Usage: ai-visibility analyze [options]

Options:
  --dir <path>     Directory to scan (default: ".")
  --file <path>    Analyze a single file
  --json           Output results as JSON
  --min-score <n>  Only show files below this score (default: "101")

Usage: ai-visibility logs [options]

Options:
  --crawler <name>   Filter by crawler name (e.g. GPTBot)
  --days <n>         Show logs from last N days (default: "7")
  --url <path>       Filter by URL path
  --summary          Show summary statistics only
  --log-file <path>  Path to log file (default: "./logs/ai-crawler.json")
  --json             Output as JSON

analyze and audit overlap in purpose — both score HTML for AI readability. audit/lint are the ones worth reaching for now: they add the crawlerAccessibility dimension via robots.txt/llms.txt context, a CI-friendly --fail-under exit code, and JSON output shaped for tooling. analyze remains for its --min-score filter across many files at once.

See the scoring pagefor what the seven breakdown dimensions mean and how they're weighted, and the API reference for the programmatic ContentAnalyzer equivalent of audit.