Skip to main content
Glama
axe.ts3.25 kB
/** * Axe Accessibility Analyzer (via Playwright + axe-core) * Uses axe-core library to test WCAG compliance * Open source and free to use */ import { chromium, Browser, Page } from 'playwright'; export interface AxeOptions { /** WCAG level to test: 'wcag2a', 'wcag2aa', 'wcag2aaa', 'wcag21a', 'wcag21aa', 'wcag22aa' */ wcagLevel?: string; /** Timeout in milliseconds (default: 60000 = 1 minute) */ timeout?: number; } export interface AxeViolation { id: string; impact: 'minor' | 'moderate' | 'serious' | 'critical'; description: string; helpUrl: string; nodes: number; } export interface AxeResult { tool: 'axe'; success: boolean; url: string; wcagLevel: string; violations: number; critical: number; serious: number; moderate: number; minor: number; passes: number; incomplete: number; issues: AxeViolation[]; error?: string; } /** * Analyze website accessibility using axe-core via Playwright * Open source, free, finds ~57% of WCAG issues automatically with zero false positives */ export async function analyzeAxe( url: string, options: AxeOptions = {} ): Promise<AxeResult> { let browser: Browser | null = null; let page: Page | null = null; try { // Launch browser browser = await chromium.launch({ headless: true }); page = await browser.newPage(); // Navigate to page await page.goto(url, { timeout: options.timeout || 60000, waitUntil: 'networkidle' }); // Inject axe-core await page.addScriptTag({ url: 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js', }); // Run axe analysis const wcagLevel = options.wcagLevel || 'wcag2aa'; const results = await page.evaluate((level) => { return (window as any).axe.run({ runOnly: { type: 'tag', values: [level], }, }); }, wcagLevel); await browser.close(); // Count violations by severity const critical = results.violations.filter((v: any) => v.impact === 'critical').length; const serious = results.violations.filter((v: any) => v.impact === 'serious').length; const moderate = results.violations.filter((v: any) => v.impact === 'moderate').length; const minor = results.violations.filter((v: any) => v.impact === 'minor').length; // Format violations const issues: AxeViolation[] = results.violations.map((v: any) => ({ id: v.id, impact: v.impact, description: v.description, helpUrl: v.helpUrl, nodes: v.nodes.length, })); return { tool: 'axe', success: true, url, wcagLevel, violations: results.violations.length, critical, serious, moderate, minor, passes: results.passes.length, incomplete: results.incomplete.length, issues, }; } catch (error) { if (browser) { await browser.close(); } return { tool: 'axe', success: false, url, wcagLevel: options.wcagLevel || 'wcag2aa', violations: 0, critical: 0, serious: 0, moderate: 0, minor: 0, passes: 0, incomplete: 0, issues: [], error: error instanceof Error ? error.message : String(error), }; } }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cordlesssteve/webby-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server