Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To hold a key in Puppeteer, call await page.keyboard.down('ArrowLeft'), do the action that needs the key held, then call await page.keyboard.up('ArrowLeft'). Use the same key name in both calls. Wrap the intervening work in try/finally when it might fail, so the key is released even if an action throws.

Hold a key with down() and up()

Puppeteer’s virtual keyboard keeps a key pressed between the down() and up() calls. The first dispatches a keydown event; the second dispatches keyup. For example:

await page.keyboard.down('ArrowLeft');
// Do the action that should happen while ArrowLeft is held.
await page.keyboard.up('ArrowLeft');

Use this pattern when the page must respond to a key remaining held during another action, rather than just to a single press. Puppeteer’s current API method references displayed version 25.12.0 on October 3, 2026; check the documentation for the version installed in your project if behavior or accepted key names matter.

Release the key if an action fails

If work between the down and up calls can throw an error, put the dependent action in a try block and release in finally:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.keyboard.down('Shift');
try {
  await page.keyboard.press('ArrowLeft');
} finally {
  await page.keyboard.up('Shift');
}

This ensures the script attempts the release on both success and failure paths. Use the same key value for the matching down and up calls.

Choose the right keyboard method

What you need Use Behavior
Keep a key held across another action down(key), then up(key) Dispatches keydown, keeps the key held in Puppeteer’s keyboard state, then dispatches keyup when released.
Press and release once, optionally with a delay press(key, { delay }) A shortcut for down and up. The optional delay is the number of milliseconds between keydown and keyup; it defaults to zero.
Enter ordinary text type(text, { delay }) Sends text character by character. The optional delay is between key events and defaults to zero.
Press a key on a particular element elementHandle.press(key) Focuses the element, then uses a keyboard down/up pair.

These methods serve different purposes: press() is not a sustained hold, and type() is text entry rather than a way to send special keys such as arrows. Holding Shift does not make type() convert its text to uppercase.

Use modifiers and named keys

To select text while moving left, hold Shift while pressing the arrow key, release Shift, and then delete the selection:

await page.keyboard.down('Shift');
await page.keyboard.press('ArrowLeft');
await page.keyboard.up('Shift');
await page.keyboard.press('Backspace');

Puppeteer documents modifier names including Shift, Meta, Control, and Alt. A held modifier stays active for subsequent key presses until you release it with up(). The KeyInput type also includes names such as ArrowLeft, ArrowDown, Backspace, and Enter, as well as letter and digit representations. See the Puppeteer KeyInput reference for the accepted values.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For example, the API reference shows a shifted A using:

await page.keyboard.down('Shift');
await page.keyboard.press('KeyA');
await page.keyboard.up('Shift');

Keyboard input is sent to the focused page context. Focus the intended control through your normal page interaction before sending keys. If you use ElementHandle.press(), Puppeteer focuses that element first.

Troubleshoot key presses that do not work

  • The key is not held during the later action: use down() and up() around that action. press() releases automatically after its down/up pair.
  • An arrow or other special key is treated like text: use press() or explicit down/up calls for special keys; reserve type() for text.
  • The wrong control reacts: make sure the intended element has focus before sending page-level keyboard input, or use ElementHandle.press() to focus an element before pressing.
  • A modifier affects more keys than intended: release it with up() after the dependent key action. Put that release in finally if intervening code can fail.
  • The key name is rejected or does not behave as expected: check that the value is a documented Puppeteer KeyInput and is spelled identically in both down and up calls.
  • A macOS shortcut such as Command+A does not work: Puppeteer’s current Keyboard class reference notes a limitation for keyboard shortcuts such as ⌘ A on macOS. This caveat concerns shortcuts and should not be generalized to all keyboard actions.

Or skip the browser setup

If your goal is a screenshot rather than testing keyboard interaction, ScreenshotNeo can return a site screenshot with one GET request. Its screenshot API does not operate a browser keyboard or reproduce key holds; use Puppeteer above when a page interaction must occur before capture.

For a direct capture, replace the sample URL with the page you need and use your API key. See the ScreenshotNeo documentation for API options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo removes cookie or consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers identify the page verdict and billing status. It also provides an MCP server for AI agents, with tools for screenshots, page information, and PDF capture. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free plan to try it without a card.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Frequently Asked Questions

Does Puppeteer’s key hold wait for a fixed amount of time?

No. With explicit down/up calls, the key remains held until your code reaches the release call; a timed interval is only needed if your task requires one.

Can I use this pattern to hold Shift while typing uppercase text?

No. Puppeteer’s type() sends text character by character, and holding Shift does not make it uppercase. Use the appropriate text directly or send individual key actions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.