npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

real-scanner

v1.1.2

Published

A secure QR/Barcode scanner package with modal interface and API key verification

Readme

Real Scanner Package

A powerful, secure QR/Barcode scanner package with modal interface and API key verification. Built with TypeScript and powered by ZXing library for reliable barcode detection across multiple formats.

Features

  • 🔐 Secure Authentication - API key verification with backend validation
  • 📱 Modal Interface - Beautiful, responsive modal scanner with auto-sizing
  • 🎯 Multi-Format Support - QR codes, Code 128, EAN-13, UPC, Data Matrix, and more
  • 📊 Auto Logging - Automatic scan logging with metadata tracking
  • 🔧 TypeScript Ready - Full type definitions and IntelliSense support
  • 📷 Optimized Camera - Enhanced camera settings with autofocus and HD resolution
  • 🎨 Responsive Design - Mobile-friendly modal with adaptive sizing
  • Performance Optimized - Non-blocking scan operations and efficient processing
  • 🛠️ Easy Integration - Simple API with automatic initialization

Installation

npm install real-scanner

Quick Start

1. Basic Setup & Initialization

import RealScanner from 'real-scanner';

// Initialize scanner with auto-verification
const scanner = new RealScanner({
  accessKey: 'ak_your_access_key_here',
  secret: 'your_secret_here',
  open_model: true, // Enable modal interface (default: true)
  autoLogScans: true, // Auto-log all scans (default: true)
  onScanSuccess: (result) => {
    console.log('✅ Scan successful!');
    console.log('Code:', result.getText());
    console.log('Format:', result.getBarcodeFormat().toString());
    // Scanner will auto-close the modal after successful scan
  },
  onScanError: (error) => {
    console.error('❌ Scan error:', error);
  },
  onAuthError: (error) => {
    console.error('🔒 Authentication failed:', error);
    // Handle auth errors (show login form, etc.)
  }
});

// Scanner automatically initializes and verifies credentials

2. Open Scanner Modal

// Simple modal opening
const openScannerButton = document.getElementById('scan-btn');
openScannerButton?.addEventListener('click', async () => {
  try {
    await scanner.openScanner();
  } catch (error) {
    console.error('Failed to open scanner:', error);
  }
});

// Advanced modal with metadata tracking
await scanner.openScanner({
  metadata: [
    { key: 'location', value: 'warehouse-A' },
    { key: 'operator', value: 'john-doe' },
    { key: 'shift', value: 'morning' }
  ],
  onClose: () => {
    console.log('📱 Scanner modal closed');
  }
});

API Reference

ScannerConfig Interface

interface ScannerConfig {
  accessKey: string;           // Required: Your API access key (format: ak_xxxxx)
  secret: string;              // Required: Your API secret key
  serverUrl?: string;          // Optional: Backend server URL (default: https://scanner-backend-iy9y.onrender.com)
  open_model?: boolean;        // Optional: Enable modal interface (default: true)
  onScanSuccess?: (result: Result) => void;  // Optional: Called when scan succeeds
  onScanError?: (error: Error) => void;      // Optional: Called on scan errors
  onAuthError?: (error: string) => void;     // Optional: Called on auth failures
  hints?: Map<DecodeHintType, any>;          // Optional: ZXing decoder hints for custom formats
  autoLogScans?: boolean;      // Optional: Auto-log all scans to backend (default: true)
}

Additional Interfaces

interface ScanModalOptions {
  metadata?: MetadataField[];  // Optional: Custom metadata to attach to scans
  onClose?: () => void;        // Optional: Callback when modal closes
  width?: string;              // Optional: Modal width (auto-responsive)
  height?: string;             // Optional: Modal height (auto-responsive)
}

interface MetadataField {
  key: string;                 // Metadata key (e.g., 'location', 'operator')
  value: string;               // Metadata value
}

interface ScanLogData {
  scannedCode: string;
  scanType: 'QR' | 'BARCODE' | 'OTHER';
  scanResult?: any;
  deviceInfo?: any;
  timestamp?: string;
  metadata?: Record<string, string>;
}

Modal Options

interface ScanModalOptions {
  metadata?: MetadataField[];  // Optional: Additional data to log with scans
  onClose?: () => void;        // Optional: Callback when modal is closed
  width?: string;              // Optional: Modal width (default: '400px')
  height?: string;             // Optional: Modal height (default: '500px')
}

Core Methods

