QuadQR Docs
Demo npm GitHub
QUADQR 1.0.1

Build with QuadQR in the browser or Node.js.

Generate, render, scan, and optionally protect QuadQR payloads with one shared JavaScript codec. Use the npm package, a browser bundler, Node.js, the CLI, or a plain script tag from a CDN.

Live library outputLoading...
INSTALLATION

Install the JavaScript package

npm install quadqr-js
Corequadqr-js

Encoding, decoding, secure payloads, RGBA scanning, rendering, utilities, and optional WASM.

Browserquadqr-js/browser

Browser ESM entry for canvas rendering, image files, video frames, and live camera scanning.

Node.jsquadqr-js/node

Shared core plus PNG generation, file scanning, and buffer scanning.

QUICK START

Encode text and decode the matrix

import { encodeText, decodeMatrix } from "quadqr-js";

const code = encodeText("Hello QuadQR", { ecc: "M" });
const result = decodeMatrix(code.matrix);

console.log(result.text); // Hello QuadQR

When no version is supplied, QuadQR chooses the smallest version that can hold the payload.

BROWSER

Render, scan image files, and use the camera

import {
  encodeText,
  renderToCanvas,
  scanFile,
  startCameraScanner
} from "quadqr-js/browser";

const code = encodeText("Hello from the browser", { ecc: "M" });
renderToCanvas(code, document.querySelector("#qr"));

// Image upload
const fileInput = document.querySelector("#image");
const imageResult = await scanFile(fileInput.files[0]);
console.log(imageResult.text);

// Live camera
let scanner;
scanner = await startCameraScanner(document.querySelector("#video"), {
  onDecode(result) {
    console.log(result);
    scanner.stop();
  }
});

Camera access requires HTTPS or localhost. Secure scans return a locked result first and can be decrypted with decryptDecoded().

NODE.JS

Generate and scan PNG files on the server

import { encodeText } from "quadqr-js";
import { savePNG, scanFile } from "quadqr-js/node";

const code = encodeText("Generated on Node.js");
await savePNG(code, "quadqr.png", {
  moduleSize: 12,
  quietZone: 4
});

const result = await scanFile("quadqr.png");
console.log(result.text);

PNG support is built in and does not require a native image dependency. JPEG, WebP, and AVIF input can use sharp when it is installed by the consuming project.

SCANNING

One scanner pipeline across browser images, camera frames, and Node.js

PixelsGeometryColor calibrationSpectrum ECCPayload
RGBA pixelsscanImageData()

Runtime-neutral scanning when your app already has decoded pixels.

Browser filesscanFile()

Scan uploaded images directly from a browser File or Blob.

Live camerastartCameraScanner()

Continuously scan video frames and receive decoded results through a callback.

Image and camera scanning use the same secure-aware decoding behavior. An encrypted symbol is detected normally, but plaintext is not exposed until the correct credential is supplied.

SECURE PAYLOAD V1

Optional authenticated encryption for protected data

Secure Payload is opt-in. Normal QuadQR codes remain unencrypted and require no password or key.

Password mode

Designed for human-entered secrets. PBKDF2-HMAC-SHA-256 derives a 256-bit key and AES-256-GCM protects confidentiality and integrity.

Raw 256-bit key mode

Designed for applications that already manage cryptographic keys, such as provisioning systems, ticket scanners, and device workflows.

import {
  encodeSecureText,
  decodeMatrix,
  decryptDecoded
} from "quadqr-js";

const code = await encodeSecureText("Private payload", {
  security: {
    mode: "password",
    password: "correct horse battery staple"
  }
});

const locked = decodeMatrix(code.matrix);
const result = await decryptDecoded(locked, {
  password: "correct horse battery staple"
});

console.log(result.text);

For application-managed keys, set mode: "raw-key" and provide an exact 32-byte key. The key itself is never stored in the QuadQR symbol.

RENDERING

Use the same matrix with multiple visual styles

renderToCanvas(code, document.querySelector("#qr"), {
  moduleSize: 12,
  quietZone: 4,
  style: "classic" // classic | depth | soft | inset
});

Styles affect presentation only. They do not change the encoded matrix, payload, or wire format.

PUBLIC API

Common methods

encodeText()

Encode UTF-8 text.

encodeBytes()

Encode arbitrary bytes.

encodeSecureText()

Encrypt and encode text.

decodeMatrix()

Decode a sampled matrix.

scanImageData()

Scan RGBA pixels.

scanFile()

Scan browser files.

startCameraScanner()

Live browser camera scanner.

decryptDecoded()

Unlock secure scan results.

renderToCanvas()

Render in a browser canvas.

renderToImageData()

Render runtime-neutral RGBA pixels.

getVersionInfo()

Inspect capacity and geometry.

initWasm()

Enable optional WASM acceleration.

See the complete API reference for options and Node-specific helpers.

CDN

Use QuadQR from a script tag with no build step

<canvas id="qr"></canvas>
<script src="https://cdn.jsdelivr.net/npm/quadqr-js@1.0.1/dist/quadqr.min.js"></script>
<script>
  const code = QuadQR.encodeText("Hello from a script tag");
  QuadQR.renderToCanvas(code, document.querySelector("#qr"));
</script>

The same global build is available through unpkg. Pin an exact package version for production sites.

CLI

Encode and decode QuadQR from the terminal

# Normal QuadQR
npx quadqr-js encode "Hello QuadQR" -o hello.png
npx quadqr-js decode hello.png

# Password-protected QuadQR
npx quadqr-js encode "Private data" --password "my-password" -o secure.png
npx quadqr-js decode secure.png --password "my-password"

For application-managed key workflows, the CLI also supports --key <64-hex-key> and keygen. See the CLI guide for all options.

OPTIONAL WASM

Enable the bundled accelerator when you want it

import { initWasm } from "quadqr-js";

await initWasm();

The JavaScript codec works without WASM. In 0.7.x the optional prebuilt module accelerates CRC-32 while keeping the same public API and wire format.