⚡ Node.jsQR / Barcodes
QR Code Validation in Node.js
Validate and classify QR code content in Node.js — detect URLs, vCards, Wi-Fi credentials, email addresses, phone numbers, and SMS payloads. Handle safe redirect logic and batch scan multiple codes in parallel.
Also available in Python
Contents
1. QR code content types
A QR code is just an encoded string. The payload determines how it should be handled:
| type | Payload example | Action |
|---|---|---|
| url | https://example.com/product/123 | Validate URL, safe redirect |
| vcard | BEGIN:VCARD\nFN:Jane Doe\n… | Parse and save contact |
| wifi | WIFI:T:WPA;S:MyNetwork;P:pass;; | Auto-connect to Wi-Fi |
| mailto:hello@example.com | Open email client | |
| phone | tel:+447911123456 | Initiate call |
| sms | sms:+447911123456?body=Hello | Open SMS app |
| text | Any plain text string | Display text |
2. Validate QR code content
Endpoint: GET /v0/qr-code?value=…
{ "valid": true, "type": "url", "content": "https://example.com/product/12345", "url": "https://example.com/product/12345" }
{ "valid": true, "type": "wifi", "content": "WIFI:T:WPA;S:MyNetwork;P:secret;;", "ssid": "MyNetwork", "security": "WPA" }
- Check
valid— well-formed QR payload - Switch on
typeto determine appropriate action - Use
contentas the raw parsed value
3. Handling URL payloads safely
⚠️Never blindly redirect users to a URL extracted from a QR code. QR codes are a common phishing vector — a malicious code can encode a lookalike domain or a data URI. Always validate the URL before acting on it.
import { createClient } from '@isvalid-dev/sdk' const iv = createClient({ apiKey: process.env.ISVALID_API_KEY! }) async function safeQrRedirect(scannedPayload: string): Promise<string> { const qr = await iv.qrCode(scannedPayload) if (!qr.valid || qr.type !== 'url') { throw new Error('QR code does not contain a URL') } const url = new URL(qr.url!) // Block non-HTTPS and known dangerous schemes if (url.protocol !== 'https:') { throw new Error(`Blocked: non-HTTPS URL (${url.protocol})`) } // Optionally validate the domain const domain = await iv.domain(url.hostname) if (!domain.valid) { throw new Error(`Blocked: invalid domain (${url.hostname})`) } return qr.url! }
4. Batch scanning with Promise.all
When processing multiple QR codes from a document scan or inventory system, validate them concurrently.
import { createClient } from '@isvalid-dev/sdk' const iv = createClient({ apiKey: process.env.ISVALID_API_KEY! }) async function processQrCode(rawContent: string) { const result = await iv.qrCode(rawContent) if (!result.valid) { throw new Error(`Invalid QR code content: ${rawContent}`) } switch (result.type) { case 'url': // Validate the embedded URL before redirecting if (!result.url?.startsWith('https://')) { throw new Error('QR code contains a non-HTTPS URL — refusing redirect') } return { action: 'redirect', target: result.url } case 'vcard': return { action: 'save_contact', data: result.content } case 'wifi': return { action: 'connect_wifi', data: result.content } case 'email': case 'phone': case 'sms': return { action: result.type, data: result.content } default: return { action: 'display_text', data: result.content } } } // Batch scan — validate multiple QR code payloads in parallel async function batchScan(payloads: string[]) { const results = await Promise.allSettled(payloads.map(p => iv.qrCode(p))) return payloads.map((payload, i) => ({ payload, result: results[i].status === 'fulfilled' ? results[i].value : null, error: results[i].status === 'rejected' ? results[i].reason?.message : null, })) } // Example const action = await processQrCode('https://example.com/product/12345') console.log(action) // { action: 'redirect', target: 'https://example.com/product/12345' }
5. Edge cases
Data URI in URL payload
⚠️A QR code can encode
data:text/html,<script>…</script>. Always block non-http/https schemes before processing.const qr = await iv.qrCode(payload) if (qr.type === 'url' && qr.url) { const url = new URL(qr.url) const ALLOWED_SCHEMES = ['https:', 'http:'] if (!ALLOWED_SCHEMES.includes(url.protocol)) { throw new Error(`Scheme not allowed: ${url.protocol}`) } }
Empty or whitespace payload
// QR decoders sometimes return empty string on failed scan const payload = scannedString.trim() if (!payload) throw new Error('Empty QR code payload — scan may have failed') const result = await iv.qrCode(payload)
6. Summary checklist
✓Validate QR payload before acting on it
✓Switch on type to dispatch correct action
✓Block non-HTTPS URLs from QR redirects
✓Validate embedded domain for URL payloads
✓Reject data: and javascript: URI schemes
✓Handle empty payload from failed scans
✓Run batch scans with Promise.allSettled
✓Return 422 with reason on invalid payloads