DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

Automated Accessibility Testing API: Run WCAG 2.1 Audits Programmatically

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));
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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

  1. Sign up at pagebolt.dev/pricing
  2. Get API key (60 seconds)
  3. Run one /audit call
  4. 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)