A Singapore Government Agency Website

Scan pages and HTML in Node.js

What this guide covers

scanPage and scanHTML scan content from a plain Node.js script, without an Oobee instance, a test framework or the CLI. Both return the results as an object that you can check in your own code. Use scanPage when you control a Playwright page, and scanHTML when you only have an HTML string.

Function Scans Runs in Status
scanPage One or more Playwright Page objects A real browser Beta in the integration guide
scanHTML One or more HTML strings JSDOM in Node.js Experimental

The functions do not write a report folder. To produce a report, use the Oobee instance in Integrate Oobee with Playwright.

Prerequisites

  • Node.js 20 or later.
  • @govtechsg/oobee installed: npm install --save-dev @govtechsg/oobee.
  • For scanPage: Playwright and its Chromium browser, npx playwright install chromium.
  • A project that runs ES modules: set "type": "module" in package.json, or use .mjs files.
  • Parameter details: npm API.

Step 1: Scan Playwright pages with scanPage

Pass one page or an array of pages. Oobee injects its scripts into each page and runs the scan.

import { chromium } from "playwright";
import { scanPage } from "@govtechsg/oobee";

const browser = await chromium.launch({ headless: false, channel: "chrome" });
const page = await browser.newPage();
await page.goto("<PAGE_URL>");

const results = await scanPage(page, {
  name: "<YOUR_NAME>",
  email: "<YOUR_EMAIL>",
});

console.log(JSON.stringify(results, null, 2));
await browser.close();

To scan several pages in one call, pass [page, page2]. To enable AAA rules or turn off Oobee’s own checks, add ruleset: ["enable-wcag-aaa"] or ruleset: ["disable-oobee"] to the config.

Step 2: Scan HTML strings with scanHTML

Pass one HTML string or an array of strings. scanHTML needs no browser.

import { scanHTML } from "@govtechsg/oobee";

const html = `<!DOCTYPE html>
<html lang="en">
<head><title>Test page</title></head>
<body>
  <h1>Accessibility test</h1>
  <button></button>
  <img src="test.jpg" />
</body>
</html>`;

const results = await scanHTML(html, {
  name: "<YOUR_NAME>",
  email: "<YOUR_EMAIL>",
  pageUrl: "<PAGE_LABEL>",
  pageTitle: "<PAGE_TITLE>",
});

For an array, Oobee appends -1, -2 and so on to pageUrl, and a number to pageTitle.

Step 3: Read the results

Both functions return the same shape. A single page returns its results directly, and several pages return merged results. Each result has three categories, and each category has a totalItems count and a rules object keyed by rule ID.

const mustFix = results.mustFix.totalItems;
const goodToFix = results.goodToFix.totalItems;

for (const [ruleId, rule] of Object.entries(results.mustFix.rules)) {
  console.log(ruleId, rule.totalItems);
  for (const item of rule.items) {
    console.log(item.html, item.message);
  }
}
Category Contents
mustFix WCAG Level A and AA failures
goodToFix AAA failures and best-practice failures
needsReview Results that need a person to confirm

Each item has html and message, and may have xpath and parentHtml. A rule also has description, helpUrl, conformance, axeImpact, shortDescription, longDescription and stepByStepGuide.

Constraints and limitations

Constraint Detail
scanHTML accuracy scanHTML runs in JSDOM and may not catch issues that need a full browser layout or JavaScript execution to appear.
scanHTML size An HTML string over 50 MB is rejected. Change this with OOBEE_SCANHTML_MAX_BYTES. Set it to 0 for no limit.
scanHTML time An axe-core run is stopped after 300000 ms. Change this with OOBEE_SCANHTML_AXE_TIMEOUT_MS.
No report folder scanPage and scanHTML return results only. They do not write report.html.
Page title override pageTitle in scanPage applies only when you pass a single page.
Name and email Both are required in the config. Oobee submits them with a summary of the results to GovTech as usage data. Set OOBEE_DISABLE_TELEMETRY=1 to stop all submissions.
Chat with me!
Bot Launcher