openScanner(options?: ScanModalOptions): Promise<void>

Opens the modal scanner interface. This is the primary method for scanning.

// Simple usage
await scanner.openScanner();

// With metadata and callbacks
await scanner.openScanner({
  metadata: [
    { key: 'department', value: 'inventory' },
    { key: 'session_id', value: 'abc123' }
  ],
  onClose: () => {
    console.log('Scanning session ended');
  }
});

setCredentialsAndVerify(accessKey: string, secret: string): Promise<boolean>

Manually set and verify API credentials (alternative to constructor approach).

try {
  const isValid = await scanner.setCredentialsAndVerify('ak_newkey', 'newsecret');
  if (isValid) {
    console.log('✅ Credentials updated and verified!');
  }
} catch (error) {
  console.error('❌ Verification failed:', error);
}

initialize(): Promise<boolean>

Verifies the API credentials with the backend. Called automatically in constructor.

// Manual initialization (if needed)
try {
  const isValid = await scanner.initialize();
  console.log('Scanner ready:', isValid);
} catch (error) {
  console.error('Initialization failed:', error);
}

setMetadata(metadata: MetadataField[]): void

Set metadata that will be attached to all future scans.

scanner.setMetadata([
  { key: 'store_id', value: 'store_001' },
  { key: 'cashier', value: 'jane_doe' }
]);

getMetadata(): Record<string, string>

Get the currently set metadata.

const currentMetadata = scanner.getMetadata();
console.log('Current metadata:', currentMetadata);

stopScanning(): void

Stops scanning and releases camera resources.

scanner.stopScanning();

closeScanner(): void

Closes the scanner modal and stops scanning.

scanner.closeScanner();

isReady(): boolean

Checks if scanner is initialized and ready to use.

if (scanner.isReady()) {
  console.log('✅ Scanner ready - can open modal');
} else {
  console.log('⏳ Scanner not ready - check credentials');
}

isScannerActive(): boolean

Checks if scanner is currently active/scanning.

if (scanner.isScannerActive()) {
  console.log('📷 Scanner is currently active');
}

getUserId(): string | null

Gets the current user ID from the verified API key.

const userId = scanner.getUserId();
if (userId) {
  console.log('User ID:', userId);
}

destroy(): void

Cleans up all resources.

scanner.destroy();

Complete Usage Examples

1. Simple Modal Scanner

import RealScanner from 'real-scanner';

// Initialize scanner
const scanner = new RealScanner({
  accessKey: 'ak_your_key_here',
  secret: 'your_secret_here',
  onScanSuccess: (result) => {
    console.log(`✅ Scanned: ${result.getText()}`);
    console.log(`📊 Format: ${result.getBarcodeFormat().toString()}`);
    // Modal automatically closes after successful scan
    // Scan is automatically logged to backend
  },
  onAuthError: (error) => {
    alert(`Authentication failed: ${error}`);
  }
});

// Add scan button to your page
const scanButton = document.getElementById('scan-btn');
scanButton.addEventListener('click', async () => {
  if (scanner.isReady()) {
    await scanner.openScanner();
  } else {
    alert('Scanner not ready. Check your credentials.');
  }
});

2. E-commerce Integration Example

import RealScanner from 'real-scanner';

class ProductScanner {
  private scanner: RealScanner;
  
  constructor() {
    this.scanner = new RealScanner({
      accessKey: process.env.SCANNER_ACCESS_KEY!,
      secret: process.env.SCANNER_SECRET!,
      onScanSuccess: (result) => {
        this.handleProductScan(result.getText());
      },
      onAuthError: (error) => {
        console.error('Scanner auth failed:', error);
        this.showAuthError();
      }
    });
  }
  
  async scanProduct(storeId: string, employeeId: string) {
    // Set metadata for tracking
    this.scanner.setMetadata([
      { key: 'store_id', value: storeId },
      { key: 'employee_id', value: employeeId },
      { key: 'action', value: 'product_scan' }
    ]);
    
    // Open scanner with custom close handler
    await this.scanner.openScanner({
      onClose: () => {
        console.log('Product scan session ended');
      }
    });
  }
  
  private async handleProductScan(barcode: string) {
    try {
      // Look up product in your database
      const product = await fetch(`/api/products/${barcode}`).then(r => r.json());
      
      if (product) {
        this.displayProduct(product);
      } else {
        alert('Product not found in inventory');
      }
    } catch (error) {
      console.error('Product lookup failed:', error);
    }
  }
  
