Skip to content
astro-post-audit
MITInstall
Astro integration · Rust · Open source

Catch errors
before they go live

After every astro build, astro-post-audit reads the generated HTML and reports missing canonicals, broken links, incomplete meta tags and accessibility problems. Static analysis – no browser, no external services.

33
Check modules
8
Presets
0.6.0
npm version
astro build
$ astro build

[FAIL] astro-post-audit

  Errors: 1   Warnings: 1   Info: 0   Files: 12

* blog/post/index.html (2)
  - Missing canonical tag [canonical/missing] at `head`
    Remedy: Set `site` in astro.config.mjs and render
    <link rel="canonical" ... /> in BaseHead.
  - <img> missing alt attribute [a11y/img-alt]
    at `img[src='/photo.jpg']`
    Remedy: Add an `alt` prop to <Image>/<Picture>
    or the <img> tag.
Output format as in the READMEErrors: 1 · Warnings: 1
Check areas
  • Canonical
  • Internal links
  • Sitemap
  • robots.txt
  • Headings
  • Open Graph
  • JSON-LD
  • hreflang
  • WCAG heuristics
  • Images
  • HTML5 conformance
  • GDPR transfers
  • AI visibility
  • C2PA
As of v0.6.0, September 2026
4
Report formats
6
Binary targets
0
Network calls by default
Astro 5–7
Peer dependency
01 — Overview

An audit of what actually ships.

The integration hooks into astro:build:done and checks the finished files in dist/. The checker is written in Rust; on install, the npm package fetches the matching binary for macOS, Linux or Windows. It only touches the network when you switch on external link checking.

github.com/casoon/astro-post-audit →
  1. 01After the build — it checks the HTML that ends up on your server
  2. 02Offline — no headless browser, no crawler, no account
  3. 03Configurable — presets, rule overrides and severity per rule ID
  4. 04Ready for CI — failOn, baseline and SARIF for GitHub Code Scanning
02 — Get started

Three steps to the first report.

  1. 1Install

    Add the package

    As a dev dependency. The postinstall script downloads the binary from GitHub Releases and verifies its SHA-256 checksum.

    npm i -D @casoon/astro-post-audit
  2. 2Register

    Add the integration

    If you use @astrojs/sitemap, place postAudit() after it. Both run in astro:build:done, in array order.

    integrations: [sitemap(), postAudit()]
  3. 3Build

    Run the build

    The audit runs with it. With failOn: 'errors' the build stops when errors are found.

    astro build
03 — Checks

What gets checked.

SEO and canonicals

Canonical present, absolute, same-origin and self-referencing; clusters of pages sharing one canonical; noindex; trailing-slash consistency.

Links, sitemap, robots.txt

Broken internal links and fragments, orphan pages, sitemap entries without a page, Disallow: /, crawl delay and conflicts between robots.txt and noindex.

HTML and headings

lang, title, viewport and meta description with length limits; exactly one H1 and no gaps in the heading hierarchy.

Accessibility heuristics

Alt text and its quality, names for links and buttons, form labels, landmarks, duplicate IDs, valid ARIA roles, aria-hidden on focusable elements.

Open Graph and JSON-LD

og:title, og:image as an absolute URL, valid twitter:card values; JSON-LD syntax, duplicate types and entity conflicts across pages.

hreflang and i18n

Self-reference, x-default, reciprocal links and existing targets; consistency of html[lang], hreflang and canonical per locale route.

Images, assets, payload

Missing width/height, lazy loading, srcset, broken asset references, JS and CSS weight per route with outlier detection.

Third-party transfers

With gdpr: true: Google Fonts, direct YouTube and Maps embeds, public CDNs and external images, plus missing SRI hashes.

Optional modules

Offline HTML5 conformance, AI visibility and llms.txt links, UX heuristics, content style, C2PA credentials and Astro/Tailwind source analysis.

04 — Configuration

From preset to production gate.

