ScreenshotNeo

BlogHow-to

How to Use Puppeteer’s Accessibility API

Inspect Puppeteer’s accessibility tree, tune snapshot scope, and use accessible names and roles to automate controls reliably.

By the ScreenshotNeo team4 October 20267 min read

Puppeteer’s accessibility API lets you inspect the browser’s serialized accessibility tree with await page.accessibility.snapshot(). The default snapshot keeps nodes Puppeteer considers interesting. Set interestingOnly: false for more detail, pass root to inspect a subtree, or set includeIframes: true to include iframe trees. If your goal is to interact with a control by its accessible name and role, use an ARIA locator instead of searching the snapshot yourself.

1. Set up Puppeteer and capture a snapshot

Install Puppeteer in a Node.js project:

npm install puppeteer

This complete example opens a page, captures its accessibility tree, handles a possible null result, and closes the browser even if navigation or capture fails:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });

    const snapshot = await page.accessibility.snapshot();
    if (snapshot === null) {
      console.log('No accessibility snapshot was returned.');
    } else {
      console.dir(snapshot, { depth: null });
    }
  } finally {
    await browser.close();
  }
})();

snapshot() is asynchronous and returns a serialized root node or null. Treat the result as structured accessibility data, not a visual or DOM dump. Fields such as name, role, description, checked, disabled, and busy may be present, but optional fields are not guaranteed for every node. Check the type definitions and API reference for your installed Puppeteer version.

2. Choose the tree detail and scope

Include nodes Puppeteer normally prunes

By default, interestingOnly is true. Puppeteer filters nodes it considers uninteresting to provide a simpler tree. Set it to false when investigating structure that the default snapshot omits:

const snapshot = await page.accessibility.snapshot({
  interestingOnly: false,
});

A fuller tree can be more useful for diagnostics, but it can also be larger and harder to scan. Start with the default for routine inspection; request all nodes when the question requires them.

Capture a subtree with root

Pass an element handle as root to focus the snapshot on a particular part of the page:

const region = await page.$('main');
if (!region) {
  throw new Error('The main element was not found');
}

const snapshot = await page.accessibility.snapshot({ root: region });
console.dir(snapshot, { depth: null });

The selector and element handle must resolve on the page you intend to inspect. If your editor reports that the root option has a different type, check the Puppeteer version installed in the project and use its matching type definitions.

Include iframe accessibility trees

Iframe inclusion is off by default. Set includeIframes: true when you need accessibility information from iframe subtrees:

const snapshot = await page.accessibility.snapshot({
  interestingOnly: false,
  includeIframes: true,
});
console.dir(snapshot, { depth: null });

This option controls whether iframe trees are included; it does not change the fact that the result is a browser accessibility representation. If a frame is cross-origin or its content is unavailable, investigate the page and frame loading behavior as well as the snapshot options.

Combine options deliberately

Option Default Use it when
interestingOnly true You need nodes Puppeteer otherwise prunes; false requests the fuller tree.
root Full page You want the snapshot rooted at an ElementHandle.
includeIframes false You need iframe accessibility trees in the frame subtree.

3. Read and search the serialized tree

Each node can have children. A recursive traversal is useful for focused diagnostics or for finding a node by a property. For example, this traversal returns the first node marked focused and safely handles a null snapshot:

function findFocusedNode(node) {
  if (!node) return null;
  if (node.focused) return node;

  for (const child of node.children ?? []) {
    const found = findFocusedNode(child);
    if (found) return found;
  }
  return null;
}

const snapshot = await page.accessibility.snapshot();
const focusedNode = snapshot ? findFocusedNode(snapshot) : null;
console.log(focusedNode?.name ?? 'No focused node in this snapshot');

Do not assume every node has every property. Check for children and optional values before reading them. For a very deep or large tree, an iterative traversal can avoid growing the JavaScript call stack:

function findNode(root, predicate) {
  if (!root) return null;
  const stack = [root];

  while (stack.length) {
    const node = stack.pop();
    if (predicate(node)) return node;
    for (const child of node.children ?? []) stack.push(child);
  }
  return null;
}

const button = findNode(snapshot, node =>
  node.role === 'button' && node.name === 'Continue'
);

