How to Disable Bluetooth Emulation in Puppeteer
Disable Puppeteer’s emulated Bluetooth adapter with one call, or use the equivalent Chrome DevTools Protocol command when working directly with CDP.
To disable Puppeteer’s emulated Bluetooth adapter, call await page.bluetooth.disableEmulation(). If your code controls Chrome through a Chrome DevTools Protocol (CDP) session, send BluetoothEmulation.disable instead. Both commands disable emulation; they do not turn off the computer’s physical Bluetooth radio.
1. Disable emulation with Puppeteer
The Puppeteer API is the shortest option when you already have a Page object. The method is experimental, so check that it exists in the Puppeteer version installed in your project.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
// Do this after creating the page and before code that relies on
// the emulated Bluetooth adapter being disabled.
await page.bluetooth.disableEmulation();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log('Bluetooth emulation disabled for this browser context.');
} finally {
await browser.close();
}
})();
In an ES module, import Puppeteer with import puppeteer from 'puppeteer';; the rest of the example is the same. Install Puppeteer with your project’s package manager if it is not already a dependency.
2. Use the raw Chrome DevTools Protocol command
When you need direct protocol access, create a CDP session attached to the page and send the disable command:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
const session = await page.createCDPSession();
await session.send('BluetoothEmulation.disable');
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log('BluetoothEmulation domain disabled.');
} finally {
await browser.close();
}
})();
Use the Puppeteer wrapper when it is available and sufficient. Use the CDP command when your automation already works with protocol sessions or needs to issue the protocol method directly. Puppeteer documents page-attached CDP sessions in its Page API reference; the command is described in the Chrome DevTools Protocol BluetoothEmulation reference.
3. Understand what gets disabled
- Emulated adapter: The Puppeteer method is documented as disabling the emulated Bluetooth adapter. The CDP command disables the BluetoothEmulation domain.
- Physical hardware: These APIs are not documented as controls for the host computer’s Bluetooth radio. Turn off real Bluetooth using the operating system or device controls.
- Device presets:
page.emulate(device)applies a device’s user agent and viewport. It is not the Bluetooth emulation control. See Puppeteer’s Page.emulate() documentation. - Scope: Although the Web Bluetooth specification expects emulated adapters to be isolated per top-level navigable, Chromium’s current implementation is tied to the browser context. Pages in the same context may therefore affect one another’s emulation state.
4. Choose the right command and timing
| Situation | Use | Consideration |
|---|---|---|
| Ordinary Puppeteer page automation | await page.bluetooth.disableEmulation() |
Experimental API; verify it is present in your installed version. |
| Direct CDP automation | await session.send('BluetoothEmulation.disable') |
Requires a live CDP session attached to the page. |
| Disable physical Bluetooth | Operating system or device controls | Puppeteer’s emulation commands do not document control of host hardware. |
Run the command after creating the page or session and before the operation whose behavior depends on Bluetooth emulation. If several pages share a browser context, account for the documented Chromium context-level scope: changing emulation state from one page may affect another. If tests need isolated state, use separate browser contexts and verify behavior with the Chrome version your automation actually launches.
5. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
page.bluetooth or disableEmulation is undefined |
The installed Puppeteer version may not expose the experimental method, or the page object is not the expected Puppeteer page. | Check the installed package version and the current Puppeteer API reference. If you have a page CDP session, try the protocol command supported by the connected Chrome. |
BluetoothEmulation.disable is reported as an unknown method |
The connected Chrome may not support the command exposed by the rolling protocol reference, or the session may target an unexpected endpoint. | Check the Chrome version and CDP endpoint used by the session. Confirm protocol support for that browser build. |
| The call fails because the session or target is closed | The browser, page, or CDP session was closed before the command ran. | Create the session from a live page and send the command before closing the page or browser. |
| Another page’s Bluetooth behavior changes | Chromium currently ties emulation state to the browser context, so pages in that context may share state. | Review context reuse in the test and isolate pages into separate browser contexts when independent state is required. |
| The computer’s Bluetooth remains on | The command affects browser emulation, not the physical radio. | Use the operating system’s Bluetooth controls. |
6. Version compatibility and reliability
Puppeteer labels disableEmulation() experimental, and the CDP reference linked here is the rolling tot protocol documentation. Treat both availability and behavior as version-sensitive: check the Puppeteer version in the lockfile and the Chrome build that Puppeteer connects to, especially when upgrading either. Keep the command near page or session setup so its ordering is explicit, and avoid assuming each page has independent emulation state within one browser context.
7. Or skip the browser setup
If your goal is a page screenshot rather than controlling Bluetooth behavior, ScreenshotNeo returns a website screenshot from one GET request. It does not expose Bluetooth emulation controls. See the ScreenshotNeo API documentation for request options.
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for free and get 1,000 screenshots a month with no card.
8. FAQ
Does disabling emulation remove Bluetooth from the computer?
No. It changes the browser’s emulated Bluetooth state. Use operating system or device controls to turn off physical Bluetooth.
Should I call both disable methods?
Usually, choose the Puppeteer API or the direct CDP command based on how your code is structured. The sources describe them as the wrapper and protocol-level approaches to disabling emulation.
Does page.emulate() change Bluetooth?
Puppeteer documents that shortcut as applying a device user agent and viewport; use the Bluetooth emulation API or CDP command for Bluetooth emulation.
Where can I confirm the exact method name?
Check the Puppeteer BluetoothEmulation API reference and the Chrome DevTools Protocol reference for the Chrome build in use.


