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:
- QA manually opens DevTools
- Inspects page structure
- Checks for heading hierarchy (H1→H2→H3)
- Verifies form labels are connected to inputs
- Looks for missing ARIA attributes
- 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();
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": []
}
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]}`);
}
}
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`);
}
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);
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
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');
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)