auditmysite
Accessibility audits for real rendered pages, built for CI and modern frontend stacks
Overview
auditmysite is a Rust CLI that audits accessibility against fully rendered pages in Chrome. Instead of scanning raw HTML only, it uses Chrome DevTools Protocol (CDP) and the browser's native Accessibility Tree, so it can evaluate dynamic DOM, computed styles, and JavaScript-heavy applications more realistically.
It is designed for teams that want a fast local check, stable JSON for automation, and a single binary that can be dropped into CI.
Why use it
- Real browser signals instead of static guesses
- Works for single pages, sitemaps, URL lists, and same-domain crawl discovery
- Outputs as terminal table, JSON, PDF, AI-optimized task list, or compact summary JSON for dashboards
- JSON output is schema-backed and tested for release stability
- Ships as a Rust binary instead of a Node-based toolchain
Why this approach
Most accessibility CLIs either depend on static parsing or require a heavier runtime stack around browser automation. auditmysite is opinionated in a different direction:
- Chrome-native accessibility data first
- CLI-first workflow for local use and CI
- Small operational surface: install a binary, point it at a URL, get a report
- Optional modules for performance, SEO, security, and mobile without changing tools
Quick Example
By default, a single URL audit runs the full analysis set, prints a compact terminal summary, and writes report artifacts into the current working directory:
./example-com-YYYY-MM-DD-single-report.pdf./example-com-YYYY-MM-DD-single-report.json./example-com-YYYY-MM-DD-single-report-screen-reader-audit.json
For CI or machine-readable output:
Install
curl installer (macOS/Linux)
|
The installer downloads the latest GitHub Release asset for your platform and verifies it against the published .sha256 checksum before installing it.
Upgrading: run the same command again. The installer detects where your current binary lives and replaces it in place — no PATH conflicts, no leftover old version.
Note: If you previously installed via
cargo install auditmysite, remove that binary first so the script installs to the right location:|
Verify the installation:
That default command writes report artifacts into the current directory, for example:
./example-com-YYYY-MM-DD-single-report.pdf./example-com-YYYY-MM-DD-single-report.json./example-com-YYYY-MM-DD-single-report-screen-reader-audit.json
cargo install (crates.io)
Requires Rust 1.75+. Builds and installs the binary from source.
Prebuilt binaries
Download from Releases.
- macOS/Linux:
.tar.gz - Windows:
.zip
Build from source
Optional Cargo features:
| Feature | What it adds | Build command |
|---|---|---|
pdf |
PDF report generation via the renderreport/Typst engine |
cargo build --release --features pdf |
pdf_test |
PDF rendering integration tests | cargo test --features pdf_test |
ai-transparency |
C2PA image-provenance check (EU AI Act Art. 50, opt-in --ai-transparency flag, single-URL mode only) |
cargo build --release --features ai-transparency |
Requirements
- Rust 1.75+ for local builds
- Chrome, Chromium, or a managed browser install (
auditmysite browser install) - macOS, Linux, or Windows for released binaries
auditmysite requires a browser to be present at run time. It does not download or install one automatically — it reports an error and exits if none is found. To install a managed Chrome for Testing into ~/.auditmysite/browsers/:
Quick Start
The fastest way to validate your setup:
That creates the default report set in the current directory. For machine-readable output only:
Single page
# default: full audit + terminal summary + PDF/JSON in current directory
# JSON
# PDF with explicit path
# stricter WCAG level
Batch audits
# explicit sitemap
# crawl from a base URL and discover same-domain pages automatically
# base URL: probe robots.txt / common sitemap locations first
# prefer sitemap automatically if one is found
# suppress sitemap suggestion and stay on the single page
# URL file
# per-page reports: scan a list/sitemap but write one PDF per URL instead of an aggregated batch report
Browser selection
CLI
auditmysite [OPTIONS] [URL] [COMMAND]
Primary commands:
auditmysite <url>: run a full single-page audit and write PDF/JSON into the current directoryauditmysite --sitemap <url>: audit sitemap URLsauditmysite --url-file <file>: audit URLs from fileauditmysite <url> --crawl: discover same-domain pages from a seed URL and audit them as a batchauditmysite browser detect: show available browsersauditmysite browser install: download and install Chrome for Testing into~/.auditmysite/browsers/(opt-in, never automatic)auditmysite doctor: run local diagnostics
Useful flags:
--prefer-sitemap: if a sitemap is detected for a base URL, switch directly into batch mode--no-sitemap-suggest: suppress sitemap probing/suggestion and keep the run on the single URL--crawl-depth <n>: limit same-domain crawl discovery depth when using--crawl--per-page-reports: scan a URL list or sitemap but write one individual report per URL instead of an aggregated batch report;-ois treated as a target directory--lang <de|en>: set the language for PDF reports (default:de)--stack: enable tech stack detection and stack-specific security probes (included automatically with--full)--interactive <off|basic|full>: control the Accessibility Journey Layer for interactive checks — tab walk, skip-link, modal focus trap, SPA navigation, form-error announcement, link-text inventory (default:full; useofffor fastest runs)--annex <en301549|bik>: add an opt-in appendix to the PDF report.en301549maps findings to EN 301 549 (chapter 9, "Web") clauses — a technical building block for a human-authored accessibility statement, not a statement itself.bikregroups the same findings by the chapters of the "BIK für Alle" editorial guide (images/alt text, link text, structure, easy language, PDFs, videos), without adding new checks. The underlying JSON data (en301549_annex,bik_guide) is always present regardless of this flag; it only gates the PDF section.--dns-check: opt-in, score-neutral DNS configuration check (CAA presence, best-effort DNSSEC, SPF when an MX record exists); runs once per host, not once per page--isolate-third-party-impact: reload the page once per top-5 third-party origin with that origin blocked and report each origin's Total Blocking Time impact; costly, requires--fullor--performance, single-URL mode only--check-ssr-content: reload the page with JavaScript disabled and flag an SSR/hydration content gap when essential content only appears client-side; one extra reload, requires--fullor--seo, single-URL mode only--design-quality: opt-in UX/readability heuristics, including alt-text quality checks (filename-like alt text, "image of" prefixes, overly long or redundant alt text); score-neutral and not part of--full--color <auto|always|never>/--progress <auto|always|never>: terminal color and batch progress policy;--progressis independent of--quiet
For the full current interface, use:
Output Contract
JSON output is treated as an automation contract.
- Contract documentation: docs/OUTPUT_CONTRACT.md
- Single report schema: docs/json-report.schema.json
- Batch report schema: docs/json-batch-report.schema.json
Key fields in a single-page report:
metric_context— machine-readable definitions for the 0–100 score scale and the report's scoped count fieldsfindings— static WCAG violations and SEO findingsinteractive_findings— journey-phase results (link texts, landmarks, heading outline, focus order, modal traps …); present when--interactive basic|fullwas usedaccessibility_journey— structured trace of each journey (steps, snapshots, durations); present when--interactive basic|fullwas usedaudit_scopeandexecution_environment— requested modules, viewports, throttle profiles, interaction mode, browser context, and live/cache provenanceaudit_qualitypluspages[].detail.module_runsandpages[].detail.rule_outcomes— distinguish complete, partial, failed, skipped, and non-applicable checks so a measurement failure cannot look like a clean resultpages[].detail.accessibility_assessments— structured warnings, manual-review items, and positive signals kept separate from confirmed violations and scoringartifacts— descriptors for separately written evidence or screen-reader sidecars without embedding binary data in the main JSONbuild_id— git short-SHA of the binary that produced the report (suffixed-dirtyfor builds from uncommitted changes,unknownfor builds without a.gitdirectory), so two reports with the sametool_versioncan be told apartpages[].detail.en301549_annexandpages[].detail.bik_guide— findings mapped to EN 301 549 clauses and to the "BIK für Alle" editorial guide chapters; always present, independent of--annexpages[].detail.accessibility_subcategory_scoresandpages[].detail.security_category_scores— the Accessibility and Security scores broken down by subcategory ({ name, score }), the same breakdown the PDF shows; single reports only
Rule IDs are stable across releases. Version 1.3.0 renamed two IDs that collided with unrelated checks: the 4.1.2 control-label check is now control-missing-label (was label, which stays with the 3.3.2 label/instructions checks), and the 2.4.9 link-purpose (link only) check is now link-name-only (was link-name, which stays with the 2.4.4 check).
For dual-viewport audits, the Accessibility score is the rounded blend of 70% mobile and 30% desktop in both JSON and PDF. WCAG occurrences, distinct grouped WCAG findings, and findings from all categories are exposed separately so counts remain comparable across formats.
Batch JSON additionally exposes site_analysis: module averages, consistency signals, page types, topic overlap, duplicate content, structured-data distribution, performance rollups, interactive coverage, and aggregated accessibility assessments. Per-page entries remain compact instead of duplicating full single-page reports.
The repository validates these contracts in automated tests.
Feature Scope
WCAG rules (Level A and AA)
Core rules:
- Non-text content (1.1.1)
- Keyboard access (2.1.1)
- Bypass blocks (2.4.1)
- Language of page (3.1.1)
- Name, role, value / form labeling (4.1.2)
- Contrast minimum (1.4.3) and non-text contrast (1.4.11)
- Headings and labels (2.4.6)
- Labels or instructions (3.3.2)
- Focus order (2.4.3), focus visible (2.4.7), and focus not obscured, minimum/enhanced (2.4.11/2.4.12, WCAG 2.2)
- Label in name (2.5.3)
- Meaningful sequence — CSS
ordervs. reading-order mismatches (1.3.2) - Pause, stop, hide —
<marquee>and long-running CSS animations without a pause control (2.2.2) - Redundant entry — same field requested twice with no reuse/autofill hint (3.3.7, WCAG 2.2)
- Target size minimum (2.5.8, WCAG 2.2) and text spacing (1.4.12)
ARIA and semantics:
- ARIA role validation — invalid roles, required owned elements, required context
- ARIA attribute checks — allowed attributes per role, required attributes, prohibited attributes
- Accessible name checks — icon-only controls, empty aria-labelledby/describedby, name/description conflicts, naming by role type (command, input, meter, progressbar, toggle, dialog, treeitem)
- ARIA relationship checks — aria-controls, aria-owns, aria-activedescendant, duplicate IDs
- Landmark structure — main, navigation, banner, contentinfo (presence, uniqueness, top-level nesting, no-duplicate for banner/contentinfo/main, required parent for landmarks)
- Content in landmarks — region rule ensuring body content lives inside landmark regions
- Table rules — caption/name, header cells, presentational tables, cell placement
- Form rules — fieldset/legend for grouped controls, required field indication, error description, label-title-only detection
- List structure — listitem context, empty lists, definition list integrity
- Dialog rules — accessible name, aria-modal, alert region labeling
- Widget rules — tab/tabpanel pairing, selected state, combobox options, slider value, tree context, summary element naming
- Media rules — application and image-role elements without accessible names
- Video checks — caption tracks for native
<video>(a same-origin track file is probed before a pass is confirmed, 1.2.2), media alternatives with a nearby-transcript heuristic (1.2.8), and keyboard operability of native video controls (unnamed or unreachable players) - ARIA hygiene (best practice, low severity) — explicit roles that restate the element's implicit role, and links without a real target (
href="#",javascript:) used as button substitutes - Duplicated accessible names — names that repeat themselves back to back (e.g. "Contact Contact"), typically from an icon label concatenated with adjacent text
- Frame and iframe rules — accessible names on all frames (
frame-title), manual-review notices for cross-origin frames (frame-tested), and a full WCAG content scan inside same-origin iframes: image-alt (1.1.1), button-name (4.1.2), link-name (2.4.4), form labels (1.3.1), duplicate IDs (4.1.1), document language attribute (3.1.1) - SVG rules — SVG image accessible names
- Server-side image maps — detection and flagging
- Meta viewport — large maximum-scale restrictions
100+ rules with stable rule_id, tags (e.g. wcag2a, wcag412, cat.aria), and an impact field (critical / serious / moderate / minor).
Methodology numbers are frozen in docs/PARITY_CONTRACT.jsonc and guarded by tests/parity_contract.rs: WCAG 2.1 AA has 50 A/AA criteria, 36 are covered by automated AuditMySite checks, and 10 are listed as manual-review criteria.
Some criteria (keyboard trap behavior, timed content, captions) cannot be reliably verified by automated means. These are flagged as not_testable in the JSON output and listed in the report's audit scope section as requiring manual review.
AAA is not fully implemented yet.
Additional modules
Modules are classified by how their result is obtained: compliance (Accessibility), measured (based on real browser data), composite (the search-experience roll-up, which blends measured SEO with heuristic sub-scores), heuristic (structural-signal estimates, marked with ~ in reports), and optional (Dark Mode — reported as a design choice, not a compliance gap).
Measured:
- Performance: Core Web Vitals (FCP, LCP, TBT, CLS), throttled profiles, DOM/load targets, render-blocking and third-party resources, critical request chains, unused code, minification potential, JavaScript heap, and modeled transfer emissions
- SEO: meta tags, headings, structured data, page-to-schema fit, content profile, tracking/external services signals, and social-preview images (
og:image/twitter:image) without an alt description - Security: HTTPS, header checks, and CDN/WAF protection detection. Headers are grouped by risk tier: CSP, HSTS, and clickjacking protection are baseline requirements, while context-dependent headers such as COOP/CORP get a verification question and safe-configuration guidance instead of an unconditional "add this header"
- Mobile: viewport, touch-target, readability checks, UX heuristics (cookie-banner, modal/overlay, CTA detection)
- HTML5 conformance: spec-conformance checking via the
html-conformcrate, part of--full; scored per distinct defect cause rather than per raw occurrence, so one templated markup mistake rendered many times doesn't get charged once per render - DNS configuration (opt-in
--dns-check): CAA, best-effort DNSSEC, and SPF when an MX record exists; score-neutral
Heuristic (indicator scores — tendency, not measurements):
- UX: 5-dimension analysis (CTA clarity, visual hierarchy, content clarity, trust signals, cognitive load) with saturation curve scoring
- Journey: user-flow analysis (entry clarity, orientation, navigation, interaction, conversion) with page-intent-aware weighting
- AI Visibility: structural readiness for LLM indexing and citation (readability, citability, structured data, AI policy, chunk quality)
- Source Quality: code hygiene signals (inline styles, deprecated elements, semantic structure, asset hygiene)
- Dark Mode: detects dark mode support via
prefers-color-schememedia queries and CSS custom properties - Easy language: recognizes an easy-language ("Leichte Sprache") or plain-language version of the page via class names, a
langvariant, or a link-text marker, and reports it as a positive signal - Tech Stack: detects CMS and frameworks (WordPress, Drupal, Joomla, Next.js, Astro, React, Vue, etc.) via in-page signals and runs stack-specific security probes (admin panel exposure, user enumeration, version disclosure)
- Commerce: shop audit that only activates when a page is detected as a store (schema-gated). Checks product structured-data completeness, presence of mandatory and trust pages (imprint, returns, shipping, payment), coarse page-kind classification (product detail, category), and rolls findings up across a batch. Derive-only — no extra browser interaction. Product-detail pages also get two commerce-aware interactive journeys — see Accessibility Journey Layer below.
Structured-data analysis
The SEO module parses JSON-LD objects, arrays, and @graph documents; normalizes short, multiple, and full-IRI @type values; and reports invalid JSON, missing or invalid context, and untyped nodes. Microdata and RDFa are detected and explicitly marked as detected but not content-validated.
Type-specific rules assess Product/Product Snippet, merchant Product + Offer, Article/BlogPosting/NewsArticle, BreadcrumbList, Organization, LocalBusiness, FAQPage, Event, Recipe, VideoObject, JobPosting, SoftwareApplication/WebApplication/MobileApplication, ProfilePage, CollectionPage/ItemList, WebPage/WebSite, and Person. Each profile records its source and review date. Eligibility blockers, recommendations, and manual checks remain separate; unknown types stay visible in the inventory without being judged incomplete.
Page-to-schema fit is evaluated conservatively from visible page intent, visible facts, and URL evidence. The tool distinguishes product, service/software, job, event, FAQ, person, location, editorial-review, corporate, hub, and lead-generation pages. Missing primary schema is only reported as an opportunity at high classification confidence, and single-item Product, JobPosting, or Event markup is rejected on corresponding overview routes.
For supported types, visible titles, prices, availability, authors, dates, FAQ content, breadcrumbs, job titles, and event dates are compared with JSON-LD. A hard mismatch is emitted only when the visible value is unambiguous; otherwise the result explicitly remains not evaluated or requires manual review. Batch reports additionally show recurring schema blockers, page-type/schema combinations, content-parity mismatches, and conflicting Organization/WebSite identities.
Runtime and evidence reliability
Page capture uses a bounded stability budget and records whether the DOM became quiet, an application-provided ready signal was observed, or the budget expired. Consent handling reports detected, dismissed, failed, and unknown states with non-sensitive evidence. Ctrl-C and SIGTERM follow the same controlled shutdown path as normal runs, and report files are written atomically so partial files are not presented as successful output.
Every audited page receives Do-Not-Track and Global Privacy Control signals (DNT: 1 and Sec-GPC: 1 on all requests, plus the matching navigator.doNotTrack/navigator.globalPrivacyControl values), so an audit visit is less likely to show up in the site owner's analytics. This is best-effort: not every analytics tool honors these signals.
Sitemap indexes are deduplicated and guarded against cycles, with hard limits of 1,000 sitemap documents and 100,000 discovered URLs. Batch aggregation stays bounded and publishes its atomic report only after collection succeeds.
Accessibility Journey Layer
Interactive checks run a real browser session after the static AXTree phase. They run in full mode by default and can be reduced via --interactive <off|basic|full> or mode in auditmysite.toml.
| Mode | What runs |
|---|---|
off |
No interactive phase — fastest, no browser interaction after initial load |
basic |
Tab-walk (focus order, reverse jumps), skip-link verification, disclosure/accordion, modal focus trap, tab-list, menu journey |
full (default) |
Everything in basic, plus: SPA-navigation detection, form-error announcement (now covering multiple independent forms per page, e.g. search + login + newsletter, and flagging live regions inserted only after submit, which not every browser/screen-reader combination announces), link-text inventory (generic/duplicate texts, heading outline, landmark structure) |
On a detected shop's product-detail page, full mode also runs two commerce-aware journeys: an add-to-cart feedback check (does adding an item announce the result via a live region or focus-managed dialog, or only update a visual cart badge — SC 4.1.3) and a quantity-stepper operability check (can the quantity field be operated by keyboard, and does its value stay exposed to assistive technology — SC 2.1.1/4.1.2). Both are click-only, single-interaction checks — never a real checkout submission, never a filled-in purchase form.
Results appear in interactive_findings and accessibility_journey in the JSON output. The execution block records detected, attempted, completed, failed, skipped, and budget-limited journeys separately from findings. Compact focus evidence retains visibility, viewport, focus-indicator, bounding-box, obscuring, aria-hidden, and inert signals without embedding a full AXTree. Interactive findings do not affect the accessibility score or legal_flags; critical interactive findings can raise the risk level.
auditmysite.toml configuration:
[]
= "full" # off | basic | full
= 8000 # wall-clock budget per URL in milliseconds (default: 6000)
Risk assessment
Risk level is computed independently from the score. A page scoring 81 can still carry "Critical" risk if it has Level A violations relevant under BFSG/EAA. Risk levels: Low, Medium, High, Critical — based on critical/high violations, legal flags, and blocking issues (4.1.2/2.1.1).
Configuration file
auditmysite.toml is an optional project-level config file placed in the working directory. It supports [audit], [rules], [interactive], [thresholds], and [budget] sections.
Rule configuration
Rules can be selectively disabled or filtered via auditmysite.toml:
[]
= ["heading-order", "landmark-one-main"]
# enabled_only = ["image-alt", "label"] # run only these rules
AI / LLM output format
Export findings as a task-oriented JSON list for direct LLM processing:
Each entry is a task object with task_id, rule_id, impact, wcag, tags, title, issue, fix, selector, node_id, and help_url — sorted by impact severity. Suitable for direct use as context in AI-assisted code remediation.
Baseline and CI diff
Save a baseline snapshot and compare future runs against it:
# Save baseline
# Future CI runs can diff against the baseline programmatically via the Rust API
The Baseline type in the audit module supports from_violations, diff, load, and save.
Non-goals (deliberately deferred)
These are recognized as potentially useful but deliberately not on the roadmap right now — each would pull the project away from its core shape (a stateless, single-run web-page auditor) for a disproportionate amount of new surface area:
- PDF document accessibility checking. auditmysite audits rendered web pages via the browser's
accessibility tree; it does not parse or score linked/embedded PDF documents (tagged-PDF
structure,
/Lang, alt text on figures, table header scope, etc.). Doing this properly would need a new PDF-parsing dependency and a second, PDF-specific SSRF-hardened fetch path (comparable in scope to the existingai_transparencymodule) for a feature that only applies when a page happens to link PDFs. Out of scope for now; revisit only as a dedicated, separately-scoped module if real demand shows up. - Full audit-history / report-diffing as a first-class feature. The
BaselineAPI above covers programmatic before/after diffing of WCAG violations for a single URL. A richer, built-in "compare this report against an older report" mode with its own CLI flag, PDF section, and batch-vs-single/methodology-consistency handling is not planned — that turns the tool from a stateless auditor into a report-history manager, a different product shape. A JSON-to-JSON diff against two saved reports is straightforward to script externally (e.g. withjq) without needing this built in.
Report Modes
Single-page reports and sitemap/batch reports are intentionally different.
Single-page report is a product-grade PDF organized as a top-down narrative:
- Cover: a composed dashboard — dominant overall score with a score-band label (no A–F grade, no "/100"), a module gauge strip, and the WCAG findings scope.
- Management view: severity counters, a "quality profile" spider radar, a score-driver table (which weighted module pulls the overall score down most), Accessibility and Security subcategory breakdowns, a one-line problem profile (isolated, concentrated in a few systemic patterns, or broad and systemic), and strengths / optimization cards.
- Findings overview: a compact, priority-sorted findings matrix precedes the detailed finding cards.
- Manual review: a fixed list of WCAG criteria that are structurally outside automated testing, and concrete VoiceOver/NVDA self-test steps where a quick manual check is realistic.
- Accessible output: PDFs are tagged and PDF/UA-1 conformant (structure tree, document language, title, bookmarks); rendering fails with a diagnostic instead of silently producing a non-conformant PDF.
- Module chapters: each module is its own chapter with a magazine-style opener and a one-line key takeaway. AI Visibility, Content Visibility, and Source Quality are merged into a single "KI & Vertrauen" (AI & Trust) chapter.
- Action plan: recommendations as action cards grouped by where the problem lives (systemic vs. local), without time or effort estimates, plus a root-cause distribution chart.
- Evidence-grade findings: each finding card can include a cropped, highlighted screenshot of the affected element, its DOM path, and (where applicable, e.g. contrast) the measured vs. required value — so a finding stands on its own without re-running the tool.
- Audit coverage: requested and completed checks, partial measurements, manual-review items, and Journey execution coverage are surfaced explicitly instead of treating missing data as a pass.
- Performance decisions: raw resource and loading metrics are paired with target ranges, the largest directly actionable lever, and prioritized actions.
The design follows a consistent four-color status system; reports use no emoji and report effort by priority rather than by time windows.
Sitemap/batch report is aggregated and domain-wide: averages, ranking, recurring issues, URL matrix, near-duplicate content, broken links, crawl diagnostics. It also verifies which recurring findings share the same underlying template component across pages — reporting "one fix resolves N pages" instead of N near-identical findings, with a confirmed/likely confidence distinction so the claim is never overstated. Template clusters require at least three affected pages and 60% site coverage, can identify selector-less document findings, and retain header/nav/main/footer context. Cross-page WCAG assessments for consistent navigation, identification, help, and multiple ways are kept separate from single-page automation and explicitly mark evidence gaps as manual review.
Batch reports are not a stack of single-page reports.
Compared to typical setups
- Better fit for JavaScript-heavy sites than static HTML-only checks
- Easier to distribute than a multi-package browser toolchain
- More automation-friendly than ad hoc console output because the JSON contract is explicit and tested
- Broader reporting surface than a pure accessibility-only checker when you also want performance, SEO, security, and mobile signals
- Violations carry stable
rule_id,tags, andimpact— easier to integrate with existing tooling or dashboards
Screen Reader Audit vs. axe-core / Pa11y
Standard accessibility checkers verify individual rules in isolation. auditmysite additionally simulates the sequential experience of a screen reader user navigating the page — detecting problems that only emerge in context.
| Capability | axe-core | Pa11y | auditmysite |
|---|---|---|---|
| Rule-based WCAG checks | ✓ | ✓ | ✓ |
| Reading sequence simulation | — | — | ✓ |
| Out-of-context link text analysis (duplicate "Read more" × 8) | — | — | ✓ |
| Accessible name quality score (not just present/absent) | — | — | ✓ |
| Landmark navigation strategy (can a SR user reach main content?) | — | — | ✓ |
| BFSG / EN 301 549 legal mapping per finding | — | — | ✓ |
Every finding also carries a per-criterion EN 301 549 (chapter 9, "Web") clause reference. A structured version — all 50 WCAG 2.1 A/AA clauses split into "violations found", "no violations in the automated scope", or "manual review required", plus which chapters (5–8, 10–13) sit outside this tool's audit scope entirely — is always in the JSON (en301549_annex) and can be added to the PDF as an appendix with --annex en301549. This is explicitly not an accessibility statement and doesn't claim to be one — it's a technical building block for a human-authored one, with an explicit scope disclaimer in both languages.
When the screen reader module runs, a JSON sidecar is written automatically next to the primary report:
example-com-YYYY-MM-DD-single-report.pdf
example-com-YYYY-MM-DD-single-report-screen-reader-audit.json ← automatic sidecar
The sidecar models what a screen reader would typically announce, node by node, based on rule-based conventions (name, role, and state) — not a verified 1:1 reproduction of what NVDA, JAWS, or VoiceOver actually announce, which can vary by assistive technology, browser, and locale. It also flags which announcements are ambiguous or missing, suitable as a developer reference and as supporting evidence for BFSG compliance audits. No extra flag is required; the file is created whenever screen reader data is available in the audit result.
Typical Workflows
Examples grouped by audience and goal.
Customer-facing report (PDF)
Single-URL audit with full module coverage and a custom logo on the cover.
# default: writes a PDF + JSON sidecar to the current directory
# explicit branding and output path
# pick a report depth: executive (management), standard (default), technical (developers)
# PDF language (default: de)
CI / automation (JSON)
Quiet, machine-readable output for pipelines.
# exit code follows score thresholds; JSON report for downstream tooling
# batch CI run on a sitemap
AI fix list
Compact, agent-friendly output that focuses on actionable fixes.
Dashboard / ranking feed
Compact summary JSON with score, grade, medal, issue counts, and top 10 findings — matches the lastAudit schema used by dashboard tools.
Sitemap / batch
Domain-wide audits with cross-page aggregation.
# explicit sitemap
# crawl from a base URL
# URL list from file
# one PDF per URL instead of an aggregated batch report
Local development
# audit a local dev server with a system Chrome
# quick CLI summary without writing files
Base URL with sitemap suggestion
# interactive: ask first if a sitemap is found
# non-interactive: switch directly to sitemap mode
# stay on the single URL even when a sitemap exists
Architecture
CLI -> Browser Manager -> Chrome/CDP -> Accessibility Tree -> WCAG Engine -> Output
Key layers:
browser/: browser detection, resolution, explicit install (browser installcommand only — no auto-download), lifecycle, poolingaudit/: pipeline, normalization, scoring, batch processingwcag/: rule engine and violationsoutput/: CLI, JSON, PDF, AI, summary formatseo/,security/,performance/,mobile/,ux/,journey/: optional analysis modulestech_stack/,source_quality/,ai_visibility/,dark_mode/: heuristic indicator modules
More detail:
- Current implementation: docs/ARCHITECTURE.md
- Browser dependency details: docs/chrome-dependency.md
- Troubleshooting: docs/TROUBLESHOOTING.md
Development
Setup
Pre-commit checks
This repository uses Git hooks with a fast local pre-commit gate and a full pre-push gate.
pre-commit runs:
nosecretson staged changescargo fmt -- --checkcargo clippy --lib --bins --all-features -- -D warnings
pre-push runs:
scripts/check-version-match.shfor pushedv*tagscargo clippy --all-targets --all-features -- -D warningscargo test
Enable the repo hook path:
Install nosecrets as a real binary first:
# or
Skip the Rust checks only when you intentionally need to bypass them:
SKIP_RUST_CHECKS=1
The hook expects nosecrets to be available in PATH.
Debugging report content (hidden --debug-typ)
PDF reports are rendered through the renderreport/Typst engine. To review report
completeness and wording without opening the binary PDF, use the hidden
--debug-typ flag together with --format pdf. It writes the intermediate Typst
source as a .typ sidecar next to the PDF, for both single and batch reports:
# Single report → reports/example-audit.pdf + reports/example-audit.typ
# Batch report → reports/example-batch.pdf + reports/example-batch.typ
The .typ file is plain text and diff-friendly — useful for checking which audits
land in the report and reviewing the exact wording of every section. The flag is
intentionally hidden from --help (developer/debug use only).
Release checks
Run the local release gate with:
It validates:
cargo test- ignored browser integration tests
- builds with and without PDF
- current
--helpoutput - JSON contract tests
- installer/release artifact consistency
- stale docs references
Troubleshooting
- Browser not found: run
auditmysite browser detector install a managed browser withauditmysite browser install - Running in Docker or as root: use
--no-sandbox - Need raw output for scripts: prefer
-f json -o report.json - Unsure about the full CLI surface: run
auditmysite --help
Contributing
Library / Development
For library development or local work from the repository:
If you want the current local repository state as an installed binary while developing:
Contributions are welcome. At minimum before opening a PR:
License
auditmysite is licensed under the MIT License. Use it freely, including
commercially.
The rule engine, document model, accessible name computation and report model live in a11y-core, also MIT, and are shared with astro-post-audit and liveaudit — the same rule IDs across build time, CI and the live page.
MIT applies from version 1.5.0 onward. Earlier releases remain under the license that applied at the time: up to 0.25.x AGPL-3.0-or-later, 0.26.0 through 1.4.0 Business Source License 1.1. See NOTICE.
Credits
- Browser automation via chromiumoxide
- PDF reports via renderreport
- WCAG reference material from W3C