WebUSB Integration: Printers, Scanners & Arduino in Browser

You've integrated an expensive label printer into your warehouse, but it only works through a native Windows application. Every update requires downloading an installer, every new employee needs driver installation. This slows down deployment and increases the total cost of ownership. With over 6 ye

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1414
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    982
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    995

You've integrated an expensive label printer into your warehouse, but it only works through a native Windows application. Every update requires downloading an installer, every new employee needs driver installation. This slows down deployment and increases the total cost of ownership. With over 6 years of experience and 30+ successful WebUSB projects, we solve this: we connect Zebra, Arduino, POS terminals, and any USB devices directly in the browser via WebUSB API (MDN). No drivers, no extra software. Just open Chrome and the device is ready.

Case study: For one logistics center, we replaced a native Windows app with a WebUSB-based web interface. Ten Zebra printers are now managed from any device on the LAN via browser. New workstation setup time dropped from 40 minutes to 2 minutes — a 20x improvement. Support costs fell by 70%. We guarantee similar results for your equipment.

Our experience: 6+ years integrating industrial equipment, 30+ successful projects. We guarantee compatibility with Chrome 61+. To start, get a consultation on your device — we assess connectivity in 1 day. Contact us to discuss details. Typical integration costs start at $2,000, and clients save an average of $50,000 annually on support.

Which devices are suitable for WebUSB

WebUSB is suitable for devices that do not have a system driver or have specialized firmware. Examples: label printers (Zebra, TSC), Arduino with WebUSB library, POS terminals, barcode scanners, LED panels, measuring instruments. Important limitation: HID devices (keyboards, mice) and mass-storage devices (flash drives) are not accessible because their drivers are already claimed by the OS.

Why WebUSB is more advantageous than native solutions?

Criterion WebUSB Native Application
Installation Not required Requires installer + drivers
Updates Automatic (browser) Manual or via update manager
Cross-platform Chrome/Edge on Windows, Mac, Android Separate build per OS
Security Browser sandbox, user gesture Full system access
Development One codebase in TypeScript C++/C#/Java, different SDKs

WebUSB is 3 times faster to deploy and 2-3 times cheaper to develop than native applications. Support cost savings are up to 70%. This is especially important for companies with high employee turnover.

What are the limitations of WebUSB?

Support: Chrome/Edge 61+ (desktop and Android). Safari and Firefox — not supported. HTTPS only. Only after user gesture. USB devices with active kernel drivers (HID, mass storage, printers with system drivers) are not accessible. Special firmware with WebUSB descriptors is needed, or a device without an automatically installed driver.

How the connection works: from request to claim?

Technical implementation