astro.config.mjsPreset production
// astro.config.mjs
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
import postAudit from '@casoon/astro-post-audit';

export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap(), // before postAudit()
    postAudit({
      preset: 'production',
      failOn: 'errors',
      maxWarnings: 0,
      hints: { sourceFiles: true },
      reports: {
        json: 'audit-report.json',
        sarif: 'audit.sarif',
      },
      rules: {
        filters: { exclude: ['404.html'] },
        external_links: { enabled: true, fail_on_broken: true },
      },
    }),
  ],
});
.github/workflows/build.ymlSARIF
# .github/workflows/build.yml
- name: Build
  run: npm run build

- name: Upload SARIF
  if: always()
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: audit.sarif
05 — Existing sites

Roll it out without breaking the build.

On older projects the first run often reports hundreds of findings. These options let you adopt it step by step.

  1. 01

    Baseline

    writeBaseline freezes the current findings in a file. From then on, only new findings are reported. Commit the file.

  2. 02

    Warn first, block later

    Enable the heuristic modules with failOn: 'never' and a JSON report, downgrade single rules to info via severity, then switch to failOn: 'errors'.

  3. 03

    Go-live gate

    goLive reports noindex on live pages, wrong origins in canonicals, OG tags and the sitemap, and forbidden domains such as staging hosts. These errors cannot be downgraded.

  4. 04

    Fast local builds

    New in 0.6.0: mode: 'fast' turns off the expensive HTML5 validation. SKIP_AUDIT=1 skips the audit for a single build.

06 — Baseline

Two lines for existing projects.

astro.config.mjsBaseline
// 1. Run once: freeze the current findings
postAudit({ writeBaseline: true, baseline: '.audit-baseline.json' })

// 2. From then on: only new findings are reported
postAudit({ baseline: '.audit-baseline.json' })
07 — Limits

What a static audit cannot see.

astro-post-audit reads files. Anything that only exists in the browser is out of scope.

No rendering

No colour contrast, no layout, no runtime JavaScript behaviour. That takes an audit in a real browser.

Heuristics are not a WCAG audit

The accessibility rules catch common mistakes. They do not replace a WCAG conformance assessment.

Heuristic modules

i18n, crawl budget, render blocking, privacy and the structured-data graph work on assumptions and need tuning per project via severity.

Download on install

The postinstall script needs access to GitHub Releases. Air-gapped CI environments have to provide the binary in advance.

08 — FAQ

Frequently asked questions.

Does astro-post-audit fail the build on errors?

Only if you configure it to. With failOn: "errors" the build fails on errors, with "warnings" also on warnings, with "never" it never fails. maxWarnings sets an upper limit for warnings. Without these options the audit only prints a report.

Which presets are available?

standard, strict, production (an alias for strict), seo, accessibility, performance, relaxed and editorial. Individual entries under rules override the preset. relaxed is meant as a starting point for existing sites with known issues.

How is this different from a browser-based audit?

astro-post-audit analyses the static HTML in dist/ without a browser. Browser-based tools such as auditmysite check the running website and therefore see rendering, contrast, load times and JavaScript behaviour. The two approaches complement each other.

How do I turn off individual checks?

Modules and options can be set one by one in the rules object. Under rules.severity, every rule ID can be set to error, warning, info or off, for example "html/title-too-long": "off". filters.exclude skips pages by glob.

How do I introduce the audit on an existing website?

Build once with writeBaseline: true and a baseline path. The audit stores all current findings in that file. Later builds report only new findings. Deleting entries from the file re-enables the check for them.

What does astro-post-audit cost and how is it distributed?

Nothing. The package is MIT-licensed, with no API costs and no account. It is distributed via npm (0.6.0 as of September 2026) with binaries from GitHub Releases for macOS, Linux and Windows on x64 and arm64. The Rust crate on crates.io is currently at 0.5.5.

Every build checked.

One package in astro.config.mjs; the report arrives with your next astro build.