Help center
How AccessGlade works
From sign-up through your first scheduled scan, with every option explained. Looking for a specific topic? Use the table of contents below or your browser's find shortcut (⌘F).
Getting started
AccessGlade is a multi-tenant accessibility platform. You sign up, create an organization (your "workspace"), add the domains you want to track, and the platform takes care of the rest.
- Request access via the waitlist while we're in closed beta. Once invited, you'll receive a tokenized sign-up link by email.
- Add a property (below). The domain is the canonical identifier.
- Either run discovery to populate the URL inventory, or paste URLs in by hand.
- Queue a scan. Findings appear in the Issues queue, rolled up by component.
Everything from there is iteration: triage findings, push the harder ones to Jira / Linear / GitHub, and watch your accessibility score on the dashboard.
Properties
A property is a domain you want to track — for example acme.com. Properties live inside an organization and inherit the organization's membership roster.
Roles
- Owner — full control, including billing and deleting the org.
- Admin — add properties, run scans, change issue status, invite members.
- Member — read access plus comments. Cannot change issue status.
Add a property at /dashboard/properties. Use the bare hostname or paste a full URL — we strip the protocol and path.
URL discovery
The discovery crawler walks your domain to build a URL inventory. It is deliberately polite: identifies itself in the User-Agent (with an optional contact email so site owners can reach you), respectsrobots.txt by default, prefers sitemap.xml when available, and rate-limits per host.
How it walks
- Fetch
robots.txtfrom the property origin. - Try every
Sitemap:URL it lists, plus/sitemap.xml. Sitemap-first means we don't miss pages humans haven't linked to. - Fall back to BFS from the seed root if no sitemap is found.
- Honor the schedule's max depth and max pages caps.
Manual control
Open a property→ "URLs" tab. From there you can add, edit, exclude, or delete URLs; bulk-include or bulk-exclude with the checkboxes; or click "Run discovery now" to queue a one-off discovery job.
Exclusions
Exclusions are per-property rules that filter URLs at discovery time. Three kinds:
- Prefix — URL starts with this exact text. Fastest. Use for whole subtrees.
- Glob — shell-style;
*matches any chars,?matches one. - Regex — JavaScript regex. Most powerful; easiest to get wrong.
The exclusions editor shows a live preview: how many URLs in your current inventory the new rule would match. Existing matched URLs aren't deleted — use the URLs tab's bulk delete for that.
Scanning
Scans run axe-coreinside a real headless Chromium against every includedURL in the property's inventory. Findings are persisted as EARL JSON-LD, the W3C-blessed format for accessibility evaluations.
Schedules
Each property has a single schedule with two cadences: discovery and scan. Typical setup: discover daily, scan weekly. The cron tick checks every minute and enqueues due jobs into the work queue.
Auto-chain
"Scan after every successful discovery" is off by default. Turn it on if you want freshly-discovered URLs to be scanned immediately — at the cost of longer first-run scans.
WCAG coverage
We run the WCAG 2.1 / 2.2 A and AA rule packs plus axe's best-practice rules. Subjective WCAG criteria (e.g. "is this content clear?") cannot be checked automatically; manual audits remain a human task.
Components
The single most useful thing AccessGlade does. While scanning, we walk up from every violation node to its nearest landmark (header, nav, main, footer,aside) and compute a structural signature ignoring text. Any violation in the same landmark on a different page collapses to the same issue.
Why it matters:a missing aria-label in your header used to be 200 issues across 200 pages. Now it's one issue with 200 pages next to it. Fix it once, close it everywhere.
See your top components on the dashboard or under each property at /dashboard/properties/[id]/components.
Triaging issues
Issues are the layer humans interact with. Each issue has:
- Status: open / in-progress / resolved / ignored / wont-fix.
- Severity: critical / serious / moderate / minor (from axe).
- Assignee: any member of the org.
- Component: when present, links to the component view.
- Activity feed + comments.
Keyboard shortcuts
The issues queue is keyboard-driven by default:
| Key | Action |
|---|---|
| j / ↓ | Move focus down |
| k / ↑ | Move focus up |
| x / space | Select / deselect |
| ↵ | Open |
| e / r / i / o | Status: in-progress / resolved / ignored / open |
| esc | Clear selection |
Integrations
Push individual issues to your team's tracker. v1 is one-way (we send; status doesn't mirror back). Configure connectors at /dashboard/integrations.
- Jira — host + email + API token + project key. Issue type defaults to
Task. - Linear — API key + team ID.
- GitHub — personal access token + owner / repo + optional labels.
Tokens are encrypted at rest using pgp_sym_encrypt against a key held outside the database. We never log token values; the connector list never exposes them to the browser.
Exports
Two flavours today:
- CSV export from the issues queue. Honors the active filter so you can hand a stakeholder a focused list rather than the whole catalogue.
- WCAG compliance matrix at /dashboard/compliance: one row per success criterion, populated from the rules currently failing.
PDF VPAT export is on the roadmap once usage indicates it's worth building.
Chrome extension
The browser extension lets users run an audit on the page they're looking at and post the results into the property that matches the hostname. It signs in using the same Supabase auth as the web app and uses /api/ingest for delivery.
Because the extension runs in the user's browser, it sees the page exactly as the user does — auth-walled internal staging environments are a great fit for it.
API reference
Today there's one ingestion endpoint: POST /api/ingest. Authenticate with a Supabase JWT (Authorization: Bearer …) belonging to a user with admin or ownerrole on the target property's organization.
Request shape
POST /api/ingest
Authorization: Bearer <supabase-jwt>
Content-Type: application/json
{
"property_id": "<uuid>",
"scanner": "axe-core",
"scanned_at": "2026-05-08T12:34:56Z",
"page_url": "https://example.com/page",
"results": [ <axe-core violation objects> ]
}Other supported scanners: lighthouse, macos-native, a11y-checker(the Chrome extension's shape). Each is normalized to EARL JSON-LD on the way in.
Response
{ "inserted": 3, "ids": ["<uuid>", "<uuid>", "<uuid>"] }See scripts/test-ingest.mjs in the repo for a working example.
Data handling
AccessGlade stores three kinds of data:
- Findings (rule failures) and their associated EARL metadata.
- HTML snippets of the violating element and its enclosing landmark — capped at 5KB and used to identify components.
- Account data — your email, role, and organization membership.
We do not store full page HTML, screenshots, cookies, or any user-entered data from the pages we scan. Tenant isolation is enforced at the database layer with Row-Level Security: a finding from org A is mathematically unable to appear in a query made by a member of org B.
Troubleshooting
Discovery returns 0 URLs
The most common cause is robots.txt disallowing our user agent. Either add an explicit Allow:for our agent, or — if you own the site — disable the "Respect robots.txt" toggle in the property's schedule. Second most common: the seed URL redirects to a different host. Add the destination domain as its own property.
Scans hang or time out
Pages that never reach networkidle(often because of long-polling XHR or analytics keepalives) hit our 20-second navigation timeout and skip. These appear in the scan job's errorcolumn. We do not retry; re-queue the scan once you've fixed the source.
I don't see a component on a finding
Components attach only to scanner-produced findings (with rendered DOM context). Findings sent via /api/ingestfrom the Chrome extension or another client don't carry component metadata, and roll up by absolute CSS selector instead.