Answer
In recent Puppeteer releases the includeHidden option for page.accessibility.snapshot() defaults to false. With the default, nodes that are not exposed to assistive technology are omitted from the AXTree snapshot. That means aria-hidden="true" nodes and CSS-hidden nodes are excluded by default.
The default changed in Puppeteer v19.0.0, released ~Nov 2022, from true to false to match the Chrome DevTools Protocol default for Accessibility.getAXTree. Puppeteer v21+ documents the type as includeHidden?: boolean with default false.
Confirmed facts
- Puppeteer v19+ passes
interestingOnly: true to CDP when includeHidden is omitted or false. The snapshot therefore reflects Chromium’s accessibility tree, not the DOM.
- When
includeHidden is false, aria-hidden="true" nodes are excluded. The exclusion is performed by Blink’s accessibility tree construction and is consistent across Chrome Stable, Beta, Dev and Canary for a given Chromium version.
- CSS-hidden nodes are also excluded with the default:
display:none, visibility:hidden, zero-size/off-screen elements that are not interesting for accessibility are omitted.
- Filtering is implemented in Chromium, not in Puppeteer. Puppeteer only forwards the flag to CDP.
Likely explanation for unexpected hidden nodes
If you are still seeing hidden nodes, the most likely cause is version mismatch.
- Puppeteer v18 and earlier defaults to
includeHidden: true. Hidden nodes are included unless you explicitly pass {includeHidden: false}.
- Custom elements with
role="none" or role="presentation" are removed from the accessibility tree regardless of includeHidden. They are semantically neutral, not hidden.
- Shadow DOM nodes are included when their shadow host is accessible.
includeHidden does not change shadow boundary traversal.
- The CDP parameter
interestingOnly also filters out layout-only containers with no name/role. This is separate from hidden filtering and can change node counts between Chromium versions.
Steps needed for this case
- Confirm Puppeteer version:
npm list puppeteer
v19.0.0+ has default false. v18.x has default true.
- Run a minimal comparison:
const snapDefault = await page.accessibility.snapshot();
const snapHidden = await page.accessibility.snapshot({includeHidden: true});
Compare node counts. With default false, aria-hidden="true" and CSS-hidden elements should be absent from snapDefault but present in snapHidden.
- Verify the CDP call:
DEBUG=puppeteer:* node script.js
Check that Accessibility.getAXTree is sent with interestingOnly: true when includeHidden is omitted.
- If you need stable behavior across Chrome channels, pin the Chromium version and test with
executablePath pointing to Stable/Beta/Dev/Canary. Filtering is consistent per Chromium version.
Future change risk: The default is now aligned with CDP and the W3C Accessibility Tree spec. A change back to true would be a breaking change and would require a major version bump with migration guidance. It is unlikely in the near term.
One missing diagnostic detail that changes the recommendation: what Puppeteer version and Chrome channel you are running. If you are on v18 or earlier, the fix is to explicitly pass {includeHidden: false}. If you are on v19+, the behavior you see is expected and you should filter at the test level rather than rely on a default change.