Skip to main content
Version: 1.0.8

QR / Barcode Scanner New in 1.0.8

Reads QR codes and barcodes into the screen — from the device's camera, from a USB or Bluetooth handheld scanner, or from a photo — and fires scan with what it read, so a scan can write a tag, look up a record or open a screen.

Reach for it when you need:

  • Scanning a work-order or batch label at a line terminal and writing it to a tag
  • A tablet on the floor that opens the right equipment screen from the code on the machine
  • Checking a part number against a pattern before it is accepted

Component name: BarcodeScanner · Category: Input

In the palette: Reads QR codes and barcodes from the device camera, a USB/Bluetooth handheld scanner (keyboard wedge) or a photo. The scanned text becomes this widget's value ({{nodes.<scanner id>.props.value}}) and fires the scan event — wire scan → Set tag with value scan.text to write it to a tag. Decoding runs in a WebAssembly worker, never on the UI thread. The camera needs HTTPS or localhost; the handheld and image modes work over plain HTTP.

Properties​

Any property can be bound to a tag, another component's property, or a query.

PropertyTypeDefaultDescription
valuestring""The last ACCEPTED scan. Bind it by node id, e.g. {{nodes.<scanner id>.props.value}}.
modesobject{"camera":true,"hid":true,"image":true,"default":"camera"}Which inputs the scanner offers, and which it shows first.
  ↳ modes.camerabooleantrueOffer the live camera mode.
  ↳ modes.hidbooleantrueAccept a USB/Bluetooth handheld scanner (it types like a keyboard). Listens in every mode while enabled, so a handheld works beside the camera.
  ↳ modes.imagebooleantrueOffer decoding a picked or freshly taken photo.
  ↳ modes.defaultenumcameraThe mode shown first. Options: camera · hid · image.
