The device picker never opens
connect()/start() must run inside a user gesture (a click handler);
browsers block device prompts otherwise.
The device picker opens every time
It should not: after the first pairing,connect() reconnects through the
browser’s stored grant with no prompt. If the picker keeps appearing, check
these, in order.
- Are you calling
requestDevice()on every connect? It always opens the chooser, by design. Use it only for pairing - see Connecting once, not every time. - Grants are per top-level origin.
localhost:3000, a preview URL, and your production domain are separate stores, so operators pair once per environment. - Private/incognito windows never persist a grant.
- Some USB-serial readers report no serial number. Chrome can only store a grant permanently for a device it can identify stably; for the rest the grant lives in memory and is dropped when the reader is unplugged or the browser restarts. Refresh and in-page navigation are still prompt-free.
- A kiosk that must never prompt needs the Chrome enterprise policy
SerialAllowUsbDevicesForUrls. That is an IT deployment step, not something a page can do.
The reader is held by another tab or application
Serial devices are exclusive. If a second tab, an encoder utility, or a terminal session already holds the reader, opening it fails and the connection state becomeserror rather than authorization-required -
re-pairing will not help. Close the other holder, or call disconnect() in
the tab that no longer needs it.
Phone NFC permission is per-origin
Moving your operator flow to a new domain prompts every operator again, and a denied permission never re-prompts on its own - it must be re-enabled from the address-bar lock icon → Permissions → NFC. Screen overlays from other apps also block the prompt. The SDK surfaces both states throughonError with
operator-actionable instructions.
”Serial blocklist” lines in the browser console
When the device picker opens, Chrome logs one line per nearby Bluetooth device it excludes (for example, wireless headphones). That output comes from the browser itself - it is expected and harmless.Still stuck?
The package ships anAGENTS.md for AI coding agents, and these docs are
agent-readable - see Use Endstate with AI tools for the fastest
ways to debug an integration with your tooling.
