ScreenshotNeo

BlogHow-to

How to Send a Character with Puppeteer

Use Puppeteer’s keyboard APIs to type text, send a single character, or press a named key. See runnable examples, event differences, and fixes for common input issues.

By the ScreenshotNeo team4 October 20265 min read

For ordinary text, focus the target field and call await page.keyboard.type('Hello'). Puppeteer types each character with keyboard and input events. For a named key such as Enter, call await page.keyboard.press('Enter'). Use sendCharacter() only when you specifically need keypress and input events without keydown or keyup.

Runnable setup

This complete Node.js example launches Chromium, focuses an input, types text, presses Enter, and closes the browser. Install Puppeteer with npm install puppeteer; its package includes a compatible browser download.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setContent('<input id="search">');
    await page.focus('#search');
    await page.keyboard.type('Puppeteer');
    await page.keyboard.press('Enter');
    const value = await page.$eval('#search', el => el.value);
    console.log(value);
  } finally {
    await browser.close();
  }
})();

Use Keyboard.type() and the Puppeteer API reference for exact API details.

Choose the right input method

Need Method Behavior
Type ordinary text into the focused element page.keyboard.type(text, options?) Sends keydown, keypress/input, and keyup for each character.
Type into a selector target page.type(selector, text, options?) Selector convenience API with optional per-character delay.
Set a field value through a locator page.locator(selector).fill(value) Convenient value entry; use keyboard typing if per-character keyboard events matter.
Send only character input events page.keyboard.sendCharacter(char) Dispatches keypress and input, without keydown or keyup.
Press a named key page.keyboard.press(key) Performs a key down and up, useful for Enter or ArrowDown.

Type text into a focused field

keyboard.type() sends text to the currently focused element. Focus explicitly when page actions may have moved focus:

await page.focus('#message');
await page.keyboard.type('Hello, world!');

Its optional delay is milliseconds between key events and defaults to zero. A delay can help when a page reacts to each keystroke or when a human-paced sequence is needed:

await page.keyboard.type('Search phrase', { delay: 75 });

For example, to observe the value after typing:

await page.focus('#query');
await page.keyboard.type('weather');
const value = await page.$eval('#query', input => input.value);
console.log(value);

Type into a selector or locator

page.type() targets a selector directly:

await page.type('#mytextarea', 'Hello');
await page.type('#mytextarea', 'World', { delay: 100 });

For a locator-based flow, Puppeteer’s getting-started guide demonstrates fill() for entering a field value. Prefer this when the goal is to set the value rather than produce a realistic per-character keyboard sequence:

await page.locator('input[name="q"]').fill('Puppeteer guide');

Send one character or press a named key

For one ordinary character, type() is usually the clearest choice:

await page.focus('#code');
await page.keyboard.type('A');

sendCharacter() is a lower-level option. It dispatches keypress and input, but not keydown or keyup. Use it only when that event distinction is required:

await page.keyboard.sendCharacter('A');

Special keys are not ordinary text. Use press() for Enter, arrows, and other named keys listed by Puppeteer:

await page.keyboard.press('Enter');
await page.keyboard.press('ArrowDown');

For a modifier-sensitive key combination, use down() and up() around the key. Modifiers affect down() and press(); they do not transform supplied text passed to type().

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

Common errors and fixes

Symptom Likely cause Fix
Text goes nowhere or into another field The intended element does not have focus. Focus it with page.focus(selector) or use page.type(selector, text).
Enter appears as text or the form does not submit A named key was passed to a text API. Use page.keyboard.press('Enter') after focusing the field.
Holding Shift does not capitalize the string keyboard.type() ignores modifier state for supplied text. Pass the desired uppercase text directly, or use down(), press(), and up() for a modifier-sensitive key action.
Page handler does not react as expected to sendCharacter() That method omits keydown and keyup. Use type() for the complete per-character sequence, or implement behavior around the events actually required.
Typing runs before the field exists The page has not rendered the target yet. Wait for it, then focus and type: await page.waitForSelector('#query'); await page.type('#query', 'text');
Typing into a disabled or read-only field has no effect The browser prevents edits to that field. Wait for the application to enable it or choose an editable target; do not assume keyboard input can override page rules.

Performance and reliability

With the default zero delay, typing is the simplest and fastest sequence for normal automation. A positive delay adds time per character, so use it only when the page depends on intermediate keystrokes or pacing is part of the task. For large values where keyboard events are irrelevant, locator fill() can express the intent more directly.

Keep focus and readiness explicit: wait for the field, ensure overlays are gone, focus it, then type. Prefer a selector or locator when possible because it avoids dependence on whichever element happened to receive focus. Close the browser in a finally block so failures do not leave Chromium running.

Or skip the browser setup

If your task is capturing a page rather than automating its input, ScreenshotNeo returns a screenshot or PDF from one API request. See the 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; response headers report the page verdict and billing status.
  • An MCP server lets AI agents use screenshot, page information, and PDF capture tools.
  • 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000.

Sign up for free and capture 1,000 screenshots a month with no card.

FAQ

Does keyboard.type() type into a specific selector?

No. It types into the focused element. Focus the field first, or use page.type(selector, text).

Should I use fill() or keyboard typing?

Use fill() to set a value; use keyboard typing when the page must receive per-character keyboard events.

How do I type a newline?

For an Enter key action, call page.keyboard.press('Enter'). Whether that inserts a line break or submits depends on the focused control and page behavior.

References