scanningobject{"mode":"continuous","formats":"common","pattern":"","cooldo… (truncated)What counts as a scan: continuous or single, accepted formats, an optional pattern, the duplicate cooldown and the per-second cap.
  ↳ scanning.modeenumcontinuouscontinuous keeps scanning; single stops after the first accepted code and shows "Scan again". Options: continuous · single.
  ↳ scanning.formatsenumcommonWhich symbologies are accepted. Fewer formats decode faster. A code outside the set fires scanRejected (reason format_not_allowed). Options: common · qr · matrix · linear · any.
  ↳ scanning.patternstring""Optional regular expression a scan must match, e.g. ^PN-\d{6}$. A non-matching scan fires scanRejected (reason pattern_mismatch) instead of scan.
  ↳ scanning.cooldownMsnumber1500The same code read again within this many ms is ignored (no event) — a label held in front of the camera fires once.
  ↳ scanning.maxPerSecondnumber5Hard cap on accepted scans per second, so a scanner can never flood the tag-write path.
feedbackobject{"beep":true,"vibrate":true,"showLastScan":true}What the operator gets on a scan.
  ↳ feedback.beepbooleantrueBeep on a scan (a low tone on a rejected one).
  ↳ feedback.vibratebooleantrueVibrate on a scan (phones/tablets).
  ↳ feedback.showLastScanbooleantrueShow the last scanned text and its format under the scanner.
cameraobject{"select":"back","nameMatch":"","showPicker":true,"showOverl… (truncated)Which camera to use, the operator's camera picker, the aiming box and the decode rate.
  ↳ camera.selectenumbackWhich camera to start: back (environment), front (user), or match = the first camera whose name contains nameMatch. The operator's own pick (camera dropdown) is remembered per browser and wins. Bindable. Options: back · front · match.
  ↳ camera.nameMatchstring""Part of the camera name to match, e.g. "Logitech" or "USB" (case-insensitive).
  ↳ camera.showPickerbooleantrueLet the operator choose among the device's cameras (and flip front/back). Turn off to lock the camera.
  ↳ camera.showOverlaybooleantrueShow the aiming box. Only the area inside it is decoded.
  ↳ camera.scanRatenumber10Target camera decodes per second. It backs off automatically on a slow device (down to 3/s).
hidobject{"scope":"global","terminator":"enter","minLength":4,"maxInt… (truncated)USB/Bluetooth handheld scanner (keyboard wedge) detection.
  ↳ hid.scopeenumglobalglobal: the handheld works whenever this view is open (not while the operator types in a text field). focused: only after clicking the scanner widget. Options: global · focused.
  ↳ hid.terminatorenumenterThe key the handheld sends after a code (Enter on most scanners). It is swallowed, so it never submits a form. Options: enter · tab · none.
  ↳ hid.minLengthnumber4Shortest keystroke burst treated as a scan.
  ↳ hid.maxInterKeyMsnumber35Longest gap between keystrokes of one scan. Scanners type 5–20 ms apart, people 80+ ms; raise it only for a slow Bluetooth scanner.
  ↳ hid.prefixstring""Characters the scanner adds before the code, stripped from the value.
  ↳ hid.suffixstring""Characters the scanner adds after the code, stripped from the value.
outputobject{"value":"","format":"","source":"","timestamp":0,"count":0,… (truncated)Read-only runtime outputs — bind a leaf by node id, e.g. {{nodes.<scanner id>.props.output.format}}.
  ↳ output.valuestring""Last accepted scan.
  ↳ output.formatstring""Its symbology (qr_code, code_128, ean_13 …; unknown for a handheld scanner).
  ↳ output.sourcestring""camera, hid or image.
  ↳ output.timestampnumber0When it was accepted, epoch ms.
  ↳ output.countnumber0Accepted scans since the view opened.
  ↳ output.errorstring""The latest camera or decode error, or empty.
  ↳ output.cameraStatestringidleidle, starting, running, paused or error.
  ↳ output.cameraIdstring""Active camera device id (this browser only).
  ↳ output.cameraLabelstring""Active camera name.
stylestyle{}Custom CSS properties

Events​

Attach event actions to these in the Event Manager.

EventLabelGroupPayload
clickClickMouseThe DOM event.
dblclickDouble clickMouseThe DOM event.
contextmenuRight clickMouseThe DOM event.
mouseenterMouse enterMouseThe DOM event.
mouseleaveMouse leaveMouseThe DOM event.
scanScanScannercontext.scan — { text, format, source: "camera"|"hid"|"image", timestamp (epoch-ms), count, cameraLabel }. In action fields: scan.text.
scanRejectedScan rejectedScannercontext.scan — the same fields as scan plus reason: "format_not_allowed" | "pattern_mismatch".
scanErrorScan errorScannercontext.scan — { source, errorCode: "no_code_found"|"decode_failed", errorMessage }.
cameraReadyCamera readyScannercontext.camera — { deviceId, label, facing: "front"|"back"|"unknown", width, height }.
cameraChangeCamera changedScannercontext.camera — the newly active camera, same fields as cameraReady.
cameraErrorCamera errorScannercontext.camera — { errorCode: "permission_denied"|"not_found"|"insecure_context"|"device_lost"|"in_use"|"unsupported", errorMessage, deviceId, label }.
Right-click behaves differently in the Designer

contextmenu fires your configured actions at runtime only — in LiveView and in preview. On the Designer canvas the right-click is captured to open the Event Manager, so testing it there will not run your actions. Test right-click in preview.

Notes​

Wiring a scan to a tag​

Handle Scan in the Event Manager with a Set tag action whose value is {{scan.text}} (the Event Manager offers it as Scanned text). The last accepted scan is also the widget's value, so another widget can bind to it by the scanner's node id. A script reads the scan as context.scan — { text, format, source, timestamp, count, cameraLabel }.

Three ways in​

modes turns each input on or off and picks the one shown first:

  • Camera — decodes the live picture inside the aiming box, about camera.scanRate (10) times a second, backing off to 3 on a slow device. The camera needs HTTPS, or localhost; over plain HTTP the browser refuses it and cameraError fires with insecure_context. The operator can switch cameras unless camera.showPicker is off, and their pick is remembered in that browser. The camera is released whenever the widget is hidden.
  • Handheld (hid) — a USB or Bluetooth scanner types like a keyboard. The widget tells a scan from typing by its speed: a burst of at least hid.minLength (4) characters with no gap over hid.maxInterKeyMs (35 ms) — scanners type 5–20 ms apart, people 80 ms or more. With hid.scope global it listens while the view is open, but never while the operator is typing in a text field; focused listens only after the widget is clicked. The terminator key the scanner sends (Enter on most) is swallowed, so it cannot submit a form. The handheld listens in every mode, beside the camera.
  • Image — decode a picked or freshly taken photo.

The handheld and image modes work over plain HTTP.

What counts as a scan​

Every read passes one gate, set under scanning:

SettingEffect
formatscommon (default), qr, matrix, linear or any. Fewer decode faster. A code outside the set fires scanRejected with reason format_not_allowed.
patternA regular expression the text must match, e.g. ^PN-\d{6}$. A miss fires scanRejected with reason pattern_mismatch.
cooldownMsThe same code read again within 1,500 ms is ignored — no event — so a label held in front of the camera fires once.
maxPerSecondAt most 5 accepted scans a second, so a scanner can never flood the tag writes.
modecontinuous keeps scanning; single stops after the first accepted code and shows Scan again.

feedback beeps (a low tone on a rejected scan), vibrates on a phone or tablet, and shows the last text and format under the scanner.

Events​

scan, scanRejected and scanError (no code found, or a decode failure) carry scan; cameraReady, cameraChange and cameraError carry camera. A camera error names its cause — permission_denied, not_found, insecure_context, device_lost, in_use or unsupported — so a handler can tell the operator what to fix. output publishes the last scan, its format and source, a count, and the camera's state.

Decoding runs in a WebAssembly worker shipped with the product, never on the screen's main thread and never from the internet, so it works on an isolated network.

See also​