Ready Barcode Scanner App with Barkoder Capacitor SDK
Introduction
This tutorial demonstrates how to build a complete, production-ready barcode scanning application using the barKoder Capacitor SDK. The Barkoder SDK is a powerful, enterprise-grade barcode scanning solution that leverages native device capabilities to deliver exceptional performance and accuracy.
Why Barkoder SDK?
The barKoder SDK stands out because:
- 40+ barcode symbologies (1D and 2D) - From traditional UPC/EAN codes to modern 2D matrix codes, the SDK handles virtually any barcode format you'll encounter in commercial, industrial, or consumer applications.
- Multiple scanning modes optimized for different use cases - Rather than a one-size-fits-all approach, Barkoder provides specialized modes (Continuous, Multi-Scan, VIN, DPM, AR Mode, Document Mode, etc.) that are pre-configured for specific industries and scenarios.
- Advanced features like DPM, AR Mode, Multi-Scan, and more - Direct Part Marking (DPM) for industrial applications, Augmented Reality overlays for interactive experiences, and simultaneous multi-barcode scanning for batch operations.
- High performance with hardware-accelerated decoding - The SDK utilizes native device capabilities and optimized algorithms to achieve real-time scanning even on mid-range devices.
- Flexible configuration for any scanning scenario - Every aspect of the scanner behavior can be customized, from decoding speed and resolution to visual feedback and scanning regions.
What You'll Build
By the end of this tutorial, you'll have built a feature-rich scanning app with:
- Real-time barcode scanning - Instant barcode detection and decoding with configurable feedback
- Gallery image scanning - Scan barcodes from existing photos in your device's gallery
- Configurable settings - Full control over scanner behavior, performance, and user experience
- Scan history tracking - Persistent storage of scan results with timestamps and images
- Multiple specialized scanning modes - Switch between different modes optimized for various use cases
- Export functionality - Share scan results via CSV or other formats
- Camera controls - Flash, zoom, and camera switching capabilities
Project Setup
Install dependencies with:
npm install
Then create a .env file and set your barKoder license key:
VITE_BARKODER_LICENSE_KEY=YOUR_BARKODER_LICENSE_KEY
The app reads this value in barkoderService.ts and registers barKoder using:
await Barkoder.registerWithLicenseKey({ licenseKey });
After configuring the key, build and sync the project:
npm run build
npm run cap:sync
Finally, open the native project:
npm run cap:android
# or
npm run cap:ios
Core Scanner Integration
The scanner service initializes barKoder with native view bounds and subscribes to result events. This keeps scanner setup tied to the actual visible view and allows result handling through a single event pipeline.
await Barkoder.initialize({ width, height, x, y });
await Barkoder.addListener('barkoderResultEvent', (payload) => { ... });
The useScannerLogic hook drives startup by ensuring native readiness, applying decoder configuration, applying mode-specific behavior, and then starting camera and scanning:
await Barkoder.startCamera();
await Barkoder.startScanning();
App Architecture (Quick Overview)
src/App.tsx defines routes, src/screens/ScannerScreen.tsx handles scanner UI and overlays, src/components/UnifiedSettings.tsx renders dynamic settings, src/constants/constants.ts defines mode IDs and home sections, and src/utils/scannerConfig.ts provides mode presets for settings and enabled types. This structure keeps scanner behavior in hooks and services while keeping screen components mostly UI-focused.
Handling Scan Results
Results arrive through barkoderResultEvent. The hook parses decoder results, pauses scanning in non-continuous modes, maps decoded values to app items, writes to history, and updates scanner UI state.
if (!settingsRef.current.continuousScanning && mode !== MODES.GALLERY) {
await Barkoder.pauseScanning();
setIsScanningPaused(true);
}
newItems.forEach((item) => {
void HistoryService.addScan(item);
});
Scanning Modes
Modes are defined in src/constants/constants.ts and include AnyScan, 1D, 2D, Continuous, MultiScan, VIN, DPM, DeBlur, DotCode, AR Mode, MRZ, and Gallery. The scannerConfig.ts module provides initial settings and enabled barcode types for each mode.
Example mode tuning
if (mode === MODES.VIN) {
await Barkoder.setEnableVINRestrictions({ value: true });
await Barkoder.setRegionOfInterest({ left: 0, top: 35, width: 100, height: 30 });
await Barkoder.setDecodingSpeed({ value: DecodingSpeed.slow });
await Barkoder.setBarkoderResolution({ value: BarkoderResolution.FHD });
} else if (mode === MODES.DPM) {
await Barkoder.setDatamatrixDpmModeEnabled({ enabled: true });
await Barkoder.setRegionOfInterest({ left: 40, top: 40, width: 20, height: 10 });
}
AR mode is configured through setARMode, setARLocationType, setARHeaderShowMode, setAROverlayRefresh, and setARDoubleTapToFreezeEnabled.
Gallery Image Scanning
Gallery scanning is implemented by selecting an image with the Capacitor Camera plugin (Photos source), initializing barKoder for image-scan context, sending base64 data to scanImage, mapping results, and navigating to details when a result is available.
const photo = await Camera.getPhoto({ source: CameraSource.Photos, resultType: CameraResultType.Base64 });
await Barkoder.scanImage({ base64: photo.base64String! });
The app also applies a fallback timer and gallery-specific result mapping to produce useful previews for decoded items.
Runtime Scanner Controls
The scanner screen supports flash through setFlashEnabled, zoom through setZoomFactor, and camera switching through setCamera, along with live settings changes for ROI, continuous behavior, thresholds, and AR options. Settings are persisted per mode through SettingsService and Capacitor Preferences.
History and Export
HistoryService stores scan history in Preferences and deduplicates by text + type, so repeated scans update count and timestamp while new scans are inserted at the top. CSV export is supported natively through Filesystem and Share, while web uses downloadable blob-based CSV generation.
Web vs Native Behavior
This app is intended for native Capacitor runtime. In plain web runtime, scanner preview is not active and a UI fallback message is shown. Platform detection is handled with:
Capacitor.getPlatform() !== 'web'
Performance Tuning Tips
Performance is best when ROI is used to reduce decode search area, continuous mode is enabled only for high-throughput flows, and continuousThreshold is tuned to reduce duplicate noise. Difficult scans or gallery scans benefit from higher quality decoding presets such as slow or rigorous, and throughput improves when unnecessary heavy result options are disabled.
Conclusion
This Capacitor implementation provides a complete Barkoder scanning architecture with native scanner integration from React, mode-aware configuration, real-time and gallery scanning, and persistent history/export workflows. For teams already building with Capacitor, this is a practical base for production scanner apps.
Resources
- Barkoder: https://barkoder.com/
- Trial license: https://barkoder.com/trial
- Documentation: https://barkoder.com/barcode-scanner-sdk/frameworks/capacitor
- Flutter app source: https://github.com/barKoderSDK/barkoder-net-maui-full-demo-app


