Implementation:Puppeteer Puppeteer CustomQueryHandler
| Property | Value |
|---|---|
| sources | packages/puppeteer-core/src/common/CustomQueryHandler.ts |
| domains | Query Handling, Extensibility |
| last_updated | 2026-02-12 00:00 GMT |
Overview
Description
CustomQueryHandler is a public interface and CustomQueryHandlerRegistry is an internal class that together provide the mechanism for registering, retrieving, and unregistering user-defined query handlers in Puppeteer. A custom query handler allows users to define their own element selection logic by implementing one or both of the queryOne and queryAll methods.
The CustomQueryHandlerRegistry class maintains a private map of registered handlers. When a handler is registered via the register method, the registry validates the name (must be alphabetic only), ensures no duplicate names exist, and ensures at least one query method is provided. It then creates an anonymous subclass of QueryHandler with interpolated functions that delegate to the registered custom selectors, and injects a registration script into the browser context via the ScriptInjector.
After registration, selectors are invoked by prefixing the selection string with <name>/ (e.g., 'lit/my-element'). A singleton instance customQueryHandlers is exported for global use.
Usage
Users register custom query handlers through the Puppeteer class methods registerCustomQueryHandler, unregisterCustomQueryHandler, customQueryHandlerNames, and clearCustomQueryHandlers. These methods delegate to the singleton customQueryHandlers registry instance.
Code Reference
Source Location
packages/puppeteer-core/src/common/CustomQueryHandler.ts
Signature
export interface CustomQueryHandler {
queryOne?: (node: Node, selector: string) => Node | null;
queryAll?: (node: Node, selector: string) => Iterable<Node>;
}
export class CustomQueryHandlerRegistry {
get(name: string): typeof QueryHandler | undefined;
register(name: string, handler: CustomQueryHandler): void;
unregister(name: string): void;
names(): string[];
clear(): void;
}
export const customQueryHandlers: CustomQueryHandlerRegistry;
Import
import {type CustomQueryHandler, customQueryHandlers} from './CustomQueryHandler.js';
I/O Contract
| Parameter | Type | Description |
|---|---|---|
| name | string |
The name to register the handler under (alphabetic characters only, [a-zA-Z]+)
|
| handler | CustomQueryHandler |
An object with optional queryOne and/or queryAll methods
|
| Method | Return Type | Description |
|---|---|---|
get(name) |
undefined | Retrieves the QueryHandler subclass for the given name |
register(name, handler) |
void |
Registers a new custom query handler |
unregister(name) |
void |
Removes a registered handler by name |
names() |
string[] |
Returns all registered handler names |
clear() |
void |
Unregisters all custom query handlers |
Usage Examples
import puppeteer from 'puppeteer';
// Register a custom query handler that selects by text content
Puppeteer.registerCustomQueryHandler('text', {
queryOne: (node, selector) => {
const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT);
while (walker.nextNode()) {
if (walker.currentNode.textContent?.includes(selector)) {
return walker.currentNode.parentElement;
}
}
return null;
},
queryAll: (node, selector) => {
const results: Node[] = [];
const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT);
while (walker.nextNode()) {
if (walker.currentNode.textContent?.includes(selector)) {
results.push(walker.currentNode.parentElement!);
}
}
return results;
},
});
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
// Use the custom handler with the 'text/' prefix
const element = await page.$('text/Example Domain');
// List registered handler names
console.log(Puppeteer.customQueryHandlerNames()); // ['text']
// Unregister a specific handler
Puppeteer.unregisterCustomQueryHandler('text');
// Clear all custom handlers
Puppeteer.clearCustomQueryHandlers();
await browser.close();