NativeInput is a CDP domain in every new session, pool browsers included. There’s nothing to turn on: connect to cdpUrl, open a page-level CDP session, send commands.
It keeps its own cursor inside the browser: it doesn’t move the machine’s mouse or draw anything in the live view.
Quickstart
NativeInput, not nativeInput) and there’s no enable call. Input goes to the active tab; with several open, attach to the one you mean to drive. The examples below use the TypeScript input from the quickstart; in Python, input_session.send takes the same methods and parameters.
Mouse
There’s no singleclick command. Move, then press and release:
getBoundingClientRect() reports at default zoom, so an element’s center is a click target; the numbers in these examples are placeholders.
Keyboard
Text
Click into a field, then insert the text in one call. It goes to the focused text control as typed text, not as a DOM value or one key event per character. Any Unicode works, up to 16,384 UTF-8 bytes.insertText refuses to run with a modifier down.
Keys and shortcuts
Keys are physical DOM codes:KeyA, Digit1, Enter, Tab, Escape, ArrowLeft, ShiftLeft, ControlLeft. Every keyDown needs its keyUp, and left and right modifiers are separate keys.
- Keys follow a US layout plus the modifiers you hold. Pass
keyto override the character, for example{ code: "KeyA", key: "ä" }. UseinsertTextfor emoji. - A key repeats only when you send another
keyDown, never on a timer. - Shortcuts reach Chrome’s own UI too:
ControlLeft+KeyLfocuses the address bar. Release the chord before inserting a URL, and wait for the navigation separately. - Keys and text go wherever Chrome’s focus is. After
Ctrl+Lor a click on the toolbar, focus stays in the address bar until you click into the page. - CapsLock is tracked per session and cleared by
reset. NumLock, ScrollLock and IME or dead-key composition aren’t supported.
Coordinates and state
Every command answers{ state }. getState reads it without changing anything.
Read
width and height rather than assuming them, and read them again after a resize (window size sets the starting size). window coordinates aren’t screen coordinates, and screenshot pixels or CSS pixels under zoom or device emulation aren’t necessarily the same units.
To show the cursor in your own viewer, place your indicator from the returned x and y, not your local mouse. If your image covers the same surface scaled but uncropped, that’s x * imageWidth / width and y * imageHeight / height. State isn’t pushed: read it from command responses or call getState.
One controller at a time
State belongs to the browser window, not your connection: a new connection starts from the last cursor position, coordinate space and focus. Each window takes input from one connection. The first command that sends input takes control; other connections can still callgetState and see the same state with ownsControl: false.
To hand over, call NativeInput.reset on the current controller or detach it. Reset releases anything held, clears CapsLock and gives up control, but keeps the cursor where it is: move again before the next click. Disconnecting does the same cleanup. Reset before moving a controlled tab to another window.
Send commands one at a time and await each. A response means the input was dispatched, not that the page reacted: wait for navigation or elements with your framework’s usual waits.
Raw CDP
On the browser-level WebSocket, find the page withTarget.getTargets, attach with Target.attachToTarget and flatten: true, and put the returned session ID on each command:
id and sessionId, with the state in result.state; check for error first. On a WebSocket opened straight to the page target (cdpUrl with /devtools/browser/<id> replaced by /devtools/page/<targetId>), leave sessionId out. This CDP session ID is not the Driver sessionId you use with the API.
Commands
button is left, middle, right, back or forward. clickCount defaults to 1.
Troubleshooting
Native input drives the browser only, not the machine’s desktop. Native OS dialogs such as file pickers, pointer lock and raw relative mouse movement aren’t covered, and it isn’t guaranteed to look like physical hardware input to every site or widget.