Access USB Devices on the Web Stay organized with collections Save and categorize content based on your preferences.
The WebUSB API makes USB safer and easier to use by bringing it to the Web.
If I said plainly and simply "USB", there is a good chance that you willimmediately think of keyboards, mice, audio, video, and storage devices. You'reright, but you'll find other kinds of Universal Serial Bus (USB) devices outthere.
These non-standardized USB devices require hardware vendors to write platform-specificdrivers and SDKs in order for you (the developer) to take advantage of them.Sadly this platform-specific code has historically prevented these devices from being usedby the Web. And that's one of the reasons the WebUSB API has been created: toprovide a way to expose USB device services to the Web. With this API, hardwaremanufacturers will be able to build cross-platform JavaScript SDKs for theirdevices.
But most importantly this willmake USB safer and easier to use by bringingit to the Web.
Let's see the behavior you could expect with the WebUSB API:
- Buy a USB device.
- Plug it into your computer. A notification appears right away, with the rightwebsite to go to for this device.
- Click the notification. The website is there and ready to use!
- Click to connect and a USB device chooser shows up in Chrome where you canpick your device.
Tada!
What would this procedure be like without the WebUSB API?
- Install a platform-specific application.
- If it's even supported on my operating system, verify that I've downloadedthe right thing.
- Install the thing. If you're lucky, you'll get no scary OS prompts or popupswarning you about installing drivers/applications from the internet. Ifyou're unlucky, the installed drivers or applications malfunction and harmyour computer. (Remember, the web is built tocontain malfunctioningwebsites).
- If you only use the feature once, the code stays on your computer until youthink to remove it. (On the Web, the space for unused is eventuallyreclaimed.)
Before I start
This article assumes you have some basic knowledge of how USB works. If not, Irecommend readingUSB in a NutShell. For background information about USB,check out theofficial USB specifications.
TheWebUSB API is available in Chrome 61.
Available for origin trials
In order to get as much feedback as possible from developers using the WebUSBAPI in the field, we've previously added this feature in Chrome 54 and Chrome57 as anorigin trial.
The latest trial has successfully ended in September 2017.
Privacy and security
HTTPS only
Because of this feature's power, it only works onsecure contexts. This meansyou'll need to build withTLS in mind.
User gesture required
As a security precaution,navigator.usb.requestDevice()
may onlybe called through a user gesture such as a touch or mouse click.
Permissions Policy
APermissions Policy is a mechanism that allows developers to selectively enableand disable various browser features and APIs. It can be defined via an HTTPheader and/or an iframe "allow" attribute.
You can define a Permissions Policy that controls whether theusb
attribute isexposed on the Navigator object, or in other words if you allow WebUSB.
Below is an example of a header policy where WebUSB is not allowed:
Feature-Policy: fullscreen "*"; usb "none"; payment "self" https://payment.example.com
Below is another example of a container policy where USB is allowed:
<iframe allowpaymentrequest allow="usb; fullscreen"></iframe>
Let's start coding
The WebUSB API relies heavily on JavaScriptPromises. If you're not familiarwith them, check out this greatPromises tutorial. One more thing,() => {}
are simply ECMAScript 2015Arrow functions.
Get access to USB devices
You can either prompt the user to select a single connected USB device usingnavigator.usb.requestDevice()
or callnavigator.usb.getDevices()
to get alist of all connected USB devices the website has been granted access to.
Thenavigator.usb.requestDevice()
function takes a mandatory JavaScript objectthat definesfilters
. These filters are used to match any USB device with thegiven vendor (vendorId
) and, optionally, product (productId
) identifiers.TheclassCode
,protocolCode
,serialNumber
, andsubclassCode
keys canalso be defined there as well.