Use tree traversal to inspect or report the representation. For an action, an ARIA locator is usually a better fit.

4. Interact by accessible name and role

Puppeteer’s ARIA selector queries by computed accessible name and role. Use a locator when the task is to click or fill a control, rather than capturing a tree and writing a custom search over it:

await page.locator('::-p-aria([name="Click me"][role="button"])').click();
await page.locator('::-p-aria(Search)').fill('accessibility testing');

The ARIA selector supports accessible-name and role matching, with ARIA relationships such as labelledby resolved before the query. Locators wait for action conditions such as visibility and enabled state. If several elements share the same accessible name, make the selector more specific or narrow it to a relevant container.

5. Understand what a snapshot can tell you

Puppeteer exposes Blink’s accessibility tree. The browser translates accessibility data into platform APIs, and operating systems or assistive technologies may further filter what users receive. A snapshot is therefore useful for inspecting the browser’s accessibility representation, but it cannot establish exactly what every screen reader will announce. When your test concerns a particular user experience, validate it with the relevant browser, platform, and assistive technology.

Version matters: API methods, options, and serialized properties can change. The supplied research identifies Puppeteer 25.12.0 in the current reference and records a snapshot enhancement in 24.37.0. Use the documentation matching the version in your project rather than assuming an example from a different release applies unchanged.

6. Troubleshoot common problems

Symptom Likely cause What to do
snapshot is null The API returned no serialized root for this capture. Handle null before traversing or printing. Confirm navigation completed and the intended page is loaded, then capture again.
A node is missing The default interestingOnly: true pruned it, or the inspected root excludes it. Try interestingOnly: false; check that root is the intended element.
Iframe content is absent includeIframes defaults to false. Set includeIframes: true and verify the relevant frame has loaded.
Expected property is undefined Serialized properties are optional and vary by node. Use optional chaining or explicit checks; consult the installed version’s SerializedAXNode definition.
ARIA locator finds no match The computed name or role differs from the assumed value, the control is not yet available, or the selector is ambiguous. Inspect the snapshot, check the accessible name and role, wait for the page state you need, and scope the locator if duplicates exist.
Editor rejects the root option Code and type definitions may be from different Puppeteer versions. Check the installed package version and its API reference and types.
Snapshot differs from screen-reader output Platform and assistive technology layers can filter or translate the browser tree. Validate with the browser, operating system, and assistive technology relevant to the behavior being tested.

7. Performance, reliability, and cost

Snapshot cost depends on the page and the amount of tree data requested. A full tree can include more nodes than the default filtered result, and iframe inclusion expands the inspected frame subtree. For repeated checks, capture only when needed, scope to a relevant root where practical, and avoid logging huge trees in routine runs.

For reliable automation, wait for the page state your task depends on before capturing or acting. Handle null snapshots and optional node properties. Prefer ARIA locators for actions because they express the target in user-facing name-and-role terms and wait for conditions needed to act. A snapshot is diagnostic evidence about a browser tree, not a guarantee of identical announcements across platforms.

Puppeteer itself is an open-source browser automation library; infrastructure cost depends on where and how you run the browser, which is outside the accessibility snapshot API. If the task is to obtain page screenshots instead of inspect accessibility data, ScreenshotNeo is a website screenshot API and MCP server. Its screenshot options, API usage, and plan details are documented at ScreenshotNeo docs.

8. Or skip the browser setup

If your goal is a clean page image rather than an accessibility-tree inspection, ScreenshotNeo captures a URL with one GET request. See the API documentation for request options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. Response headers say which page verdict applied and whether the shot was billed.
  • An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
  • The free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan.

Create a free ScreenshotNeo account for 1,000 screenshots a month, with no card required.

9. FAQ

Does an accessibility snapshot return HTML?

No. It returns serialized accessibility information for the page or selected root, not a DOM or visual representation.

Should I use a snapshot or an ARIA locator?

Use a snapshot to inspect accessibility structure. Use an ARIA locator to find and act on a control by its computed name and role.

Does a successful snapshot prove a page is accessible?

No. It shows the browser’s accessibility representation. It does not replace testing with relevant assistive technologies or broader accessibility checks.

Can I rely on every serialized field being present?

No. Properties are optional and depend on the node. Check values before using them and consult the version-specific type definition.