Repository navigation
Soundcheck Accessibility And SEO
Two modules are off by default and worth turning on for most sites: a11y runs axe-core on every page and seo compares what search engines read. This page covers turning them on, what each reports and how they show in a comparison.
rhythm soundcheck snapshot staging.yoursite.com --modules +a11y,seo
# …make your change…
rhythm soundcheck compare+ adds to the default list (or the config's modules:), so the line above runs health, visual, interact, cache, speed, a11y, seo. compare runs with the snapshot's modules, so you only name them once. To keep them on for the project, set modules: [health, visual, interact, cache, speed, a11y, seo] in .soundcheck/config.yaml. Both run after speed on each page; interact still runs last.
The a11y module runs axe-core 4.14.0, built into the binary, on every page that loaded with a status below 400. It runs the WCAG 2.0 A and AA rules and reports violations only. Iframes are skipped and each page gets at most 45 seconds.
Each failing element is an issue:
| Part | What it holds |
|---|---|
| check |
a11y/<axe rule id>, such as a11y/label, a11y/image-alt, a11y/color-contrast
|
| title | axe's help text, such as Form elements must have labels
|
| source | a stable selector for the element, such as input[name="phone"] or main > form > img
|
| detail | the element's HTML (up to 160 characters) and axe's reasons, one per line |
| fix | a link to the rule on dequeuniversity.com |
| level | warning when axe rates it critical or serious, notice when moderate or minor |
So a new accessibility problem is NEW in a comparison, never BROKE. Problems the snapshot already had aren't shown; ones that went away are FIXED. When a rule fails on more than 20 elements of a page, the first 20 are reported and each detail says so.
A contact form that gained an unlabeled phone field and an image without alt text:
[NEW] Images must have alternative text - /contact.php
source: main > form > img
<img src="/beans.svg" width="20" height="10">
fix: See https://dequeuniversity.com/rules/axe/4.14/image-alt for what the rule asks and how to fix it.
[NEW] Form elements must have labels - /contact.php
source: input[name="phone"]
<input name="phone">
fix: See https://dequeuniversity.com/rules/axe/4.14/label for what the rule asks and how to fix it.
The selector starts at the nearest element with a stable id or a name, so a change higher up the page doesn't move it. Ids that look generated (long numbers, hex, React's :r1:) are skipped. Query strings in href, src and action and anything that looks like a token are masked in the HTML snippet.
Warning
In 1.2.0 the confirm pass doesn't see accessibility issues on its second visit, so the issues above come back as [UNSTABLE] instead of [NEW] and never fail --fail-on. Until that's fixed, compare with --confirm=off when a11y is on: rhythm soundcheck compare --confirm=off. The output above is from that command.
A page where axe itself fails adds a run warning, a11y: <path>: <reason>.
The seo module reports no issues of its own. It records what search engines read on each page and on the site, then reports what changed between two runs that both had it on.
Per page it keeps the meta description, the canonical link, the robots meta (and X-Robots-Tag), the number of <h1> headings, hreflang links, Open Graph tags and the JSON-LD types. Per site it reads robots.txt and the sitemap (from robots.txt's Sitemap: lines, else /sitemap.xml, /sitemap_index.xml or /wp-sitemap.xml), following sitemap indexes on the same host up to 50 files. The facts go into seo/ in the run folder.
An SEO plugin update that swapped every canonical for a noindex:
[BROKE] Page is now set to noindex - /, /about.php, /contact.php +1 more
(none) → noindex
fix: Search engines will drop this page. Remove the noindex (WordPress: Settings → Reading, or the SEO plugin's settings for the page).
[NEW] Canonical link removed - /
/ → –
fix: Every page should print <link rel="canonical"> with its own URL; check the SEO plugin's settings after the update.
[NEW] Canonical link removed - /about.php
/about.php → –
fix: Every page should print <link rel="canonical"> with its own URL; check the SEO plugin's settings after the update.
What it reports:
| Check | Class | Title |
|---|---|---|
seo/robots-meta |
BROKE |
Page is now set to noindex (also none, or googlebot: noindex in X-Robots-Tag) |
seo/robots-meta |
CHANGED |
Robots meta changed (index, follow and all count as saying nothing) |
seo/robots-txt |
BROKE |
robots.txt now blocks the whole site, robots.txt now blocks every page but the home page, robots.txt returns <code> (5xx) |
seo/robots-txt |
CHANGED |
robots.txt is gone (404), robots.txt rules changed (detail: Now disallows: /shop/. No longer disallows: /wp-admin/.) |
seo/sitemap |
BROKE |
Sitemap returns <code> (5xx), Sitemap is gone (404)
|
seo/sitemap |
CHANGED |
Sitemap lists fewer pages, when it lost more than 20% |
seo/canonical |
NEW, CHANGED |
Canonical link removed, Canonical URL changed (adding one isn't reported) |
seo/description |
NEW, CHANGED |
Meta description removed, Meta description changed
|
seo/h1 |
NEW, CHANGED |
Page has no <h1> heading anymore, Page now has several <h1> headings
|
seo/hreflang |
NEW, CHANGED |
Language links (hreflang) removed, Language links (hreflang) changed
|
seo/og |
NEW, CHANGED |
Open Graph tags removed, Open Graph tags changed
|
seo/jsonld |
NEW |
Structured data removed: <Type>, Structured data is no longer valid JSON
|
seo/redirect |
CHANGED |
Page now redirects to <path>, Page now redirects to the home page
|
Every change carries its own fix text. A few rules keep the noise down:
- URLs on either run's host compare by path, so comparing staging with production (
--against) doesn't flag canonicals that name production. -
robots.txtcounts as blocking the site forDisallow: /or/*underUser-agent: *, unlessAllow: /orAllow: /*opens it again.Allow: /$alone leaves only the home page open, which is its own BROKE. - A page that now redirects isn't compared field by field, since that would show the target's facts.
- Pages that errored or answered 400 or more in either run are left to health.
- With seo on, health's
Page now ends somewhere elseandPage is set to noindexare dropped on pages where seo reports the same thing, so one cause gives one line.
Site-level changes (robots-txt, sitemap) have no pages; in JSON their pages is null.
--list-checks prints every module with whether it's on, then the checks it makes:
rhythm soundcheck --list-checksa11y: off unless asked for (+a11y)
a11y/label warning Form field without a label
a11y/<axe rule id> warning Every axe-core rule that fails, e.g. a11y/color-contrast (a notice when axe rates it minor or moderate)
seo: off unless asked for (+seo)
seo/canonical notice Canonical link changed
seo/description notice Meta description changed
seo/robots-meta warning Robots meta changed
seo/h1 notice Headings changed
seo/hreflang notice Language links changed
seo/og notice Open Graph tags changed
seo/jsonld notice Structured data changed
seo/redirect notice Redirect changed
seo/robots-txt warning robots.txt changed
seo/sitemap warning Sitemap changed
The full list (health, visual, interact, cache, speed, echo and exec too) is in the CLI reference.
rhythm · Useful ideas. Working systems. · Check only sites you own or have permission to test. Keep staging sealed (responsible use) · This wiki is published from wiki/ in the rhythm repository; suggest changes there with a pull request.
Get started
rhythm in depth
Tuner
- Overview
- Your first scan
- Reading results
- Choosing checks
- Requests and politeness
- Output and reports
- Batch scans
- Local scans
- Integrity and malware
- Changes and notifications
Tuner in depth
- Known vulnerabilities
- PHP advisories
- CI and code scanning
- GitHub Action
- Config file
- Watch and serve
- Writing checks
- Check packs
- Finding reference
- CLI reference
- Coming from Wordfence CLI or WPScan
- FAQ and troubleshooting
Soundcheck
- Overview
- Your first check
- Reading results
- Review and accept
- Discovery
- Page health
- Visual changes
- Interactions
- Forms and flows
- Cache
- Speed
- Accessibility and SEO
Soundcheck in depth
- CI
- CI baselines and PR comments
- Configuration
- Error rules and exec
- WordPress updates
- Fleet and client reports
- History
- Import from BackstopJS and Lost Pixel
- Firefox and WebKit
- CLI reference
- FAQ and troubleshooting
- Benchmark
Echo
- Overview
- Your first run
- Connectors
- Sealing staging
- Echo Inbox
- Messages and checks
- Checks and rules
- Attachments
- Actions and compare
- With Soundcheck
- Replay
- Deliverability
Echo in depth
- Docker and DDEV
- Agency hub and reports
- Schedule
- MCP server
- Conformance kit
- CI
- Configuration
- API
- CLI reference
- FAQ and troubleshooting
- Benchmark
Project