For instance, here's how to get access to a connected Arduino device configuredto allow the origin.
navigator.usb.requestDevice({filters:[{vendorId:0x2341}]}).then(device=>{console.log(device.productName);// "Arduino Micro"console.log(device.manufacturerName);// "Arduino LLC"}).catch(error=>{console.error(error);});
Before you ask, I didn't magically come up with this0x2341
hexadecimalnumber. I simply searched for the word "Arduino" in thisList of USB ID's.
The USBdevice
returned in the fulfilled promise above has some basic, yetimportant information about the device such as the supported USB version,maximum packet size, vendor, and product IDs, the number of possibleconfigurations the device can have. Basically it contains all fields in thedevice USB Descriptor.
// Get all connected USB devices the website has been granted access to.navigator.usb.getDevices().then(devices=>{devices.forEach(device=>{console.log(device.productName);// "Arduino Micro"console.log(device.manufacturerName);// "Arduino LLC"});})
By the way, if a USB device announces itssupport for WebUSB, as well asdefining a landing page URL, Chrome will show a persistent notification when theUSB device is plugged in. Clicking this notification will open the landing page.

Talk to an Arduino USB board
Okay, now let's see how easy it is to communicate from a WebUSB compatibleArduino board over the USB port. Check out instructions athttps://github.com/webusb/arduino to WebUSB-enable yoursketches.
Don't worry, I'll cover all the WebUSB device methods mentioned below later inthis article.
letdevice;navigator.usb.requestDevice({filters:[{vendorId:0x2341}]}).then(selectedDevice=>{device=selectedDevice;returndevice.open();// Begin a session.}).then(()=>device.selectConfiguration(1))// Select configuration #1 for the device..then(()=>device.claimInterface(2))// Request exclusive control over interface #2..then(()=>device.controlTransferOut({requestType:'class',recipient:'interface',request:0x22,value:0x01,index:0x02}))// Ready to receive data.then(()=>device.transferIn(5,64))// Waiting for 64 bytes of data from endpoint #5..then(result=>{constdecoder=newTextDecoder();console.log('Received: '+decoder.decode(result.data));}).catch(error=>{console.error(error);});
Keep in mind that the WebUSB library I'm using is just implementingone example protocol (based on the standard USB serial protocol) and thatmanufacturers can create any set and types of endpoints they wish.Control transfers are especially nice for small configuration commands asthey get bus priority and have a well defined structure.
And here's the sketch that has been uploaded to the Arduino board.
// Third-party WebUSB Arduino library#include <WebUSB.h>WebUSBWebUSBSerial(1/* https:// */,"webusb.github.io/arduino/demos");#define Serial WebUSBSerialvoidsetup(){Serial.begin(9600);while(!Serial){;// Wait for serial port to connect.}Serial.write("WebUSB FTW!");Serial.flush();}voidloop(){// Nothing here for now.}
The third-partyWebUSB Arduino library used in the sample code above doesbasically two things:
- The device acts as a WebUSB device enabling Chrome to read thelanding page URL.
- It exposes a WebUSB Serial API that you may use to override the default one.
Look at the JavaScript code again. Once I get thedevice
picked by the user,device.open()
runs all platform-specific steps to start a session with the USBdevice. Then, I have to select an available USB Configuration withdevice.selectConfiguration()
. Remember that a configuration specifies how thedevice is powered, its maximum power consumption and its number of interfaces.Speaking of interfaces, I also need to request exclusive access withdevice.claimInterface()
since data can only be transferred to an interface orassociated endpoints when the interface is claimed. Finally callingdevice.controlTransferOut()
is needed to set up the Arduino device with theappropriate commands to communicate through the WebUSB Serial API.
From there,device.transferIn()
performs a bulk transfer onto thedevice to inform it that the host is ready to receive bulk data. Then, thepromise is fulfilled with aresult
object containing aDataViewdata
thathas to be parsed appropriately.
If you're familiar with USB, all of this should look pretty familiar.
I want more
The WebUSB API lets you interact with the all USB transfer/endpoint types:
- CONTROL transfers, used to send or receive configuration or commandparameters to a USB device, are handled with
controlTransferIn(setup,length)
andcontrolTransferOut(setup, data)
. - INTERRUPT transfers, used for a small amount of time sensitive data, arehandled with the same methods as BULK transfers with
transferIn(endpointNumber, length)
andtransferOut(endpointNumber, data)
. - ISOCHRONOUS transfers, used for streams of data like video and sound, arehandled with
isochronousTransferIn(endpointNumber, packetLengths)
andisochronousTransferOut(endpointNumber, data, packetLengths)
. - BULK transfers, used to transfer a large amount of non-time-sensitive data ina reliable way, are handled with
transferIn(endpointNumber, length)
andtransferOut(endpointNumber, data)
.
You may also want to have a look at Mike Tsao'sWebLight project whichprovides a ground-up example of building a USB-controlled LED device designedfor the WebUSB API (not using an Arduino here). You'll find hardware, software,and firmware.
Revoke access to a USB device
The website can clean up permissions to access a USB device it no longer needsby callingforget()
on theUSBDevice
instance. For example, for aneducational web application used on a shared computer with many devices, a largenumber of accumulated user-generated permissions creates a poor user experience.
// Voluntarily revoke access to this USB device.awaitdevice.forget();
Asforget()
is available in Chrome 101 or later, check if this feature issupported with the following:
if("usb"innavigator &&"forget"inUSBDevice.prototype){// forget() is supported.}
Limits on transfer size
Some operating systems impose limits on how much data can be part ofpending USB transactions. Splitting your data into smaller transactions and onlysubmitting a few at a time helps avoid those limitations. It also reducesthe amount of memory used and allows your application to report progress as thetransfers complete.
Because multiple transfers submitted to an endpoint always execute in order, it ispossible to improve throughput by submitting multiple queued chunks to avoidlatency between USB transfers. Every time a chunk is fully transmitted it willnotify your code that it should provide more data as documented in the helperfunction example below.
constBULK_TRANSFER_SIZE=16*1024;// 16KBconstMAX_NUMBER_TRANSFERS=3;asyncfunctionsendRawPayload(device,endpointNumber,data){leti=0;letpendingTransfers=[];letremainingBytes=data.byteLength;while(remainingBytes >0){constchunk=data.subarray(i*BULK_TRANSFER_SIZE,(i+1)*BULK_TRANSFER_SIZE);// If we've reached max number of transfers, let's wait.if(pendingTransfers.length==MAX_NUMBER_TRANSFERS){awaitpendingTransfers.shift();}// Submit transfers that will be executed in order.pendingTransfers.push(device.transferOut(endpointNumber,chunk));remainingBytes-=chunk.byteLength;i++;}// And wait for last remaining transfers to complete.awaitPromise.all(pendingTransfers);}
Tips
Debugging USB in Chrome is easier with the internal pageabout://device-log
where you can see all USB device related events in one single place.

The internal pageabout://usb-internals
also comes in handy and allows youto simulate connection and disconnection of virtual WebUSB devices.This is be useful for doing UI testing without for real hardware.

On most Linux systems, USB devices are mapped with read-only permissions bydefault. To allow Chrome to open a USB device, you will need to add a newudevrule. Create a file at/etc/udev/rules.d/50-yourdevicename.rules
with thefollowing content:
SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
where[yourdevicevendor]
is2341
if your device is an Arduino for instance.ATTR{idProduct}
can also be added for a more specific rule. Make sure youruser
is amember of theplugdev
group. Then, just reconnect your device.
Resources
- Stack Overflow:https://stackoverflow.com/questions/tagged/webusb
- WebUSB API Spec:http://wicg.github.io/webusb/
- Chrome Feature Status:https://www.chromestatus.com/feature/5651917954875392
- Spec Issues:https://github.com/WICG/webusb/issues
- Implementation Bugs:http://crbug.com?q=component:Blink>USB
- WebUSB ❤ ️Arduino:https://github.com/webusb/arduino
- IRC:#webusb on W3C's IRC
- WICG Mailing list:https://lists.w3.org/Archives/Public/public-wicg/
- WebLight project:https://github.com/sowbug/weblight
Send a tweet to@ChromiumDev using the hashtag#WebUSB
and let us know where and how you're using it.
Acknowledgements
Thanks toJoe Medley for reviewing this article.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2016-03-30 UTC.