Generating Reports from Axe DevTools JSON Results

This page is not available in the language you requested. You have been redirected to the English version of the page.
Link to this page copied to clipboard

Using the @axe-devtools/reporter package for generating reports

Not for use with personal data

Use the Axe DevTools reporter with Playwright to produce accessibility reports for scanned pages

Generating reports is now just as easy as running scans. With the Axe DevTools reporter, you can generate immediately viewable HTML reports, JUnit XML reports for viewing in CI testing environments, and CSV reports to import into a multitude of other tools. This guide details how to install, set up, and use the Axe DevTools reporter.

Prerequisites

In order to use the Axe DevTools reporter, you need an existing Node.js project to integrate Axe DevTools as well as the reporter into. This portion of the guide only covers the reporter setup, so if you don't already have Axe DevTools running scans, read this guide on how to run scans with Axe DevTools.

Installing the Reporter

If you already configured your ~/.npmrc file to download Axe DevTools npm packages, all you need to do is run the command:

npm install @axe-devtools/reporter

If you haven't configured your installation authentication already, read one of the basic installation guides.

note

Starting with version 4.15.0, the reporter no longer includes jsdom. If you generate HTML reports, read Pre-rendering HTML reports to find out whether you need to install it or supply a browser.

Adding the Reporter to your Project

Import the reporter with the syntax that matches your project:

JavaScript with CommonJS modules

const { Reporter } = require('@axe-devtools/reporter');

JavaScript with ES modules

import { Reporter } from '@axe-devtools/reporter';

TypeScript

TypeScript uses the same import syntax as ES modules. @axe-devtools/reporter ships its own type declarations, so there is no separate @types/ package to install:

import { Reporter } from '@axe-devtools/reporter';

In order to use the reporter, your Axe DevTools library and webdriver will need to be imported as well.

Reporter Options

There are three major choices you need to make when using the Axe DevTools reporter

  1. What to name the reports
  2. Where to store the reports
  3. What format to generate the reports in

You can name the reports whatever you choose. When you initialize the reporter, you pass it a suite name which all the reports generated with that instance will share. Each report also includes a name assigned on a per-scan basis. The location, or directory, where the reports will be stored is also entirely up to the user. This directory location is also set at the instance level, so all reports generated on one reporter instance will share a directory. The optional report formats are HTML, which we recommend for immediate user viewing, JUnit XML, which we recommend for use in CI environments, CSV, which enables the scan results to be imported into other tools, and EARL (Evaluation and Report Language), which outputs a W3C EARL JSON-LD document for machine-readable accessibility reporting.

Using the Reporter

Once the reporter is imported into your project, you can initialize it. The constructor takes two arguments: the report suite name, and the destination directory for the reports. Your initialization statement should look something like this:

const reporter = new Reporter('<suite-name>', '<dir-name>');

There are two steps to running the reporter once an Axe DevTools scan has been run. First, the results must be logged for the reporter to access. Then, the reporter processes these results into the report.

reporter.logTestResult('<scan-name>', <results-object>);
reporter.buildHTML('<scan-dir>');

Pre-rendering HTML reports

An HTML report is self-contained and renders itself when it is opened in a browser. Before writing one, the reporter also tries to pre-render it into static markup, so that the report's content is present in the file itself and displays as soon as the file is opened.

Pre-rendering needs either a browser or jsdom. Starting with version 4.15.0, jsdom is an optional peer dependency and is no longer installed along with the reporter, so choose whichever of these suits your environment:

  • Supply a browser. Pass browserPath in the renderOptions argument to buildHTML, or set the AXE_DEVTOOLS_REPORTER_BROWSER_PATH environment variable, pointing at a Chromium-based executable. No browser driver or automation library is needed.

  • Install jsdom yourself. This keeps the behavior of earlier versions:

    npm install jsdom
  • Rely on a browser already installed on the machine. If you supply no browser and do not install jsdom, the reporter looks for a Chromium-based browser in this machine's standard install locations and then on the PATH.

Each time you call buildHTML, the reporter chooses one of these in the following order:

  1. The browser given by browserPath or AXE_DEVTOOLS_REPORTER_BROWSER_PATH, if that path exists.
  2. jsdom, if it is installed.
  3. A Chromium-based browser found on this machine, unless you set autoDetectBrowser to false.
  4. None of the above, in which case pre-rendering is skipped. The report is still written and still renders when opened in a browser.
note

Step 3 starts a browser process for each report. On a large batch run, or on a build machine where running a browser that the reporter located itself is unwanted, set autoDetectBrowser to false (or set AXE_DEVTOOLS_REPORTER_BROWSER_AUTO_DETECT to a falsy value) and either supply browserPath or install jsdom.

When a browser is used, it runs with its sandbox enabled and without network access. Reports contain content taken from the pages you scanned, so leave the sandbox enabled unless you are in a trusted, constrained environment that cannot support it. See RenderOptions for the full list of options.

Sample file

This sample file uses the same base as the writing tests example, but it integrates the reporter as well. The same file is shown in JavaScript and in TypeScript.

JavaScript

const rimraf = require('rimraf');
const { AxeDevToolsBuilder } = require('@axe-devtools/playwright');
const playwright = require('playwright');
const { Reporter } = require('@axe-devtools/reporter');

(async () => {
  rimraf.sync('./a11y_results/*');

  const browser = await playwright.chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();

  const reporter = new Reporter('playwright', './a11y_results');

  await page.goto('https://dequeuniversity.com/demo/mars/');

  const results = await new AxeDevToolsBuilder({ page }).analyze();

  reporter.logTestResult('tested-page', results);
  reporter.buildHTML('./a11y_results');
  await browser.close();
})();

TypeScript

