> [!CAUTION]
> **Important:** Chrome will be removing support for Chrome Apps on all platforms. Chrome browser and the Chrome Web Store will continue to support extensions. [**Read the announcement**](https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html) and learn more about [**migrating your app**](https://developer.chrome.com/apps/migration).

This document describes how to use the [USB API](https://developer.chrome.com/docs/apps/usb) to communicate with USB devices. Some devices
are not accessible through the USB API (see the [Caveats](https://developer.chrome.com/docs/apps/app_usb.md.txt#caveats) section below for details). Chrome Apps
can also connect to [serial](https://developer.chrome.com/docs/apps/serial) and [Bluetooth](https://developer.chrome.com/docs/apps/bluetooth) devices.

> [!NOTE]
> **Note:** **Samples:** For examples that illustrate how Chrome Apps can connect to hardware devices, see the [serial](https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples/serial), [servo](https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples/servo), and [usb](https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples/usb) samples.

For background information about USB, see the official [USB specifications](http://www.usb.org/home).
[*USB in a NutShell*](http://www.beyondlogic.org/usbnutshell/usb1.shtml) is a reasonable crash course that you may find helpful.

## Manifest requirement

The USB API requires the "usb" permission in the manifest file:

```json
"permissions": [
  "usb"
]
```

In addition, in order to prevent [finger-printing](http://en.wikipedia.org/wiki/Device_fingerprint), you must declare all the device types you
want to access in the manifest file. Each type of USB device corresponds to a vendor id/product id
(VID/PID) pair. You can use [usb.getDevices](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-getDevices) to enumerate devices by their VID/PID pair.

You must declare the VID/PID pairs for each type of device you want to use under the `usbDevices`
permission in your app's manifest file, as shown in the example below:

```json
"permissions": [
  {
    "usbDevices": [
      {
        "vendorId": 123,
        "productId": 456
      }
    ]
  }
]
```

> [!NOTE]
> **Note:** Note that only decimal numbers are allowed in JSON format. You cannot use hexadecimal numbers in these fields.

Since **Chrome 57** , the requirement for declaring all the device types in the app manifest is
relaxed for apps running as ChromeOS [kiosk apps](https://developer.chrome.com/docs/apps/apps/manifest/kiosk_enabled). For kiosk apps, you can use the
`interfaceClass` permission property to request permission to access USB devices that:

- implement a USB interface of a specific interface class
- have a specific USB device class

For example, the following `usbDevices` permission would grant an app access to all USB devices that
implement a printer interface (interface class code 7), and to USB hub devices (device class code
9):

```json
"permissions": [
  {
    "usbDevices": [
      {"interfaceClass": 7},
      {"interfaceClass": 9}
    ]
  }
]
```

For the list of acceptable `interfaceClass` values, see [USB Class Codes](http://www.usb.org/developers/defined_class).

The `interfaceClass` property can be combined with the `vendorId` property to get access only to USB
devices from a specific vendor, as demonstrated by the following example:

```json
"permissions": [
  {
    "usbDevices": [
      {
        "vendorId": 123,
        "interfaceClass": 7
      }
    ]
  }
]
```

> [!NOTE]
> **Note:** Note that `usbDevices` permissions with `interfaceClass` property have effect only when the app is running in kiosk session - outside a kiosk session these permissions will be ignored.

## Finding a device

To determine whether one or more specific devices are connected to a user's system, use the
[usb.getDevices](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-getDevices) method:

```javascript
chrome.usb.getDevices(enumerateDevicesOptions, callback);
```

| Parameter (type) | Description |
|---|---|
| EnumerateDevicesOptions (object) | An object specifying both a `vendorId` (long) and `productId` (long) used to find the correct type of device on the bus. Your manifest must declare the `usbDevices` permission section listing all the `vendorId` and `deviceId` pairs your app wants to access. |
| callback (function) | Called when the device enumeration is finished. The callback will be executed with one parameter, an array of `Device` objects with three properties: `device`, `vendorId`, `productId`. The device property is a stable identifier for a connected device. It will not change until the device is unplugged. The detail of the identifier is opaque and subject to change. Do not rely on its current type. If no devices are found, the array will be empty. |

Example:

```javascript
function onDeviceFound(devices) {
  this.devices=devices;
  if (devices) {
    if (devices.length > 0) {
      console.log("Device(s) found: "+devices.length);
    } else {
      console.log("Device could not be found");
    }
  } else {
    console.log("Permission denied.");
  }
}

chrome.usb.getDevices({"vendorId": vendorId, "productId": productId}, onDeviceFound);
```

## Opening a device

Once the `Device` objects are returned, you can open a device using usb.openDevice to obtain a
connection handle. You can only communicate with USB devices using connection handles.

| Property | Description |
|---|---|
| device | Object received in [usb.getDevices](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-getDevices) callback. |
| data (arraybuffer) | Contains the data sent by the device if the transfer was inbound. |

Example:

```javascript
var usbConnection = null;
var onOpenCallback = function(connection) {
  if (connection) {
    usbConnection = connection;
    console.log("Device opened.");
  } else {
    console.log("Device failed to open.");
  }
};

chrome.usb.openDevice(device, onOpenCallback);
```

> [!NOTE]
> **Note:** Not every device can be opened successfully. In general, operating systems lock down many types of USB interfaces (e.g. keyboards and mice, mass storage devices, webcams, etc.) and they cannot be claimed by user applications. On Linux (other than ChromeOS), once an interface of a device is locked down by the OS, the whole device is locked down (because all the interfaces shares the same device file), even if the other interfaces of the device can be used in theory. On ChromeOS, you can request access to unlocked interfaces using the [usb.requestAccess](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-requestAccess) method. If permitted, the permission broker will unlock the device file for you.

To simplify the opening process, you can use the [usb.findDevices](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-findDevices) method, which enumerates,
requests access, and opens devices in one call:

```javascript
chrome.usb.findDevices({"vendorId": vendorId, "productId": productId, "interfaceId": interfaceId}, callback);
```

which is equivalent to:

```javascript
chrome.usb.getDevices({"vendorId": vendorId, "productId": productId}, function (devices) {
  if (!devices) {
    console.log("Error enumerating devices.");
    callback();
    return;
  }
  var connections = [], pendingAccessRequests = devices.length;
  devices.forEach(function (device) {
    chrome.usb.requestAccess(interfaceId, function () {
      // No need to check for errors at this point.
      // Nothing can be done if an error occurs anyway. You should always try
      // to open the device.
      chrome.usb.openDevices(device, function (connection) {
        if (connection) connections.push(connection);
        pendingAccessRequests--;
        if (pendingAccessRequests == 0) {
          callback(connections);
        }
      });
    });
  })
});
```

## USB transfers and receiving data from a device

The USB protocol defines four types of transfers: [control](https://developer.chrome.com/docs/apps/app_usb.md.txt#control_transfers), [bulk](https://developer.chrome.com/docs/apps/app_usb.md.txt#bulk_transfers), [isochronous](https://developer.chrome.com/docs/apps/app_usb.md.txt#isochronous_transfers) and
[interrupt](https://developer.chrome.com/docs/apps/app_usb.md.txt#interrupt_transfers). These transfers are described below.

Transfers can occur in both directions: device-to-host (inbound), and host-to-device (outbound). Due
to the nature of the USB protocol, both inbound and outbound messages must be initiated by the host
(the computer that runs the Chrome app). For inbound (device-to-host) messages, the host (initiated
by your JavaScript code) sends a message flagged as "inbound" to the device. The details of the
message depend on the device, but usually will have some identification of what you are requesting
from it. The device then responds with the requested data. The device's response is handled by
Chrome and delivered asynchronously to the callback you specify in the transfer method. An outbound
(host-to-device) message is similar, but the response doesn't contain data returned from the device.

For each message from the device, the specified callback will receive an event object with the
following properties:

| Property | Description |
|---|---|
| resultCode (integer) | 0 is success; other values indicate failure. An error string can be read from `chrome.extension.lastError` when a failure is indicated. |
| data (arraybuffer) | Contains the data sent by the device if the transfer was inbound. |

Example:

```javascript
var onTransferCallback = function(event) {
   if (event && event.resultCode === 0 && event.data) {
     console.log("got " + event.data.byteLength + " bytes");
   }
};

chrome.usb.bulkTransfer(connectionHandle, transferInfo, onTransferCallback);
```

## CONTROL transfers

Control transfers are generally used to send or receive configuration or command parameters to a USB
device. The controlTransfer method always sends to/reads from endpoint 0, and no claimInterface is
required. The method is simple and receives three parameters:

```javascript
chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
```

| Parameter (types) | Description |
|---|---|
| connectionHandle | Object received in [usb.openDevice](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-openDevice) callback. |
| transferInfo | Parameter object with values from the table below. Check your USB device protocol specification for details. |
| transferCallback() | Invoked when the transfer has completed. |

Values for `transferInfo` object:

| Value | Description |
|---|---|
| requestType (string) | "vendor", "standard", "class" or "reserved". |
| recipient (string) | "device", "interface", "endpoint" or "other". |
| direction (string) | "in" or "out". The "in" direction is used to notify the device that it should send information to the host. All communication on a USB bus is host-initiated, so use an "in" transfer to allow a device to send information back. |
| request (integer) | Defined by your device's protocol. |
| value (integer) | Defined by your device's protocol. |
| index (integer) | Defined by your device's protocol. |
| length (integer) | Only used when direction is "in". Notifies the device that this is the amount of data the host is expecting in response. |
| data (arraybuffer) | Defined by your device's protocol, required when direction is "out". |

Example:

```javascript
var transferInfo = {
  "requestType": "vendor",
   "recipient": "device",
  "direction": "out",
  "request":  0x31,
  "value": 120,
  "index": 0,
  // Note that the ArrayBuffer, not the TypedArray itself is used.
  "data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};
chrome.usb.controlTransfer(connectionHandle, transferInfo, optionalCallback);
```

## ISOCHRONOUS transfers

Isochronous transfers are the most complex type of USB transfer. They are commonly used for streams
of data, like video and sound. To initiate an isochronous transfer (either inbound or outbound), you
must use the [usb.isochronousTransfer](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-isochronousTransfer) method:

```javascript
chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
```

| Parameter | Description |
|---|---|
| connectionHandle | Object received in [usb.openDevice](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-openDevice) callback. |
| isochronousTransferInfo | Parameter object with the values in the table below. |
| transferCallback() | Invoked when the transfer has completed. |

Values for `isochronousTransferInfo` object:

| Value | Description |
|---|---|
| transferInfo (object) | An object with the following attributes: **direction (string):** "in" or "out". **endpoint (integer):** defined by your device. Usually can be found by looking at an USB instrospection tool, like `lsusb -v` **length (integer):** only used when direction is "in". Notifies the device that this is the amount of data the host is expecting in response. Should be AT LEAST `packets` × `packetLength`. **data (arraybuffer):**defined by your device's protocol; only used when direction is "out". |
| packets (integer) | Total number of packets expected in this transfer. |
| packetLength (integer) | Expected length of each packet in this transfer. |

Example:

```javascript
var transferInfo = {
  "direction": "in",
  "endpoint": 1,
  "length": 2560
};

var isoTransferInfo = {
  "transferInfo": transferInfo,
  "packets": 20,
  "packetLength": 128
};

chrome.usb.isochronousTransfer(connectionHandle, isoTransferInfo, optionalCallback);
```

> [!NOTE]
> **Note:** **Notes:** One isochronous transfer will contain `isoTransferInfo.packets` packets of `isoTransferInfo.packetLength` bytes. If it is an inbound transfer (your code requested data from the device), the `data` field in the onUsbEvent will be an ArrayBuffer of size `transferInfo.length`. It is your duty to walk through this ArrayBuffer and extract the different packets, each starting at a multiple of `isoTransferInfo.packetLength` bytes. If you are expecting a stream of data from the device, remember that you will have to send one "inbound" transfer for each transfer you expect back. USB devices don't send transfers to the USB bus unless the host explicitly requests them through "inbound" transfers.

## BULK transfers

Bulk transfers are commonly used to transfer a large amount of non-time-sensitive data in a reliable
way. [usb.bulkTransfer](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-bulkTransfer) has three parameters:

```javascript
chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
```

| Parameter | Description |
|---|---|
| connectionHandle | Object received in [usb.openDevice](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-openDevice) callback. |
| transferInfo | Parameter object with the values in the table below. |
| transferCallback | Invoked when the transfer has completed. |

Values for `transferInfo` object:

| Value | Description |
|---|---|
| direction (string) | "in" or "out". |
| endpoint (integer) | Defined by your device's protocol. |
| length (integer) | Only used when direction is "in". Notifies the device that this is the amount of data the host is expecting in response. |
| data (ArrayBuffer) | Defined by your device's protocol; only used when direction is "out". |

Example:

```javascript
var transferInfo = {
  "direction": "out",
  "endpoint": 1,
  "data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};
```

## INTERRUPT transfers

Interrupt transfers are used to small amount of time sensitive data. Since all USB communication is
initiated by the host, host code usually polls the device periodically, sending interrupt IN
transfers that will make the device send data back if there is anything in the interrupt queue
(maintained by the device). [usb.interruptTransfer](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-interruptTransfer) has three parameters:

```javascript
chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
```

| Parameter | Description |
|---|---|
| connectionHandle | Object received in [usb.openDevice](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-openDevice) callback. |
| transferInfo | Parameter object with the values in the table below. |
| transferCallback | Invoked when the transfer has completed. Notice that this callback doesn't contain the device's response. The purpose of the callback is simply to notify your code that the asynchronous transfer requests has been processed. |

Values for `transferInfo` object:

| Value | Description |
|---|---|
| direction (string) | "in" or "out". |
| endpoint (integer) | Defined by your device's protocol. |
| length (integer) | Only used when direction is "in". Notifies the device that this is the amount of data the host is expecting in response. |
| data (ArrayBuffer) | Defined by your device's protocol; only used when direction is "out". |

Example:

```javascript
var transferInfo = {
  "direction": "in",
  "endpoint": 1,
  "length": 2
};
chrome.usb.interruptTransfer(connectionHandle, transferInfo, optionalCallback);
```

## Caveats

Not all devices can be accessed through the USB API. In general, devices are not accessible because
either the Operating System's kernel or a native driver holds them off from user space code. Some
examples are devices with HID profiles on OSX systems, and USB pen drives.

On most Linux systems, USB devices are mapped with read-only permissions by default. To open a
device through this API, your user will need to have write access to it too. A simple solution is to
set a udev rule. Create a file `/etc/udev/rules.d/50-yourdevicename.rules` with the following
content:

```text
SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
```

Then, just restart the udev daemon: `service udev restart`. You can check if device permissions are
set correctly by following these steps:

- Run `lsusb` to find the bus and device numbers.
- Run `ls -al /dev/bus/usb/[bus]/[device]`. This file should be owned by group "plugdev" and have group write permissions.

Your app cannot do this automatically since this this procedure requires root access. We recommend
that you provide instructions to end-users and link to the [Caveats](https://developer.chrome.com/docs/apps/app_usb.md.txt#caveats) section on this page for an
explanation.

On ChromeOS, simply call [usb.requestAccess](https://developer.chrome.com/docs/apps/reference/usb.md.txt#method-requestAccess). The permission broker does this for you.