ScreenshotNeo

BlogHow-to

How to Select a Device with Puppeteer DeviceRequestPrompt

Wait for Puppeteer’s device prompt before triggering a page request, match the intended device, and pass the returned device object to select().

By the ScreenshotNeo team4 October 20267 min read

To select a device with Puppeteer’s DeviceRequestPrompt, start page.waitForDevicePrompt() before triggering the page’s device request. Use prompt.waitForDevice(predicate) to find the intended device, then pass the returned device object to prompt.select(device).

const [devicePrompt] = await Promise.all([
  page.waitForDevicePrompt(),
  page.click('#connect-bluetooth'),
]);

const device = await devicePrompt.waitForDevice(({name}) =>
  name.includes('My Device'),
);

await devicePrompt.select(device);

This is the request-time selection flow, commonly used with Web Bluetooth. It is different from Puppeteer’s device emulation APIs, which simulate a device profile’s viewport and user agent. See the official DeviceRequestPrompt reference and Page.waitForDevicePrompt reference.

1. How the prompt workflow works

  1. Arm the prompt wait. Call waitForDevicePrompt() before the browser action that causes the page to request a device.
  2. Trigger the request. Click the page control or perform the action that invokes the relevant web API.
  3. Match a device. Call waitForDevice(predicate). It resolves to the first device in the prompt that matches your predicate.
  4. Select the returned object. Pass that device object to select(); do not pass its name string.

Puppeteer’s documented pattern puts the wait and click in Promise.all. This registers the wait before the click takes effect, avoiding a race where the request happens before Puppeteer is listening. The method does not return a prompt that is already active, so waiting after the click is too late.

2. Complete runnable example

The following Node.js script uses Puppeteer’s browser launcher, opens a page that has a button with the selector #connect-bluetooth, waits for its device request, picks the first device whose name contains My Device, and selects it. Replace the example URL and predicate with values suitable for your page and test environment.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless: false});
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com/device-test', {
      waitUntil: 'domcontentloaded',
    });

    const [prompt] = await Promise.all([
      page.waitForDevicePrompt(),
      page.click('#connect-bluetooth'),
    ]);

    const device = await prompt.waitForDevice(({name}) =>
      name.includes('My Device'),
    );

    await prompt.select(device);
    console.log('Selected the matching device.');
  } finally {
    await browser.close();
  }
})().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

This is a runnable script structure, but it requires a real page that requests a device and a browser environment where that request can be fulfilled. https://example.com/device-test is a placeholder: replace it with your own test page. The page must expose the trigger selector shown in the example and make a device request in response to the click.

Why use Promise.all?

Calling waitForDevicePrompt() and then awaiting it before clicking would leave the script waiting for a prompt that cannot appear until the click. Starting both operations together avoids that deadlock while ensuring the prompt listener is armed first:

const [prompt] = await Promise.all([
  page.waitForDevicePrompt(),
  page.click('#connect-bluetooth'),
]);

Do not reverse the order by clicking first and then calling waitForDevicePrompt(). A prompt that has already opened is not returned by that wait.

3. Choose a reliable device predicate

waitForDevice(filter) resolves to the first prompt device for which your predicate returns true. Puppeteer’s example matches a substring of name; that is convenient when the test setup guarantees a unique name. If multiple devices can share that name, a broad predicate may select the wrong one.

const device = await prompt.waitForDevice(({name}) =>
  name === 'Test Sensor A',
);
await prompt.select(device);

Write the predicate for the actual device data and test requirements. The reference does not prescribe a universal identity strategy or guarantee that a name is unique. Inspect the device objects available in your installed Puppeteer version and the browser environment rather than assuming fields that are not documented for that version.

Because the method returns the first matching device, make the condition as discriminating as your environment allows. If the target is not present yet, the wait can continue while the prompt waits for a match; use the optional wait options supported by your installed version to bound that wait where appropriate.

4. DeviceRequestPrompt versus device emulation

Task API and input What it does
Respond to a page’s live device request DeviceRequestPrompt methods; select a device object from the prompt Lets the page continue with a device chosen for that request
Simulate a device profile page.emulate(KnownDevices[...]); use a predefined profile Emulates device metrics and user agent for page testing

