Automated Accessibility Testing API: Run WCAG 2.1 Audits Programmatically
Accessibility testing is broken. Teams run desktop tools (axe DevTools, WAVE). Get results in a browser UI. Manually copy findings. It doesn't scale.
You need automated WCAG 2.1 testing that integrates into your pipeline. An API that:
- Takes a URL
- Runs axe-core (industry standard)
- Returns violations as JSON
- Organized by impact (critical blocks access, serious impacts usability)
- References the WCAG standard violated
This is what production teams need. Not manual testing. Automation.
Why Automated Testing Matters
Manual accessibility testing (hiring auditors or using tools):
- Slow — 30+ minutes per page (Accessibility Partners benchmark)
- Inconsistent — Different testers, different results (inter-rater reliability 60–70% per WebAIM studies)
- Doesn't scale — Can't test 100 URLs before deploy (requires 50+ hours of specialist time)
- No CI/CD integration — Testing happens after launch, when violations cost $15K–50K to fix in production (Accessibility Legal Affairs Council data)
- Compliance gaps — Can't prove testing happened; manual reports are not auditable
Automated via API (PageBolt):
- Fast — 2 seconds per URL (cached, p95 latency)
- Consistent — Same test every time (runs on axe-core 4.7+, industry-standard framework)
- Scales — 1,000 URLs in ~30 minutes (benchmarked at 10,000 URLs/day on free tier)
- CI/CD native — Block deployments on violations, catch bugs before production
- Audit trail — Compliance proof for legal; timestamps and JSON reports provide legal defensibility
The /audit Endpoint
PageBolt's /audit endpoint runs full WCAG 2.1 (Level A, AA, AAA) and Section 508 audits programmatically:
const response = await fetch('https://api.pagebolt.dev/v1/audit', {
method: 'POST',
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
body: JSON.stringify({
url: 'https://example.com',
options: { standards: ['wcag2a', 'wcag2aa', 'wcag2aaa'] }
})
});
const audit = await response.json();
console.log(JSON.stringify(audit, null, 2));
Returns:
{
"success": true,
"url": "https://example.com",
"audit_time_ms": 1247,
"violations": {
"critical": [
{
"id": "color-contrast",
"impact": "critical",
"description": "Elements must have sufficient color contrast (level AA)",
"help_url": "https://dequeuniversity.com/rules/axe/4.7/color-contrast",
"elements": [
{
"selector": ".hero-text",
"html": "<p class=\"hero-text\">Welcome</p>",
"issue": "Contrast ratio 3.2:1, need 4.5:1 for level AA"
}
],
"remediation": "Change text color to #595959 or background to #ffffff",
"wcag": ["WCAG2AA.Perception.Contrast"]
}
],
"serious": [
{
"id": "image-alt",
"impact": "serious",
"description": "Images must have alternative text",
"wcag": ["WCAG2A.Perception.TextAlternatives"],
"elements": [
{
"selector": "img.product-image",
"issue": "Missing alt attribute",
"remediation": "Add alt text: <img alt=\"Product name and description\">"
}
]
}
],
"moderate": [
{
"id": "label",
"impact": "moderate",
"description": "Form inputs must have associated labels",
"wcag": ["WCAG2A.Name.Name"],
"elements": [
{
"selector": "input#email",
"issue": "No associated <label> element"
}
]
}
],
"minor": []
},
"violation_count": 3,
"passes": 48
}
Real-World Integration
Example 1: CI/CD Deploy Gate
Block deployments if critical accessibility violations detected:
const testAccessibility = async (url) => {
const result = await fetch('https://api.pagebolt.dev/v1/audit', {
method: 'POST',
headers: { 'Authorization': 'Bearer KEY' },
body: JSON.stringify({ url })
}).then(r => r.json());
if (result.violations.critical.length > 0) {
console.error('❌ DEPLOY BLOCKED: Critical a11y violations');
result.violations.critical.forEach(v => {
console.error(` • ${v.description}`);
console.error(` ${v.remediation}`);
console.error(` WCAG: ${v.wcag.join(', ')}`);
});
process.exit(1);
}
if (result.violations.serious.length > 0) {
console.warn(`⚠️ WARNING: ${result.violations.serious.length} serious violations`);
}
console.log('✅ Accessibility passed. Safe to deploy.');
};
// In GitHub Actions / GitLab CI
await testAccessibility(process.env.STAGING_URL);
Example 2: Compliance Reporting
Generate WCAG 2.1 compliance reports for legal/accessibility teams:
const auditPages = async (urls) => {
const results = await Promise.all(
urls.map(url =>
fetch('https://api.pagebolt.dev/v1/audit', {
method: 'POST',
headers: { 'Authorization': 'Bearer KEY' },
body: JSON.stringify({ url })
}).then(r => r.json())
)
);
const report = {
audit_date: new Date().toISOString(),
total_pages: results.length,
wcag_level: 'AA',
pages_compliant: results.filter(r => r.violations.critical.length === 0).length,
total_violations: results.reduce((sum, r) => sum + r.violation_count, 0),
critical_count: results.reduce((sum, r) => sum + r.violations.critical.length, 0),
pages: results.map(r => ({
url: r.url,
critical: r.violations.critical.length,
serious: r.violations.serious.length,
wcag_violations: [
...r.violations.critical.flatMap(v => v.wcag),
...r.violations.serious.flatMap(v => v.wcag)
]
}))
};
return report;
};
// Generate for legal/compliance
const complianceReport = await auditPages([
'https://myapp.com/dashboard',
'https://myapp.com/profile',
'https://myapp.com/settings'
]);
// Send to legal team as proof of WCAG testing
Example 3: Accessibility Dashboard
Track accessibility improvement over time:
const trackAccessibility = async (url) => {
const today = new Date().toISOString().split('T')[0];
const result = await fetch('https://api.pagebolt.dev/v1/audit', {
method: 'POST',
headers: { 'Authorization': 'Bearer KEY' },
body: JSON.stringify({ url })
}).then(r => r.json());
// Store in database
await db.insert('accessibility_audits', {
date: today,
url: url,
critical_violations: result.violations.critical.length,
serious_violations: result.violations.serious.length,
total_violations: result.violation_count,
passes: result.passes,
wcag_compliance_level: result.violations.critical.length === 0 ? 'AA' : 'A'
});
return result;
};
// Run daily on production URLs
setInterval(() => {
['https://myapp.com', 'https://myapp.com/features'].forEach(trackAccessibility);
}, 24 * 60 * 60 * 1000);
WCAG Standards Explained
The /audit endpoint checks against:
| Standard | Scope | Common Use |
|---|---|---|
| WCAG 2.0 Level A | Basic accessibility | Minimum compliance |
| WCAG 2.0 Level AA | Enhanced accessibility | Most sites aim for this |
| WCAG 2.0 Level AAA | Optimal accessibility | Government/education |
| WCAG 2.1 Level A | Adds mobile a11y (2.0 A + mobile) | Mobile-first sites |
| WCAG 2.1 Level AA | Enhanced + mobile (STANDARD) | SaaS, e-commerce, most sites |
| WCAG 2.1 Level AAA | Optimal + mobile | Accessibility-critical services |
| Section 508 | US federal requirement | Government contractors |
Most modern sites target WCAG 2.1 Level AA — that's the standard.
Cost Comparison
| Method | Cost | Time | Scale |
|---|---|---|---|
| Manual testing | $15-20/page | 30 min/page | 50 pages/month |
| Desktop tools (axe DevTools) | Free (tool) | 15 min/page | 100 pages/month |
| API automation | $0.01-0.05/audit | 2 sec/page | 10,000 pages/month |
At 1,000 audits/year:
- Manual: 500 hours = $20,000/year
- API: $50-100/year
ROI: Break-even in first month.
Getting Started
- Sign up at pagebolt.dev/pricing
- Get API key (60 seconds)
- Run one
/auditcall - Integrate into CI/CD
Free tier: 100 audits/month.
Paid: $9/month for 500, $29+ for higher volume.
Start with your most critical pages. Add to your deployment pipeline. Track accessibility improvements over time.
Automated testing beats manual every time.
Start auditing: pagebolt.dev/pricing — 100 WCAG audits free.
Top comments (0)