import rimraf from 'rimraf';
import { AxeDevToolsBuilder } from '@axe-devtools/playwright';
import * as playwright from 'playwright';
import { Reporter } from '@axe-devtools/reporter';
import type { AxeResults } from 'axe-core';

(async () => {
  rimraf.sync('./a11y_results/*');

  const browser = await playwright.chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();

  const reporter = new Reporter('playwright', './a11y_results');

  await page.goto('https://dequeuniversity.com/demo/mars/');

  const results: AxeResults = await new AxeDevToolsBuilder({ page }).analyze();

  reporter.logTestResult('tested-page', results);
  reporter.buildHTML('./a11y_results');
  await browser.close();
})();

Sample output

The examples below show what each machine-readable report contains for a single failed check. Values such as the suite and test names come from the arguments you pass the reporter; the remaining fields are populated from the axe-core results. An HTML report is meant to be opened in a browser rather than read as source, so it is not shown here.

CSV

buildCSV writes one row per result, preceded by a header row describing each column. Fields that contain commas or line breaks, such as Remediation, are quoted.

Page URL,Page Title,Outcome,Impact,Code Snippet,Selector,Remediation,Manual,Rule ID,Help,Description,Help URL,Standard,WCAG 2 Success Criteria,Section 508 Paragraph,Tags,Date,axe-core,Needs Review,IGT,Found By,Test Title,Share URL
https://dequeuniversity.com/demo/mars/,My Test Suite,Failed,Serious,<h3>Be Bold...</h3>,"a[href=""mars2.html?a=be_bold""] > h3","Fix any of the following:
  Element has insufficient color contrast of 4.31 (foreground color: #ff9999, background color: #344b6e, font size: 13.5pt (18px), font weight: normal). Expected contrast ratio of 4.5:1",false,color-contrast,Elements must meet minimum color contrast ratio thresholds,Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds,https://dequeuniversity.com/rules/axe/4.12/color-contrast,WCAG 2.0 Level AA,1.4.3 Contrast (Minimum),,"cat.color, wcag2aa, wcag143, TTv5, TT13.c, EN-301-549, EN-9.1.4.3, ACT, RGAAv4, RGAA-3.2.1",2026-07-10T18:11:41.859Z,4.12.1,No,,,My Test Suite,

JUnit XML

buildJUnitXML groups results into a testcase per rule, with a failure element for each rule that did not pass. When a rule fails on more than one element, the occurrences are listed within the same failure, separated by a -------- divider.

<?xml version="1.0" encoding="utf-8"?>
<testsuites>
<testsuite name="My Test Suite" package="axe-result" timestamp="2026-07-10T11:11:42-0700">
<properties>
<property name="platform.userAgent" value="" />
<property name="platform.testMachine" value="" />
<property name="testSubject.fileName" value="https://dequeuniversity.com/demo/mars/" />
<property name="testSubject.lineNum" value="-1" />
</properties>
<testcase name="color-contrast">
<failure message="Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
https://dequeuniversity.com/rules/axe/4.12/color-contrast" impact="serious">
<![CDATA[https://dequeuniversity.com/demo/mars/]]>
CSS Path: <![CDATA[a[href="mars2.html?a=be_bold"] > h3]]>
HTML: <![CDATA[<h3>Be Bold...</h3>]]>
</failure>
</testcase>
</testsuite>
</testsuites>

EARL

buildEARL produces a W3C EARL (Evaluation and Report Language) JSON-LD document for machine-readable accessibility reporting. The @context declares the vocabularies used, and @graph holds one assertion per result.

{
  "@context": {
    "@vocab": "http://www.w3.org/ns/earl#",
    "earl": "http://www.w3.org/ns/earl#",
    "WCAG2": "http://www.w3.org/TR/WCAG21/#",
    "dct": "http://purl.org/dc/terms/",
    "sch": "https://schema.org/",
    "source": "dct:source",
    "title": "dct:title",
    "assertedBy": { "@type": "@id" },
    "outcome": { "@type": "@id" },
    "mode": { "@type": "@id" },
    "isPartOf": { "@id": "http://purl.org/dc/terms/isPartOf", "@type": "@id" }
  },
  "@graph": [
    {
      "@type": "Assertion",
      "mode": "earl:automatic",
      "subject": {
        "@type": ["earl:TestSubject", "sch:WebPage"],
        "source": "https://dequeuniversity.com/demo/mars/"
      },
      "assertedBy": "https://github.com/dequelabs/axe-core/releases/tag/v4.12.1",
      "result": {
        "@type": "TestResult",
        "outcome": "earl:failed"
      },
      "test": {
        "@type": "TestCase",
        "title": "color-contrast",
        "@id": "https://dequeuniversity.com/rules/axe/4.12/color-contrast",
        "isPartOf": ["WCAG2:contrast-minimum"]
      }
    }
  ]
}

Troubleshooting

A message says static HTML pre-rendering was skipped

If a run prints a message beginning axe-devtools-reporter: skipping static HTML pre-rendering, the reporter found no browser and no installed jsdom. The report is still written and still renders when you open it in a browser, so this is a warning rather than an error. To pre-render the report again, supply a browser or install jsdom as described in Pre-rendering HTML reports. The message is printed once per run, not once per report.

An HTML report is written without its content

A report that opens empty when it was pre-rendered usually means the browser was not given enough time to build it. Raise virtualTimeBudgetMs in the renderOptions argument to buildHTML. Large reports are the common cause.

A large report fails with a buffer overflow

Raise maxBufferBytes in the renderOptions argument to buildHTML. It limits how much rendered output the reporter accepts from the browser, and defaults to 64 MB.

Getting more help

If you have trouble with getting scan results, contact your Deque representative directly, reach us via our support desk, or send us an email. We'll be happy to help.

See Also