KnownDevices is a list of profiles for emulation. It is not the list of live devices in a DeviceRequestPrompt, and emulating a phone profile does not select a Bluetooth device. See Puppeteer’s KnownDevices reference and Page.emulate reference.

5. Cancel a prompt

If your test needs to decline a device request, call cancel() on the prompt:

const [prompt] = await Promise.all([
  page.waitForDevicePrompt(),
  page.click('#connect-bluetooth'),
]);

await prompt.cancel();

This cancels the prompt. The class reference does not define a detailed page-side outcome for every site, so assert the behavior your application promises, such as showing a disconnected state or enabling a retry control.

6. Timeouts, errors, and troubleshooting

Symptom Likely cause What to check or change
waitForDevicePrompt() never resolves The page did not make a device request, the click missed, or the wait started after an earlier request. Verify the trigger selector and the page’s request flow. Start the wait before triggering the request, in the same Promise.all pattern.
The click fails before a prompt appears The page is not ready, the selector does not match, or the control is not clickable. Wait for the control to be available and verify the selector against the page. Make sure the test action actually invokes the device request.
waitForDevice() does not find the intended device The device is absent from the prompt or the predicate is too strict or checks the wrong property. Inspect the prompt’s current devices list and the fields exposed by your installed version. Adjust the predicate to match the intended device, not an assumed schema.
The wrong device is selected The predicate matches multiple devices and the method returns the first match. Use a more specific condition and make the test environment’s available devices predictable.
The wait rejects or exceeds the test’s time budget The expected prompt or matching device did not arrive before the configured wait limit. Check the installed version’s WaitTimeoutOptions type and API reference for timeout behavior, then set a limit appropriate to the test. The surfaced reference does not establish a universal default or detailed no-match rejection behavior.
select() receives an invalid argument A name string or another value was passed instead of the device object returned by waitForDevice(). Keep and pass the returned object: const device = await prompt.waitForDevice(...); await prompt.select(device);.
The code works on one Puppeteer release but not another API documentation surfaced across versions differs, and the locally installed release may expose different types or details. Check the documentation and TypeScript declarations that correspond to the Puppeteer version in your project.

The class reference surfaced as Puppeteer 25.12.0, while the separately surfaced waitForDevice() reference was 25.2.1 and the prompt-wait method was in the next-version docs. Confirm the installed release’s reference and type definitions before relying on release-specific timeout details.

7. Performance, reliability, and cost

  • Performance: The key delay is waiting for the page request and for a matching device to become available. Keep the predicate inexpensive and avoid waiting for unrelated page activity before arming the prompt.
  • Reliability: Register the wait before the trigger, use a precise predicate, and make the test environment’s available devices predictable. Handle cancellation and errors in the test’s normal cleanup path.
  • Cost: Puppeteer’s prompt-selection flow does not itself specify a service price. Your runtime, browser infrastructure, and any hardware or hosted test environment have costs determined by your setup; the cited API references do not give pricing.

Or skip the browser setup

If your task is to capture a page rather than exercise its live device-selection flow, ScreenshotNeo provides a website screenshot API and MCP server. It does not select a Bluetooth device or replace a Web Bluetooth interaction test; it captures the page as an image or PDF. Make one GET request:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

See the ScreenshotNeo API documentation. Cookie and consent banners are accepted and removed before capture, along with known newsletter popups and chat widgets. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

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

FAQ

Can I select a device by passing its name to select()?

No. Use waitForDevice() to obtain a device object, then pass that object to select().

Does DeviceRequestPrompt emulate a phone or tablet?

No. It responds to a page’s device request. Use Puppeteer’s emulation APIs and KnownDevices for device metrics and user-agent simulation.

Can I select a device from a prompt that is already open?

waitForDevicePrompt() does not return an already-active prompt. Arm it before the action that triggers the request.

Is Web Bluetooth the only use?

Web Bluetooth is the example in the API guidance; the prompt is described as a response mechanism for a page requesting a device through a web API.