Puppeteer Keypress Options Explained
Learn when to use Puppeteer’s press(), type(), down(), up(), and sendCharacter(), what their options do, and how to troubleshoot keyboard input.
Puppeteer has several keyboard methods for different jobs: use page.keyboard.type(text, options) to enter a string, page.keyboard.press(key, options) to press a named or special key, and down() followed by up() when a key must stay held across actions. press() accepts text, delay, and commands; type() accepts delay. The right choice depends on the events your page needs to receive.
1. Run a complete keyboard example
This runnable Node.js example launches Chromium, types into a focused input, presses Enter, and closes the browser. Install Puppeteer with npm install puppeteer, save the code as keyboard.mjs, then run node keyboard.mjs.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setContent('<input id="query">');
await page.locator('#query').click();
await page.keyboard.type('Puppeteer keyboard');
await page.keyboard.press('Enter');
console.log(await page.locator('#query').map(input => input.value).wait());
} finally {
await browser.close();
}
The example uses the current locator API to focus the input before sending keys. Keyboard events go to the focused page element, so focus the intended target before calling the keyboard methods. For the complete API details, see Puppeteer’s Keyboard class, press(), type(), and KeyInput references.
2. Choose the right keyboard method
| Task | Method | Behavior |
|---|---|---|
| Enter ordinary text | keyboard.type(text, options) |
Sends a keyboard event sequence for each character. A held modifier such as Shift does not transform the string. |
| Press a named or special key | keyboard.press(key, options) |
A shortcut for down() followed by up(). |
| Keep a key held across actions | keyboard.down(key), then keyboard.up(key) |
Use for modifiers and interactions such as selecting text while moving with an arrow key. |
| Send character input without keydown or keyup | keyboard.sendCharacter(char) |
Dispatches keypress and input events only. |
For example, type a phrase and then use named keys to edit it:
await page.keyboard.type('Hello');
await page.keyboard.press('ArrowLeft');
await page.keyboard.press('Backspace');
3. Understand press() options
The signature is page.keyboard.press(key, options?). The key is a Puppeteer KeyInput, such as 'Enter', 'ArrowLeft', 'Control', or 'KeyA'. Consult the official KeyInput reference for the complete accepted key list; key names are not all ordinary text characters.
| Option | Meaning | Example |
|---|---|---|
text |
When specified, generates an input event with this text. | { text: 'x' } |
delay |
Waits between keydown and keyup, in milliseconds. Defaults to 0. |
{ delay: 100 } |
commands |
Specifies keyboard shortcut command names documented by Chromium. | { commands: ['selectAll'] } |
The valid command names are defined by Chromium; check the Puppeteer press() reference and its linked Chromium source rather than assuming a command spelling. The text option is useful when a key press should force text input. It does not turn press() into the general-purpose string method: use type() for a string of characters.
await page.keyboard.press('Enter', { delay: 100 });
await page.keyboard.press('KeyA', { text: 'a' });
If a modifier is already held, modifiers affect press(). For example, holding Shift while pressing a letter can produce uppercase input. press() itself is still a down-and-up pair; use separate down() and up() calls when the modifier needs to remain held for multiple actions.
4. Type strings and control typing delay
keyboard.type(text, { delay }) types each character through the keyboard event sequence. Its delay defaults to zero. The delay for type() is documented as time between key presses; for press(), it is the wait between keydown and keyup. These settings describe different timing points.
await page.keyboard.type('World', { delay: 100 });
await page.keyboard.type('Done');
A held Shift key does not capitalize text sent with type(). If you need modifier-sensitive keyboard behavior, use down() and press() for those key events, or provide the desired string directly to type().
5. Hold and release keys
down(key) dispatches keydown and leaves the key held. Calling down() again for an already-held key sets repeat. Call up(key) to release it. Modifier state stays active for later key presses until released.
await page.keyboard.type('Hello World!');
await page.keyboard.press('ArrowLeft');
await page.keyboard.down('Shift');
for (let i = 0; i < ' World'.length; i++) {
await page.keyboard.press('ArrowLeft');
}
await page.keyboard.up('Shift');
await page.keyboard.press('Backspace');
This follows the official class example: hold Shift while moving the cursor left to select text, release Shift, then delete the selection. If an exception might occur between down() and up(), use try/finally to release the modifier so it cannot affect later actions.
await page.keyboard.down('Shift');
try {
await page.keyboard.press('ArrowLeft');
} finally {
await page.keyboard.up('Shift');
}
6. Use sendCharacter() for character-only input
sendCharacter(char) emits keypress and input events without keydown or keyup. It differs from press(), which combines down and up, and from type(), which sends the full per-character sequence. Choose it only when the page specifically needs character input without the keydown/keyup pair.
7. Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Text appears in the wrong field or nowhere | The intended element does not have focus. | Locate and focus the input before using page.keyboard; check that a dialog or frame has not taken focus. |
ArrowDown or Enter does not type literal text |
These are named keys, not ordinary text input. | Use type() for text; use press() for the key action. |
| Holding Shift does not uppercase a string | type() ignores held modifiers when generating its text. |
Pass the intended capitalization to type(), or use key-by-key press() with Shift held. |
| Subsequent actions behave as if a modifier is active | A key was pressed with down() and never released. |
Call up(); release held keys in a finally block. |
| A shortcut behaves differently than expected on macOS | The Keyboard class documentation notes that macOS shortcuts such as Command+A for Select All do not work through this API. | Do not assume this shortcut works through page.keyboard; consult the current Puppeteer documentation and issue reference for platform-specific status. |
| An option or key name is rejected or has no effect | The installed Puppeteer version may differ from the API page or the key/command name may be invalid. | Check the installed-version documentation and the KeyInput/Chromium command references. |
Puppeteer’s API pages in the research dossier show differing version labels across methods. Verify newer options against the documentation matching your installed package version.
8. Performance and reliability notes
With no delay, type() runs without an intentional per-character wait. A nonzero delay adds time as characters are sent, so reserve it for cases where gradual keyboard events matter. Likewise, a delay on press() intentionally holds the key between keydown and keyup. Avoid adding delays as a substitute for waiting for the page to be ready: focus the correct element and wait for the application state you need before typing.
Keyboard input is event-driven. A field may update only after particular events, and special keys do not mean the same thing as inserting text. Select the method based on the event sequence the target page expects, release held keys reliably, and verify the resulting field value or application state when correctness matters. No keyboard method guarantees that a page’s own event handlers or validation will accept the input.
9. Or skip the browser setup
If your goal is a screenshot rather than keyboard interaction, ScreenshotNeo is a website screenshot API and MCP server. One GET request captures a URL as an image or PDF. See the ScreenshotNeo API documentation.
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 banners, popups, and chat widgets are removed before the shot.
- Bot checks, blank pages, and failed loads are never billed.
- An MCP server lets AI agents take screenshots.
- 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000.
Sign up free for 1,000 screenshots a month, no card required.
10. FAQ
Can I use keyboard.press() to type a sentence?
Use type() for a sentence. press() is for one named key press, with options for text input, timing, and commands.
Does keyboard.type() behave like a physical keyboard?
It sends keyboard events for each character, but it is a browser automation API and its modifier behavior is explicitly different: held modifiers do not transform text typed with type().
Where can I find every valid key name?
Use Puppeteer’s KeyInput reference, which lists accepted keys.


