A high-level API to control headless Chrome and Firefox browsers over the DevTools Protocol and WebDriver BiDi
94
Realistic keyboard, mouse, and touchscreen input simulation with timing controls and platform-specific key mappings.
Provides keyboard input simulation with support for key combinations, text typing, and special keys.
interface Keyboard {
/** Press key down (without releasing) */
down(key: string, options?: KeyDownOptions): Promise<void>;
/** Release key */
up(key: string): Promise<void>;
/** Press and release key */
press(key: string, options?: PressOptions): Promise<void>;
/** Type text character by character */
type(text: string, options?: TypeOptions): Promise<void>;
/** Send single character */
sendCharacter(char: string): Promise<void>;
}
interface KeyDownOptions {
/** Text to insert */
text?: string;
/** Commands to send (Mac only) */
commands?: string[];
}
interface PressOptions {
/** Delay between key down and up */
delay?: number;
/** Text to insert */
text?: string;
/** Commands to send (Mac only) */
commands?: string[];
}
interface TypeOptions {
/** Delay between key presses */
delay?: number;
}Usage Examples:
import puppeteer from "puppeteer-core";
const browser = await puppeteer.launch({ executablePath: "/path/to/chrome" });
const page = await browser.newPage();
await page.goto("https://example.com");
const keyboard = page.keyboard;
// Basic typing
await page.focus("#text-input");
await keyboard.type("Hello World!", { delay: 100 });
// Key combinations
await keyboard.down("Control");
await keyboard.press("a"); // Select all
await keyboard.up("Control");
await keyboard.down("Control");
await keyboard.press("c"); // Copy
await keyboard.up("Control");
// Special keys
await keyboard.press("Tab");
await keyboard.press("Enter");
await keyboard.press("Escape");
await keyboard.press("Backspace");
// Arrow keys and navigation
await keyboard.press("ArrowUp");
await keyboard.press("ArrowDown");
await keyboard.press("ArrowLeft");
await keyboard.press("ArrowRight");
await keyboard.press("Home");
await keyboard.press("End");
await keyboard.press("PageUp");
await keyboard.press("PageDown");
// Function keys
await keyboard.press("F1");
await keyboard.press("F12");
// Modifier combinations
await keyboard.down("Shift");
await keyboard.press("ArrowRight"); // Select text
await keyboard.up("Shift");
await keyboard.down("Alt");
await keyboard.press("Tab"); // Alt+Tab
await keyboard.up("Alt");
await browser.close();Provides mouse input simulation including movement, clicking, dragging, and scrolling.
interface Mouse {
/** Move mouse to coordinates */
move(x: number, y: number, options?: MouseMoveOptions): Promise<void>;
/** Click at coordinates */
click(x: number, y: number, options?: ClickOptions): Promise<void>;
/** Press mouse button down */
down(options?: MouseDownOptions): Promise<void>;
/** Release mouse button */
up(options?: MouseUpOptions): Promise<void>;
/** Scroll mouse wheel */
wheel(options?: MouseWheelOptions): Promise<void>;
/** Drag from current position to target */
drag(start: { x: number; y: number }, target: { x: number; y: number }): Promise<void>;
/** Drag and drop operation */
dragAndDrop(start: { x: number; y: number }, target: { x: number; y: number }, options?: DragAndDropOptions): Promise<void>;
}
interface MouseMoveOptions {
/** Number of intermediate steps */
steps?: number;
}
interface ClickOptions {
/** Mouse button to click */
button?: "left" | "right" | "middle";
/** Number of clicks */
clickCount?: number;
/** Delay between mousedown and mouseup */
delay?: number;
}
interface MouseDownOptions {
/** Mouse button to press */
button?: "left" | "right" | "middle";
/** Number of clicks */
clickCount?: number;
}
interface MouseUpOptions {
/** Mouse button to release */
button?: "left" | "right" | "middle";
/** Number of clicks */
clickCount?: number;
}
interface MouseWheelOptions {
/** Horizontal scroll delta */
deltaX?: number;
/** Vertical scroll delta */
deltaY?: number;
}
interface DragAndDropOptions {
/** Delay during drag operation */
delay?: number;
}Usage Examples:
const mouse = page.mouse;
// Basic mouse operations
await mouse.move(100, 200);
await mouse.click(100, 200);
// Different click types
await mouse.click(300, 400, { button: "right" }); // Right-click
await mouse.click(500, 600, { button: "middle" }); // Middle-click
await mouse.click(700, 800, { clickCount: 2 }); // Double-click
// Mouse down/up for custom timing
await mouse.move(150, 250);
await mouse.down();
await page.waitForTimeout(1000); // Hold for 1 second
await mouse.up();
// Drag operations
await mouse.move(100, 100);
await mouse.down();
await mouse.move(200, 200, { steps: 10 }); // Smooth movement
await mouse.up();
// Drag and drop
await mouse.dragAndDrop(
{ x: 100, y: 100 },
{ x: 300, y: 300 },
{ delay: 100 }
);
// Scrolling
await mouse.move(500, 500);
await mouse.wheel({ deltaY: -100 }); // Scroll up
await mouse.wheel({ deltaY: 100 }); // Scroll down
await mouse.wheel({ deltaX: -50 }); // Scroll left
await mouse.wheel({ deltaX: 50 }); // Scroll right
// Complex mouse interactions
const element = await page.$("#draggable");
if (element) {
const box = await element.boundingBox();
if (box) {
// Click and drag element
await mouse.move(box.x + box.width / 2, box.y + box.height / 2);
await mouse.down();
await mouse.move(box.x + 100, box.y + 100, { steps: 5 });
await mouse.up();
}
}Provides touch input simulation for mobile and touch-enabled devices.
interface Touchscreen {
/** Tap at coordinates */
tap(x: number, y: number): Promise<void>;
/** Start touch at coordinates */
touchStart(touches: TouchPoint[]): Promise<void>;
/** Move touch points */
touchMove(touches: TouchPoint[]): Promise<void>;
/** End touch */
touchEnd(): Promise<void>;
}
interface TouchPoint {
x: number;
y: number;
/** Touch identifier for multi-touch */
id?: number;
/** Touch radius */
radiusX?: number;
radiusY?: number;
/** Touch rotation angle */
rotationAngle?: number;
/** Touch pressure */
force?: number;
}Usage Examples:
const touchscreen = page.touchscreen;
// Basic tap
await touchscreen.tap(200, 300);
// Multi-touch gestures
await touchscreen.touchStart([
{ x: 100, y: 100, id: 0 },
{ x: 200, y: 200, id: 1 }
]);
// Pinch gesture (zoom out)
await touchscreen.touchMove([
{ x: 110, y: 110, id: 0 },
{ x: 190, y: 190, id: 1 }
]);
await touchscreen.touchEnd();
// Swipe gesture
await touchscreen.touchStart([{ x: 300, y: 400 }]);
await touchscreen.touchMove([{ x: 100, y: 400 }]); // Swipe left
await touchscreen.touchEnd();
// Complex touch interaction
const button = await page.$("#touch-button");
if (button) {
const box = await button.boundingBox();
if (box) {
await touchscreen.tap(
box.x + box.width / 2,
box.y + box.height / 2
);
}
}Common key constants and platform-specific mappings:
type Key =
| "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
| "Power" | "Eject" | "Abort" | "Help" | "Backspace" | "Tab"
| "Numlock" | "Scrolllock" | "Delete" | "Escape" | "F1" | "F2"
| "F3" | "F4" | "F5" | "F6" | "F7" | "F8" | "F9" | "F10"
| "F11" | "F12" | "F13" | "F14" | "F15" | "F16" | "F17" | "F18"
| "F19" | "F20" | "F21" | "F22" | "F23" | "F24" | "Digit0"
| "Digit1" | "Digit2" | "Digit3" | "Digit4" | "Digit5" | "Digit6"
| "Digit7" | "Digit8" | "Digit9" | "KeyA" | "KeyB" | "KeyC"
| "KeyD" | "KeyE" | "KeyF" | "KeyG" | "KeyH" | "KeyI" | "KeyJ"
| "KeyK" | "KeyL" | "KeyM" | "KeyN" | "KeyO" | "KeyP" | "KeyQ"
| "KeyR" | "KeyS" | "KeyT" | "KeyU" | "KeyV" | "KeyW" | "KeyX"
| "KeyY" | "KeyZ" | "Semicolon" | "Equal" | "Comma" | "Minus"
| "Period" | "Slash" | "Backquote" | "BracketLeft" | "Backslash"
| "BracketRight" | "Quote" | "Altleft" | "Altright" | "CapsLock"
| "ControlLeft" | "MetaLeft" | "ShiftLeft" | "ControlRight"
| "MetaRight" | "ShiftRight" | "ContextMenu" | "Enter" | "Space"
| "ArrowDown" | "ArrowLeft" | "ArrowRight" | "ArrowUp" | "End"
| "Home" | "Insert" | "PageDown" | "PageUp" | "PrintScreen"
| "NumpadDivide" | "NumpadMultiply" | "NumpadSubtract"
| "NumpadAdd" | "NumpadEnter" | "NumpadDecimal" | "Numpad0"
| "Numpad1" | "Numpad2" | "Numpad3" | "Numpad4" | "Numpad5"
| "Numpad6" | "Numpad7" | "Numpad8" | "Numpad9" | "Copy"
| "Cut" | "Paste" | "AudioVolumeMute" | "AudioVolumeDown"
| "AudioVolumeUp" | "MediaTrackNext" | "MediaTrackPrevious"
| "MediaStop" | "MediaPlayPause" | "BrowserSearch" | "BrowserHome"
| "BrowserBack" | "BrowserForward" | "BrowserRefresh"
| "BrowserStop" | "BrowserFavorites" | "LaunchApplication1"
| "LaunchApplication2" | "LaunchMail" | "LaunchMediaPlayer";
interface USKeyboardLayout {
[key: string]: {
keyCode: number;
shiftKeyCode?: number;
key: string;
shiftKey?: string;
code: string;
text?: string;
shiftText?: string;
location?: number;
};
}Usage Examples:
// Using key constants
await keyboard.press("Enter");
await keyboard.press("ArrowDown");
await keyboard.press("F1");
await keyboard.press("ControlLeft");
// Key combinations with proper timing
await keyboard.down("ShiftLeft");
await keyboard.press("KeyA"); // Capital A
await keyboard.up("ShiftLeft");
// Platform-specific shortcuts
const isMac = process.platform === "darwin";
const cmdOrCtrl = isMac ? "MetaLeft" : "ControlLeft";
await keyboard.down(cmdOrCtrl);
await keyboard.press("KeyC"); // Copy
await keyboard.up(cmdOrCtrl);
await keyboard.down(cmdOrCtrl);
await keyboard.press("KeyV"); // Paste
await keyboard.up(cmdOrCtrl);Complex input scenarios and best practices:
interface AdvancedInputScenarios {
/** Simulate realistic typing with human-like delays */
humanType(text: string, options?: HumanTypeOptions): Promise<void>;
/** Simulate form filling with tab navigation */
fillForm(fields: FormField[]): Promise<void>;
/** Simulate file drag and drop */
dragDropFile(filePath: string, target: ElementHandle): Promise<void>;
/** Simulate drawing/signature input */
drawPath(points: Point[], options?: DrawOptions): Promise<void>;
}
interface HumanTypeOptions {
/** Base delay between keystrokes */
baseDelay?: number;
/** Random delay variation */
variation?: number;
/** Typing mistakes probability */
mistakeRate?: number;
}
interface FormField {
selector: string;
value: string;
type?: "text" | "email" | "password" | "number";
}
interface Point {
x: number;
y: number;
}
interface DrawOptions {
pressure?: number;
smooth?: boolean;
delay?: number;
}Usage Examples:
// Realistic human typing
async function humanType(page: Page, selector: string, text: string) {
await page.focus(selector);
for (let i = 0; i < text.length; i++) {
const char = text[i];
const delay = Math.random() * 100 + 50; // 50-150ms random delay
await page.keyboard.type(char);
await page.waitForTimeout(delay);
// Occasionally make a mistake and correct it
if (Math.random() < 0.05) { // 5% mistake rate
await page.keyboard.press("Backspace");
await page.waitForTimeout(200);
await page.keyboard.type(char);
}
}
}
// Form automation with tab navigation
async function fillFormWithTabs(page: Page) {
const fields = [
{ selector: "#firstName", value: "John" },
{ selector: "#lastName", value: "Doe" },
{ selector: "#email", value: "john.doe@example.com" },
{ selector: "#phone", value: "555-0123" }
];
await page.focus(fields[0].selector);
for (const field of fields) {
await page.keyboard.type(field.value);
await page.keyboard.press("Tab");
await page.waitForTimeout(200);
}
}
// Signature/drawing simulation
async function drawSignature(page: Page, canvasSelector: string) {
const canvas = await page.$(canvasSelector);
if (!canvas) return;
const box = await canvas.boundingBox();
if (!box) return;
const startX = box.x + 50;
const startY = box.y + box.height / 2;
// Draw a simple signature curve
await page.mouse.move(startX, startY);
await page.mouse.down();
for (let i = 0; i <= 100; i++) {
const x = startX + i * 2;
const y = startY + Math.sin(i * 0.1) * 20;
await page.mouse.move(x, y);
await page.waitForTimeout(10);
}
await page.mouse.up();
}
// File drag and drop simulation
async function simulateFileDrop(page: Page, filePath: string, dropSelector: string) {
const dropZone = await page.$(dropSelector);
if (!dropZone) return;
const box = await dropZone.boundingBox();
if (!box) return;
// Simulate drag and drop events
const fileInput = await page.evaluateHandle(() => {
const input = document.createElement('input');
input.type = 'file';
input.style.display = 'none';
document.body.appendChild(input);
return input;
});
await fileInput.uploadFile(filePath);
await page.evaluate((input, dropZone) => {
const file = input.files[0];
const dt = new DataTransfer();
dt.items.add(file);
const dragEvent = new DragEvent('drop', {
dataTransfer: dt,
bubbles: true,
cancelable: true
});
dropZone.dispatchEvent(dragEvent);
}, await fileInput.asElement(), await dropZone.asElement());
}Common input-related errors and handling strategies:
class InputError extends Error {
constructor(message: string);
}
class KeyboardError extends InputError {
constructor(message: string);
}
class MouseError extends InputError {
constructor(message: string);
}Usage Examples:
// Safe input operations
async function safeType(page: Page, selector: string, text: string) {
try {
await page.waitForSelector(selector, { timeout: 5000 });
await page.focus(selector);
await page.keyboard.type(text);
return true;
} catch (error) {
console.log(`Failed to type in ${selector}:`, error.message);
return false;
}
}
// Retry mechanism for flaky inputs
async function retryClick(page: Page, x: number, y: number, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
await page.mouse.click(x, y);
return true;
} catch (error) {
console.log(`Click attempt ${i + 1} failed:`, error.message);
if (i === maxRetries - 1) throw error;
await page.waitForTimeout(1000);
}
}
return false;
}Install with Tessl CLI
npx tessl i tessl/npm-puppeteer-coredocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10