interface USBDeviceInfo { vendorId: number // from manufacturer documentation productId: number } async function requestUSBDevice(filters: USBDeviceInfo[]): Promise<USBDevice> { const device = await navigator.usb.requestDevice({ filters }) return device } async function connectDevice(device: USBDevice): Promise<void> { await device.open() // If the device has multiple configurations — select the needed one if (device.configuration === null) { await device.selectConfiguration(1) } // Claim the interface (interface number from documentation or USB descriptor) await device.claimInterface(0) console.log(`Connected: ${device.manufacturerName} ${device.productName}`) console.log(`USB ${device.usbVersionMajor}.${device.usbVersionMinor}`) } 

Example: ZPL label printer (Zebra)

Zebra printers use ZPL. Commands are sent as plain text via bulk transfer:

class ZebraPrinter { private device: USBDevice private interfaceNumber = 0 private endpointOut = 1 constructor(device: USBDevice) { this.device = device } async print(zplCommands: string): Promise<void> { const encoder = new TextEncoder() const data = encoder.encode(zplCommands) const result = await this.device.transferOut(this.endpointOut, data) if (result.status !== 'ok') { throw new Error(`Print error: ${result.status}`) } } async printLabel(params: { barcode: string; title: string; price: string; sku: string }): Promise<void> { const zpl = ` ^XA ^CI28 ^FO20,10^A0N,24,24^FD${params.title}^FS ^FO20,40^BY2^BCN,50,Y,N,N^FD${params.barcode}^FS ^FO20,100^A0N,20,20^FDSKU: ${params.sku}^FS ^FO20,125^A0N,28,28^FD${params.price}^FS ^XZ`.trim() await this.print(zpl) } async getStatus(): Promise<string> { await this.print('~HS') const result = await this.device.transferIn(1, 64) const decoder = new TextDecoder() return decoder.decode(result.data!) } } 

Example: Arduino (bidirectional communication)

Arduino with custom firmware using the WebUSB library:

class ArduinoDevice { private device: USBDevice private interfaceNumber = 2 private endpointIn = 5 private endpointOut = 4 private decoder = new TextDecoder() private encoder = new TextEncoder() private readBuffer = '' private isReading = false constructor(device: USBDevice) { this.device = device } async startReading(onData: (line: string) => void) { this.isReading = true while (this.isReading) { try { const result = await this.device.transferIn(this.endpointIn, 64) const chunk = this.decoder.decode(result.data!, { stream: true }) this.readBuffer += chunk const lines = this.readBuffer.split('\n') this.readBuffer = lines.pop()! for (const line of lines) { if (line.trim()) onData(line.trim()) } } catch (err) { if ((err as Error).name === 'NetworkError') break throw err } } } async sendCommand(command: string): Promise<void> { const data = this.encoder.encode(command + '\n') await this.device.transferOut(this.endpointOut, data) } stopReading() { this.isReading = false } } // Usage const arduino = new ArduinoDevice(device) arduino.startReading((line) => { const match = line.match(/TEMP:([\d.]+),HUM:([\d.]+)/) if (match) { setSensorData({ temp: parseFloat(match[1]), humidity: parseFloat(match[2]) }) } }) await arduino.sendCommand('LED:ON') await arduino.sendCommand('SERVO:90') 

React hook for WebUSB

function useWebUSB() { const [device, setDevice] = useState<USBDevice | null>(null) const [isConnected, setIsConnected] = useState(false) const [isSupported] = useState(() => 'usb' in navigator) useEffect(() => { if (!isSupported) return function onConnect(event: USBConnectionEvent) { console.log('USB connected:', event.device.productName) } function onDisconnect(event: USBConnectionEvent) { if (event.device === device) { setDevice(null) setIsConnected(false) } } navigator.usb.addEventListener('connect', onConnect) navigator.usb.addEventListener('disconnect', onDisconnect) return () => { navigator.usb.removeEventListener('connect', onConnect) navigator.usb.removeEventListener('disconnect', onDisconnect) } }, [device, isSupported]) async function reconnectPaired() { const devices = await navigator.usb.getDevices() if (devices.length > 0) { const dev = devices[0] await connectDevice(dev) setDevice(dev) setIsConnected(true) } } return { device, isConnected, isSupported, reconnectPaired } } 

Diagnostics and reverse engineering

How to read a USB descriptor without documentation

function inspectDevice(device: USBDevice) { console.log('Vendor ID:', device.vendorId.toString(16)) console.log('Product ID:', device.productId.toString(16)) device.configuration?.interfaces.forEach((iface) => { console.log(`\nInterface ${iface.interfaceNumber}:`) iface.alternates.forEach((alt) => { alt.endpoints.forEach((ep) => { console.log(` Endpoint ${ep.endpointNumber}: ${ep.direction} ${ep.type}, packet size: ${ep.packetSize}`) }) }) }) } 

This helps find the required endpoint numbers without documentation.

More about protocol reverse engineering

If documentation for the device is missing, we use a USB traffic sniffer (e.g., Wireshark with usbmon) to capture commands. After analysis, we reconstruct the protocol and implement it in TypeScript. This method requires access to a reference device and application.

Typical problems and their solutions

Problem Cause Solution
Device not found by requestDevice() Incorrect filters or active system driver Check vendorId/productId, replace driver with WinUSB via Zadig
SecurityError on API call Not HTTPS or not user gesture Open page via HTTPS, call API after click
NotFoundError after requestDevice Device already claimed by another application Close other programs using USB
NetworkError on transferIn Device disconnected or timeout Reconnect device, implement retry logic

Diagnostics checklist:

  1. Check 'usb' in navigator — must be true.
  2. Ensure the page is served via HTTPS (or localhost).
  3. Call navigator.usb.requestDevice() only after a user click.
  4. If the device does not appear — open DevTools and check console for errors.
  5. On Windows, try replacing the device driver with WinUSB using Zadig.

What's included in the integration

  • Analysis: filter selection, protocol study, endpoint identification.
  • Prototype development: connection, command sending, data reception, error handling.
  • Testing: on target OS (Windows, macOS, Android), verify disconnection and reconnection.
  • Documentation: interaction scheme description, code examples.
  • Training: user instructions, driver setup recommendations (WinUSB).

Order turnkey WebUSB integration — we'll prepare a prototype in 5 days. Get a consultation on your device right now. With 6+ years in the market and over 30 projects, we deliver results. Typical engagement saves 200 hours of IT maintenance per month.

To ensure browser USB integration works smoothly, we test with Chrome WebUSB and verify WebUSB compatibility across all endpoints. Our Zebra WebUSB examples show how to connect a printer via browser. For Arduino WebUSB, bidirectional communication is demonstrated. The USB protocol reverse engineering process is detailed above. Replace your native app with a web-based solution today.