Device Access

    The can be used to communicate with bluetooth devices. In order to use this API in Electron, developers will need to handle the select-bluetooth-device event on the webContents associated with the device request.

    Additionally, can be used to handle pairing to bluetooth devices on Windows or Linux when additional validation such as a pin is needed.

    This example demonstrates an Electron application that automatically selects the first available bluetooth device when the button is clicked.

    Open in Fiddle

    • main.js
    • preload.js
    • index.html
    • renderer.js
    1. const { contextBridge, ipcRenderer } = require('electron')
    2. contextBridge.exposeInMainWorld('electronAPI', {
    3. bluetoothPairingRequest: (callback) => ipcRenderer.on('bluetooth-pairing-request', callback),
    4. bluetoothPairingResponse: (response) => ipcRenderer.send('bluetooth-pairing-response', response)
    5. })
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    6. <title>Web Bluetooth API</title>
    7. </head>
    8. <body>
    9. <h1>Web Bluetooth API</h1>
    10. <button id="clickme">Test Bluetooth</button>
    11. <p>Currently selected bluetooth device: <strong id="device-name""></strong></p>
    12. <script src="./renderer.js"></script>
    13. </body>
    14. </html>
    1. async function testIt() {
    2. const device = await navigator.bluetooth.requestDevice({
    3. acceptAllDevices: true
    4. })
    5. document.getElementById('device-name').innerHTML = device.name || `ID: ${device.id}`
    6. }
    7. document.getElementById('clickme').addEventListener('click',testIt)
    8. window.electronAPI.bluetoothPairingRequest((event, details) => {
    9. const response = {}
    10. switch (details.pairingKind) {
    11. case 'confirm': {
    12. response.confirmed = confirm(`Do you want to connect to device ${details.deviceId}?`)
    13. break
    14. }
    15. case 'confirmPin': {
    16. response.confirmed = confirm(`Does the pin ${details.pin} match the pin displayed on device ${details.deviceId}?`)
    17. break
    18. }
    19. case 'providePin': {
    20. const pin = prompt(`Please provide a pin for ${details.deviceId}.`)
    21. if (pin) {
    22. response.pin = pin
    23. response.confirmed = true
    24. } else {
    25. response.confirmed = false
    26. }
    27. }
    28. }
    29. window.electronAPI.bluetoothPairingResponse(response)
    30. })
    • The select-hid-device event on the Session can be used to select a HID device when a call to navigator.hid.requestDevice is made. Additionally the and hid-device-removed events on the Session can be used to handle devices being plugged in or unplugged when handling the select-hid-device event. Note: These events only fire until the callback from select-hid-device is called. They are not intended to be used as a generic hid device listener.
    • can be used to provide default permissioning to devices without first calling for permission to devices via navigator.hid.requestDevice. Additionally, the default behavior of Electron is to store granted device permission through the lifetime of the corresponding WebContents. If longer term storage is needed, a developer can store granted device permissions (eg when handling the select-hid-device event) and then read from that storage with setDevicePermissionHandler.
    • ses.setPermissionCheckHandler(handler) can be used to disable HID access for specific origins.

    By default Electron employs the same blocklist used by Chromium. If you wish to override this behavior, you can do so by setting the disable-hid-blocklist flag:

    This example demonstrates an Electron application that automatically selects HID devices through ses.setDevicePermissionHandler(handler) and through when the Test WebHID button is clicked.

    docs/fiddles/features/web-hid (23.0.0)

    • main.js
    • index.html
    • renderer.js
    1. const {app, BrowserWindow} = require('electron')
    2. const path = require('path')
    3. function createWindow () {
    4. const mainWindow = new BrowserWindow({
    5. width: 800,
    6. height: 600
    7. })
    8. mainWindow.webContents.session.on('select-hid-device', (event, details, callback) => {
    9. //Add events to handle devices being added or removed before the callback on
    10. //`select-hid-device` is called.
    11. mainWindow.webContents.session.on('hid-device-added', (event, device) => {
    12. console.log('hid-device-added FIRED WITH', device)
    13. //Optionally update details.deviceList
    14. })
    15. mainWindow.webContents.session.on('hid-device-removed', (event, device) => {
    16. console.log('hid-device-removed FIRED WITH', device)
    17. //Optionally update details.deviceList
    18. })
    19. event.preventDefault()
    20. if (details.deviceList && details.deviceList.length > 0) {
    21. callback(details.deviceList[0].deviceId)
    22. }
    23. })
    24. mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
    25. if (permission === 'hid' && details.securityOrigin === 'file:///') {
    26. return true
    27. })
    28. mainWindow.webContents.session.setDevicePermissionHandler((details) => {
    29. if (details.deviceType === 'hid' && details.origin === 'file://') {
    30. return true
    31. }
    32. mainWindow.loadFile('index.html')
    33. }
    34. app.whenReady().then(() => {
    35. createWindow()
    36. app.on('activate', function () {
    37. if (BrowserWindow.getAllWindows().length === 0) createWindow()
    38. })
    39. })
    40. app.on('window-all-closed', function () {
    41. if (process.platform !== 'darwin') app.quit()
    42. })
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    6. <title>WebHID API</title>
    7. </head>
    8. <body>
    9. <h1>WebHID API</h1>
    10. <button id="clickme">Test WebHID</button>
    11. <h3>HID devices automatically granted access via <i>setDevicePermissionHandler</i></h3>
    12. <div id="granted-devices"></div>
    13. <h3>HID devices automatically granted access via <i>select-hid-device</i></h3>
    14. <div id="granted-devices2"></div>
    15. <script src="./renderer.js"></script>
    16. </body>
    17. </html>
    1. async function testIt() {
    2. const grantedDevices = await navigator.hid.getDevices()
    3. let grantedDeviceList = ''
    4. grantedDevices.forEach(device => {
    5. grantedDeviceList += `<hr>${device.productName}</hr>`
    6. })
    7. document.getElementById('granted-devices').innerHTML = grantedDeviceList
    8. const grantedDevices2 = await navigator.hid.requestDevice({
    9. filters: []
    10. })
    11. grantedDeviceList = ''
    12. grantedDevices2.forEach(device => {
    13. grantedDeviceList += `<hr>${device.productName}</hr>`
    14. })
    15. document.getElementById('granted-devices2').innerHTML = grantedDeviceList
    16. }
    17. document.getElementById('clickme').addEventListener('click',testIt)

    The can be used to access serial devices that are connected via serial port, USB, or Bluetooth. In order to use this API in Electron, developers will need to handle the select-serial-port event on the Session associated with the serial port request.

    • The and serial-port-removed events on the Session can be used to handle devices being plugged in or unplugged when handling the select-serial-port event. Note: These events only fire until the callback from select-serial-port is called. They are not intended to be used as a generic serial port listener.
    • can be used to provide default permissioning to devices without first calling for permission to devices via navigator.serial.requestPort. Additionally, the default behavior of Electron is to store granted device permission through the lifetime of the corresponding WebContents. If longer term storage is needed, a developer can store granted device permissions (eg when handling the select-serial-port event) and then read from that storage with setDevicePermissionHandler.
    • ses.setPermissionCheckHandler(handler) can be used to disable serial access for specific origins.

    This example demonstrates an Electron application that automatically selects serial devices through ses.setDevicePermissionHandler(handler) as well as demonstrating selecting the first available Arduino Uno serial device (if connected) through when the Test Web Serial button is clicked.

    docs/fiddles/features/web-serial (23.0.0)

    • main.js
    • index.html
    • renderer.js
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    6. <title>Web Serial API</title>
    7. <body>
    8. <h1>Web Serial API</h1>
    9. <button id="clickme">Test Web Serial API</button>
    10. <p>Matching Arduino Uno device: <strong id="device-name""></strong></p>
    11. <script src="./renderer.js"></script>
    12. </body>
    13. </html>
    1. async function testIt() {
    2. const filters = [
    3. { usbVendorId: 0x2341, usbProductId: 0x0043 },
    4. { usbVendorId: 0x2341, usbProductId: 0x0001 }
    5. ];
    6. try {
    7. const port = await navigator.serial.requestPort({filters});
    8. const portInfo = port.getInfo();
    9. document.getElementById('device-name').innerHTML = `vendorId: ${portInfo.usbVendorId} | productId: ${portInfo.usbProductId} `
    10. } catch (ex) {
    11. if (ex.name === 'NotFoundError') {
    12. document.getElementById('device-name').innerHTML = 'Device NOT found'
    13. } else {
    14. document.getElementById('device-name').innerHTML = ex
    15. }
    16. }
    17. }
    18. document.getElementById('clickme').addEventListener('click',testIt)

    The can be used to access USB devices. Electron provides several APIs for working with the WebUSB API:

    • The select-usb-device event on the Session can be used to select a USB device when a call to navigator.usb.requestDevice is made. Additionally the and usb-device-removed events on the Session can be used to handle devices being plugged in or unplugged when handling the select-usb-device event. Note: These two events only fire until the callback from select-usb-device is called. They are not intended to be used as a generic usb device listener.
    • The can be used to respond when device.forget() is called on a USB device.
    • can be used to provide default permissioning to devices without first calling for permission to devices via navigator.usb.requestDevice. Additionally, the default behavior of Electron is to store granted device permission through the lifetime of the corresponding WebContents. If longer term storage is needed, a developer can store granted device permissions (eg when handling the select-usb-device event) and then read from that storage with setDevicePermissionHandler.
    • ses.setPermissionCheckHandler(handler) can be used to disable USB access for specific origins.

    This example demonstrates an Electron application that automatically selects USB devices (if they are attached) through ses.setDevicePermissionHandler(handler) and through when the Test WebUSB button is clicked.

    • index.html
    • renderer.js
    1. const e = require('express')
    2. const path = require('path')
    3. function createWindow () {
    4. const mainWindow = new BrowserWindow({
    5. width: 800,
    6. height: 600
    7. })
    8. let grantedDeviceThroughPermHandler
    9. mainWindow.webContents.session.on('select-usb-device', (event, details, callback) => {
    10. //Add events to handle devices being added or removed before the callback on
    11. //`select-usb-device` is called.
    12. mainWindow.webContents.session.on('usb-device-added', (event, device) => {
    13. console.log('usb-device-added FIRED WITH', device)
    14. //Optionally update details.deviceList
    15. })
    16. mainWindow.webContents.session.on('usb-device-removed', (event, device) => {
    17. console.log('usb-device-removed FIRED WITH', device)
    18. //Optionally update details.deviceList
    19. })
    20. event.preventDefault()
    21. if (details.deviceList && details.deviceList.length > 0) {
    22. const deviceToReturn = details.deviceList.find((device) => {
    23. if (!grantedDeviceThroughPermHandler || (device.deviceId != grantedDeviceThroughPermHandler.deviceId)) {
    24. return true
    25. }
    26. })
    27. if (deviceToReturn) {
    28. callback(deviceToReturn.deviceId)
    29. } else {
    30. callback()
    31. }
    32. }
    33. })
    34. mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
    35. if (permission === 'usb' && details.securityOrigin === 'file:///') {
    36. return true
    37. }
    38. })
    39. mainWindow.webContents.session.setDevicePermissionHandler((details) => {
    40. if (details.deviceType === 'usb' && details.origin === 'file://') {
    41. if (!grantedDeviceThroughPermHandler) {
    42. grantedDeviceThroughPermHandler = details.device
    43. return true
    44. } else {
    45. return false
    46. }
    47. }
    48. })
    49. mainWindow.loadFile('index.html')
    50. }
    51. app.whenReady().then(() => {
    52. createWindow()
    53. app.on('activate', function () {
    54. if (BrowserWindow.getAllWindows().length === 0) createWindow()
    55. })
    56. })
    57. app.on('window-all-closed', function () {
    58. if (process.platform !== 'darwin') app.quit()
    59. })
    1. function getDeviceDetails(device) {
    2. return grantedDevice.productName || `Unknown device ${grantedDevice.deviceId}`
    3. }
    4. async function testIt() {
    5. const noDevicesFoundMsg = 'No devices found'
    6. const grantedDevices = await navigator.usb.getDevices()
    7. let grantedDeviceList = ''
    8. if (grantedDevices.length > 0) {
    9. grantedDevices.forEach(device => {
    10. grantedDeviceList += `<hr>${getDeviceDetails(device)}</hr>`
    11. })
    12. } else {
    13. grantedDeviceList = noDevicesFoundMsg
    14. }
    15. document.getElementById('granted-devices').innerHTML = grantedDeviceList
    16. grantedDeviceList = ''
    17. try {
    18. const grantedDevice = await navigator.usb.requestDevice({
    19. filters: []
    20. })
    21. grantedDeviceList += `<hr>${getDeviceDetails(device)}</hr>`
    22. } catch (ex) {
    23. if (ex.name === 'NotFoundError') {
    24. grantedDeviceList = noDevicesFoundMsg
    25. }
    26. }
    27. document.getElementById('granted-devices2').innerHTML = grantedDeviceList
    28. }