  private displayProduct(product: any) {
    // Update UI with product info
    document.getElementById('product-name')!.textContent = product.name;
    document.getElementById('product-price')!.textContent = `$${product.price}`;
    document.getElementById('product-stock')!.textContent = `${product.stock} in stock`;
  }
  
  private showAuthError() {
    // Handle authentication error in UI
    const errorDiv = document.getElementById('error-message');
    errorDiv!.textContent = 'Scanner authentication failed. Please contact support.';
    errorDiv!.style.display = 'block';
  }
}

// Usage
const productScanner = new ProductScanner();
const scanBtn = document.getElementById('scan-product-btn');
scanBtn?.addEventListener('click', () => {
  productScanner.scanProduct('store_001', 'emp_123');
});

Scan from Image File

const scanner = new RealScanner({
  accessKey: 'your-access-key',
  secret: 'your-secret-key'
});

await scanner.initialize();

const fileInput = document.getElementById('file-input');
fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  const imageUrl = URL.createObjectURL(file);
  
  try {
    const result = await scanner.scanImage(imageUrl);
    console.log('Scanned:', result.getText());
    // Automatically logged to backend
  } catch (error) {
    console.error('No barcode found');
  }
});

Disable Auto-Logging and Log Manually

const scanner = new RealScanner({
  accessKey: 'your-access-key',
  secret: 'your-secret-key',
  autoLogScans: false, // Disable automatic logging
  onScanSuccess: async (result) => {
    // Custom logic before logging
    const shouldLog = confirm('Log this scan?');
    
    if (shouldLog) {
      await scanner.manualLogScan({
        scannedCode: result.getText(),
        scanType: 'QR',
        scanResult: {
          format: result.getBarcodeFormat().toString(),
          timestamp: new Date().toISOString()
        }
      });
    }
  }
});

await scanner.initialize();
await scanner.startScanning();

View Scan History

const scanner = new RealScanner({
  accessKey: 'your-access-key',
  secret: 'your-secret-key'
});

await scanner.initialize();

// Get recent scans
const logsData = await scanner.getScanLogs(1, 10);

console.log(`Total scans: ${logsData.pagination.total}`);
logsData.logs.forEach(log => {
  console.log(`${log.scan_type}: ${log.scanned_code} at ${log.created_at}`);
});

Display Statistics Dashboard

const scanner = new RealScanner({
  accessKey: 'your-access-key',
  secret: 'your-secret-key'
});

await scanner.initialize();

const stats = await scanner.getStats();

console.log('API Key:', stats.apiKey.name);
console.log('Total Scans:', stats.statistics.totalScans);
console.log('Recent Scans (24h):', stats.statistics.recentScans24h);
console.log('QR Codes:', stats.statistics.scansByType.QR || 0);
console.log('Barcodes:', stats.statistics.scansByType.BARCODE || 0);

Select Camera Device

const scanner = new RealScanner({
  accessKey: 'your-access-key',
  secret: 'your-secret-key'
});

await scanner.initialize();

// Get available devices
const devices = await scanner.getVideoDevices();
console.log('Available cameras:', devices);

// Use specific camera
await scanner.startScanning({
  deviceId: devices[1].deviceId // Use second camera
});

Backend Integration

Server Requirements

Your backend server must implement the following endpoints:

1. Verify API Key

POST /api/v1/verify-key

Request:

{
  "accessKey": "your-access-key",
  "secret": "your-secret-key"
}

Response (Success):

{
  "success": true,
  "valid": true,
  "message": "API key verified successfully",
  "data": {
    "id": "key-id",
    "user_id": "user-id",
    "name": "My API Key",
    "access_key": "your-access-key",
    "status": "active"
  }
}

2. Log Scan

POST /api/v1/log-scan

Headers:

Authorization: Bearer your-access-key
Content-Type: application/json

Request:

{
  "scannedCode": "ABC123",
  "scanType": "QR",
  "scanResult": {
    "format": "QR_CODE",
    "text": "ABC123"
  },
  "deviceInfo": {
    "userAgent": "...",
    "platform": "..."
  },
  "ipAddress": "192.168.1.1",
  "timestamp": "2025-01-01T00:00:00.000Z"
}

Response:

{
  "success": true,
  "message": "Scan logged successfully",
  "data": {
    "scanLogId": "log-id",
    "timestamp": "2025-01-01T00:00:00.000Z"
  }
}

