Conectamos un escáner Bluetooth a una web app — y esto es lo que aprendimos
Cómo convertimos un lector de códigos de barras de 30€ en la pieza clave de un sistema de inventario web. Sin SDKs, sin apps nativas. Solo JavaScript y un truco con keydown.
Todo empezó con una frase del cliente:
"Con la cámara del móvil vamos demasiado lento. ¿No hay un aparatito que lea más rápido?"
Spoiler: sí lo hay. Y por 30 euros.
Pero integrarlo en una aplicación web progresiva sin instalar nada fue… interesante. Este es el camino que recorrimos, los errores que cometimos, y el truco que lo hizo funcionar.
Un móvil. Un lector Bluetooth de 30€.
Un hook de React. 5x más rápido.
El contexto: inventario sanitario con trazabilidad
Estábamos desarrollando un sistema de gestión de inventario para una distribuidora de dispositivos médicos. Cada caja tiene un código DataMatrix con información codificada en formato GS1: referencia del producto, número de lote, fecha de caducidad. Todo obligatorio por normativa sanitaria europea.
Ya teníamos funcionando un escáner por cámara con tres capas de detección:
Funcionaba. Pero en una sesión de inventariado de 200+ productos, la cámara se quedaba corta. Enfocar, esperar al reconocimiento, mover a la siguiente caja… 3 productos por minuto. A ese ritmo, inventariar el almacén llevaba todo el día.
El hardware: un lector Bluetooth de 30€
Buscábamos un lector compacto, Bluetooth, compatible con iOS y Android sin instalar drivers. Encontramos el Eyoyo EY-017P (~30€ en Amazon). Se acopla a la parte trasera del móvil con una pinza y lee DataMatrix, EAN-13, Code 128 y QR a distancia.
Lo más importante: funciona en modo HID (Human Interface Device). ¿Qué significa esto? Que para el sistema operativo, es literalmente un teclado Bluetooth. Cada vez que escaneas un código, el lector "teclea" los caracteres a toda velocidad y pulsa Enter.
⚙️ Así funciona el modo HID
Esto significa que no necesitas WebBluetooth, no necesitas permisos especiales, no necesitas SDK propietario. Solo necesitas escuchar eventos de teclado en JavaScript.
¿Demasiado bonito para ser verdad? Casi. Hay un truco.
El reto: ¿quién está tecleando?
Si el escáner es un "teclado", los eventos llegan como pulsaciones normales al navegador. Pero el usuario también puede estar escribiendo en un campo de búsqueda. ¿Cómo distingues una cosa de la otra?
La respuesta está en la velocidad.
Un humano teclea una letra cada 100-300 milisegundos. Un escáner HID "teclea" una letra cada 5-15 milisegundos. Es literalmente 20 veces más rápido que un humano.
El algoritmo es simple: si las pulsaciones llegan con un gap promedio menor de 50ms, es un escáner. Si no, es una persona.
// 🔍 ¿Humano o escáner? La velocidad delata
const MAX_GAP_MS = 50
function onKeyDown(e: KeyboardEvent) {
const now = Date.now()
const gap = now - lastKeyTime
if (gap < MAX_GAP_MS) {
buffer += e.key // Rápido → escáner → acumular
} else {
buffer = e.key // Lento → humano → resetear
}
lastKeyTime = now
if (e.key === "Enter" && buffer.length > 4) {
onScan(buffer) // ¡Código completo!
buffer = ""
}
}
Esto corre en un event listener global en fase capture, para interceptar las pulsaciones antes de que lleguen a cualquier input del DOM. Así el escáner funciona sin importar dónde esté el foco.
Gotcha de iOS con teclados Bluetooth
Cuando iOS detecta un teclado BT conectado, oculta el teclado virtual automáticamente. Solución: pulsa dos veces el botón lateral del escáner, o toca el icono diminuto (▽) que aparece en la esquina inferior derecha de la pantalla.
En la práctica no es problema: la vinculación código → producto solo se hace una vez por referencia. Después, todo va automático sin escribir nada.
El detalle que marca la diferencia
Algo que añadimos y que al cliente le encantó: un indicador visual en la cabecera del escáner que parpadea brevemente cuando el Eyoyo detecta un código. Un badge verde que dice "HID" durante 1.2 segundos.
Parece una tontería, pero en un almacén sin mirar la pantalla (apuntas el lector a la caja, aprietas el gatillo), ese flash verde en el rabillo del ojo te confirma que "ha ido bien, pasa a la siguiente".
// 💚 Flash visual de confirmación — UX que importa
onScan: (code) => {
setHidFlash(true) // Badge verde "HID"
setTimeout(() => setHidFlash(false), 1200) // Desaparece en 1.2s
onBarcodeDetected(code, "hid") // Procesa el código
}
Pequeñas cosas que hacen que una herramienta técnica se sienta humana.
Los números
De 3 a 15 productos por minuto. 5x más rápido por 30€ y una mañana de desarrollo. Sin instalar nada en el móvil. Sin SDK. Sin app nativa.
Lo que haríamos diferente
Honestamente, poca cosa. Pero si nos pusiéramos finos:
- Vibración diferenciada — una vibración corta para cámara, doble para HID. Feedback táctil sin mirar la pantalla.
- Modo solo-HID — si sabes que vas a usar el lector toda la sesión, poder apagar la cámara y ahorrar batería.
- Gap configurable — algunos lectores baratos son más lentos. El
maxInterKeyMsdebería ser ajustable desde settings.
TL;DR para los impacientes
Si estás construyendo una app web de inventario, logística, punto de venta, o cualquier cosa que necesite escaneo rápido de códigos de barras:
- Compra un lector Bluetooth HID (~30€). No necesitas uno caro.
- Escucha
keydownen fase capture para interceptar antes que el DOM. - Mide el gap entre pulsaciones: promedio <50ms = escáner.
- Acumula el buffer hasta
Enter, luego emite el código completo. - No reemplaces la cámara — deja que ambos métodos convivan.
Sin WebBluetooth. Sin permisos especiales. Sin SDKs. Solo JavaScript escuchando teclas muy, muy rápidas.
🛠️ Stack utilizado en este proyecto
¿Estás construyendo algo parecido? En Nexus Code desarrollamos aplicaciones web a medida con Next.js, React y TypeScript. Sistemas de inventario, integraciones con hardware, automatización con IA — cuéntanos tu proyecto y te decimos cómo lo haríamos.