DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

Programmatic Accessibility Analysis: Extract Page Structure with /inspect

Programmatic Accessibility Analysis: Extract Page Structure with /inspect

Accessibility audits usually mean manual testing: open DevTools, navigate the page structure, check heading hierarchy, verify semantic HTML. It's slow. It doesn't scale.

What if you could extract a page's complete element map — headings, landmarks, form labels, ARIA attributes — as JSON? Then analyze structure programmatically in your pipeline.

That's what PageBolt's /inspect endpoint does.

The Problem: Manual Accessibility Review

Current workflow:

  1. QA manually opens DevTools
  2. Inspects page structure
  3. Checks for heading hierarchy (H1→H2→H3)
  4. Verifies form labels are connected to inputs
  5. Looks for missing ARIA attributes
  6. Documents findings in a spreadsheet

This works for small teams. It breaks at scale. You need automated analysis.

The Solution: PageBolt /inspect Endpoint

Extract a page's element map with one API call:

const response = await fetch('https://api.pagebolt.dev/v1/inspect', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${apiKey}` },
  body: JSON.stringify({
    url: 'https://example.com',
  })
});

const elements = await response.json();
Enter fullscreen mode Exit fullscreen mode

Response structure (simplified):

{
  "url": "https://example.com",
  "title": "Example Page",
  "elements": [
    {
      "tag": "input",
      "role": "input",
      "text": "",
      "selector": "input[name=\"email\"]",
      "attributes": {
        "type": "email",
        "name": "email",
        "id": "email-input",
        "aria-label": "Email address",
        "placeholder": "Enter your email",
        "required": "true"
      },
      "rect": { "x": 120, "y": 240, "width": 300, "height": 40 }
    },
    {
      "tag": "button",
      "role": "button",
      "text": "Submit",
      "selector": "#submit-btn",
      "attributes": { "type": "submit" },
      "rect": { "x": 120, "y": 300, "width": 120, "height": 40 }
    }
  ],
  "headings": [
    { "level": 1, "text": "Welcome to Example", "selector": "#page-title" },
    { "level": 2, "text": "Sign In", "selector": "h2.section-title" }
  ],
  "forms": [
    { "selector": "form#login", "action": "/login", "method": "POST", "fields": ["input[name=\"email\"]", "input[name=\"password\"]"] }
  ],
  "links": [],
  "images": []
}
Enter fullscreen mode Exit fullscreen mode

Now you can run accessibility checks programmatically.

Real Use Cases

1. Heading Hierarchy Validation

Note: headings are returned in their own headings array — separate from interactive elements.

const { headings } = await response.json();
const levels = headings.map(h => h.level);

// Check: H1 exists
if (!levels.includes(1)) console.warn('Missing H1');

// Check: No skipped levels (H1 → H3 without H2)
for (let i = 0; i < levels.length - 1; i++) {
  if (levels[i + 1] - levels[i] > 1) {
    console.warn(`Skipped heading level: H${levels[i]} → H${levels[i + 1]}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Form Label Coverage

const { elements } = await response.json();
const inputs = elements.filter(el => el.tag === 'input');
const unlabeled = inputs.filter(input =>
  !input.attributes?.['aria-label'] && !input.attributes?.placeholder
);

if (unlabeled.length > 0) {
  console.warn(`${unlabeled.length} inputs missing labels`);
}
Enter fullscreen mode Exit fullscreen mode

3. ARIA Attribute Inventory

const { elements } = await response.json();
const ariaAttrs = { label: 0, expanded: 0, required: 0 };

elements.forEach(el => {
  if (el.attributes?.['aria-label']) ariaAttrs.label++;
  if (el.attributes?.['aria-expanded'] !== undefined) ariaAttrs.expanded++;
  if (el.attributes?.required) ariaAttrs.required++;
});

console.log('ARIA usage:', ariaAttrs);
Enter fullscreen mode Exit fullscreen mode

Integrate into Your Pipeline

Add accessibility checks to CI/CD:

# GitHub Actions example
- name: Accessibility checks
  run: |
    node scripts/accessibility-audit.js https://staging.example.com
Enter fullscreen mode Exit fullscreen mode

Script (scripts/accessibility-audit.js):

const apiKey = process.env.PAGEBOLT_API_KEY;
const url = process.argv[2];

const response = await fetch('https://api.pagebolt.dev/v1/inspect', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${apiKey}` },
  body: JSON.stringify({ url })
});

const { elements, headings } = await response.json();

// Run your checks
if (!headings.some(h => h.level === 1)) {
  throw new Error('❌ Missing H1 heading');
}

// Check inputs have labels
const inputs = elements.filter(el => el.tag === 'input');
const unlabeled = inputs.filter(i => !i.attributes?.['aria-label'] && !i.attributes?.placeholder);
if (unlabeled.length > 0) {
  throw new Error(`❌ ${unlabeled.length} inputs missing labels`);
}

console.log('✅ Accessibility checks passed');
Enter fullscreen mode Exit fullscreen mode

Why This Approach

  • Real data: Extract actual DOM structure from the rendered page (not static HTML)
  • No manual clicks: Automated, repeatable checks
  • Scales: Run on 100 URLs daily in your staging environment
  • CI/CD ready: Fail builds if accessibility standards drop
  • Combines with /screenshot: Screenshot + /inspect gives you visual proof + element structure

Pricing

100 inspections/month free. Starter plan: $29/month for 5,000 inspections.

Start free — no credit card required.

Top comments (0)