3. Get Statistics (Optional)

GET /api/v1/stats

Headers:

Authorization: Bearer your-access-key

4. Get Scan Logs (Optional)

GET /api/v1/scan-logs?page=1&limit=50

Headers:

Authorization: Bearer your-access-key

Scan Types

The scanner automatically categorizes scans into three types:

  • QR: QR_CODE, DATA_MATRIX, AZTEC, MAXICODE
  • BARCODE: EAN_13, EAN_8, UPC_A, UPC_E, CODE_128, CODE_39, CODE_93, CODABAR, ITF
  • OTHER: All other formats

Automatic Scan Logging

By default, every successful scan is automatically logged to your backend with comprehensive data:

Logged Data Includes:

  • 📝 Scanned code text
  • 🔖 Scan type (QR/BARCODE/OTHER)
  • 📊 Barcode format (CODE_128, QR_CODE, etc.)
  • 🖥️ Device information (user agent, platform, screen resolution)
  • ⏰ Timestamp (ISO format)
  • 🏷️ Custom metadata (if provided)
  • 📍 IP address and session info

Example logged data:

{
  "scannedCode": "ABC123456789",
  "scanType": "BARCODE",
  "scanResult": {
    "format": "CODE_128",
    "text": "ABC123456789",
    "rawBytes": 12
  },
  "deviceInfo": {
    "userAgent": "Mozilla/5.0...",
    "platform": "MacIntel",
    "language": "en-US",
    "screenResolution": "1920x1080"
  },
  "metadata": {
    "location": "warehouse-A",
    "operator": "john-doe",
    "shift": "morning"
  },
  "timestamp": "2025-11-30T10:15:30.000Z"
}

Disable automatic logging:

const scanner = new RealScanner({
  accessKey: 'ak_your_key',
  secret: 'your_secret',
  autoLogScans: false  // Disable auto-logging
});

Error Handling

const scanner = new RealScanner({
  accessKey: 'your-key',
  secret: 'your-secret'
});

try {
  await scanner.initialize();
  await scanner.startScanning();
} catch (error) {
  if (error.message === 'Invalid API credentials') {
    console.error('Please check your access key and secret');
  } else {
    console.error('Scanner error:', error);
  }
}

Security Notes

  • Access key and secret are transmitted securely via HTTPS
  • Invalid credentials trigger alerts and prevent scanner usage
  • All scanning operations are blocked until credential verification succeeds
  • Scans are logged with authentication headers

Performance Features

  • 🚀 Non-blocking Operations - Scan logging doesn't block the scanning loop
  • 📱 Responsive Modal - Auto-adapts to mobile/desktop (100vh mobile, 80vh desktop)
  • 🎯 Optimized Camera Settings - 1920x1080 resolution with autofocus
  • Fast Detection - Enhanced ZXing hints for quick barcode recognition
  • 🔄 Efficient Scanning - Suppresses "not found" errors to reduce noise
  • 📦 Lightweight - Minimal dependencies, TypeScript compiled

Browser Compatibility

  • Chrome/Edge 56+ (Recommended)
  • Firefox 52+
  • Safari 11+
  • Mobile browsers (iOS Safari, Chrome Mobile)
  • 🔒 Requires HTTPS for camera access (except localhost development)
  • 📱 Mobile responsive - Optimized for touch devices

Troubleshooting

Common Issues

Scanner not opening:

// Check if scanner is ready
if (!scanner.isReady()) {
  console.log('Scanner not ready - check credentials');
}

// Check browser console for auth errors

Camera permission denied:

  • Ensure you're using HTTPS (required for camera access)
  • Check browser camera permissions in settings
  • Try refreshing the page and allowing camera access

Performance warnings in console:

  • These are normal ZXing library warnings
  • The scanner is optimized to prevent blocking operations
  • No action needed from your side

Scans not being logged:

// Check if auto-logging is enabled
const scanner = new RealScanner({
  accessKey: 'your_key',
  secret: 'your_secret',
  autoLogScans: true  // Make sure this is true
});

// Check network requests in browser dev tools

Modal not responsive on mobile:

  • The modal automatically adapts to screen size
  • On mobile: 100vw x 100vh (fullscreen)
  • On desktop: 80vh x 80vh (windowed)

License

MIT

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Support

For issues and questions, please open an issue on GitHub or contact support.