Installation
This page describes how to integrate the Scandit Data Capture SDK into your web project. You can consume the Scandit Data Capture SDK Web packages in two ways:
- as an external resource from a CDN in HTML
- as package dependency via npm.
Scandit Data Capture SDKs npm packages are distributed under @scandit/ scope.
You need to add the @scandit/web-datacapture-core package, which contains the shared functionality used by the other data capture packages.
If you're using barcodecapture-related functionalities,
make sure to also add the:
@scandit/web-datacapture-barcodepackage, and/or@scandit/web-datacapture-parser
In addition, you need to add @scandit/web-datacapture-id if you want to scan personal identification documents, such as identity cards, passports or visas. See the ID Capture documentation to learn more.
You can safely remove barcode or id dependencies if you are not going to use their features.
Prerequisites
Before you begin, make sure you have the following prerequisites in place:
- The latest stable version of Node.js and npm (required only if including and building the SDK as part of an app, instead of just including it as an external resource from a CDN in HTML).
- Valid Scandit Data Capture SDK license, sign up for a free trial if you don't already have a license key
Devices running the Scandit Data Capture SDK need to have a GPU and run a browser capable of making it available (requires WebGL - current support? and OffscreenCanvas - current support?) or the performance will drastically decrease.
Install via CDN
CDNs offer a convenient way to get started but they introduce dependencies into your application. Your app's functionality becomes directly tied to the CDN's availability and performance. Any CDN outages or slowdowns will immediately affect your users' experience.
For production environments, we recommend:
-
Self-hosting the SDK files on your own infrastructure, where you are strongly encouraged to:
- Configure optimal cache headers and compression settings
- Set correct MIME types for .wasm, .js and .model files
- Control Content-Length headers for accurate loading progress
- Minimize request redirections and network latency
- Implement your own fallback mechanisms
-
If self-hosting isn't feasible, use a paid enterprise CDN service that provides:
- Guaranteed uptime and performance metrics
- Enterprise-grade support
You can use the jsDelivr or UNPKG CDN to specify a certain version (or range) and include and import from our library as follows. This example imports the core and barcode capture packages:
<!--
You can optionally preload the modules.
More info about this feature here https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload
-->
<link
rel="modulepreload"
href="https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-core@8.0.0/build/js/index.js"
/>
<link
rel="modulepreload"
href="https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-barcode@8.0.0/build/js/index.js"
/>
<!-- polyfill browsers not supporting import maps. use the latest version from here https://github.com/guybedford/es-module-shims/releases -->
<script
async
src="https://ga.jspm.io/npm:es-module-shims@2.6.2/dist/es-module-shims.js"
></script>
<script type="importmap">
{
"imports": {
"@scandit/web-datacapture-core": "https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-core@8.0.0/build/js/index.js",
"@scandit/web-datacapture-barcode": "https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-barcode@8.0.0/build/js/index.js",
"@scandit/web-datacapture-barcode/": "https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-barcode@8.0.0/",
"@scandit/web-datacapture-core/": "https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-core@8.0.0/"
}
}
</script>
<script type="module">
// Importing only the necessary items is recommended
import {
DataCaptureContext,
Camera,
} from "@scandit/web-datacapture-core";
import {
BarcodeCapture,
barcodeCaptureLoader,
} from "@scandit/web-datacapture-barcode";
// Insert your code here
</script>
OR
<script type="module">
// OR import everything. Not recommended.
import * as SDCCore from "@scandit/web-datacapture-core";
import * as SDCBarcode from "@scandit/web-datacapture-barcode";
// Insert your code here
</script>
In alternative to jsdeliver unpkg can be used as alternative:
Alternatively, you can also put the same JavaScript/TypeScript code in a separate file via:
<script type="module" src="script.js"></script>
Complete Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Scandit CDN Simple sample</title>
<script type="importmap">
{
"imports": {
"@scandit/web-datacapture-core": "https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-core@8.0.0/build/js/index.js",
"@scandit/web-datacapture-barcode": "https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-barcode@8.0.0/build/js/index.js",
"@scandit/web-datacapture-barcode/": "https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-barcode@8.0.0/",
"@scandit/web-datacapture-core/": "https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-core@8.0.0/"
}
}
</script>
<link
rel="modulepreload"
href="https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-core@8.0.0/build/js/index.js"
/>
<link
rel="modulepreload"
href="https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-barcode@8.0.0/build/js/index.js"
/>
<style>
html,
body {
margin: 0;
padding: 0;
height: 100%;
}
#app {
height: 100%;
}
</style>
<!-- Check the latest version here https://github.com/guybedford/es-module-shims/releases -->
<script
async
src="https://ga.jspm.io/npm:es-module-shims@2.6.2/dist/es-module-shims.js"
></script>
<script type="module">
import {
DataCaptureView,
Camera,
DataCaptureContext,
FrameSourceState,
} from "@scandit/web-datacapture-core";
import {
barcodeCaptureLoader,
BarcodeCaptureSettings,
BarcodeCapture,
Symbology,
} from "@scandit/web-datacapture-barcode";
let view = new DataCaptureView();
view.connectToElement(document.getElementById("app"));
view.showProgressBar();
const context = await DataCaptureContext.forLicenseKey("-- ENTER LICENSE KEY HERE --", {
libraryLocation:
"https://cdn.jsdelivr.net/npm/@scandit/web-datacapture-barcode@8.0.0/sdc-lib/",
moduleLoaders: [barcodeCaptureLoader()],
});
view.hideProgressBar();
const camera = Camera.pickBestGuess();
await view.setContext(context);
// Depending on the use case further camera settings adjustments can be made here.
const cameraSettings = BarcodeCapture.recommendedCameraSettings;
await camera.applySettings(cameraSettings);
await context.setFrameSource(camera);
await context.frameSource.switchToDesiredState(FrameSourceState.On);
const settings = new BarcodeCaptureSettings();
settings.enableSymbologies([Symbology.Code128, Symbology.QR]);
let barcodeCapture = await BarcodeCapture.forContext(context, settings);
barcodeCapture.addListener({
didScan: async (barcodeCaptureMode, session) => {
const barcode = session.newlyRecognizedBarcode;
if (!barcode) {
return;
}
const symbology = new SymbologyDescription(barcode.symbology);
alert(`Scanned: ${barcode.data ?? ""}\n(${symbology.readableName})`);
},
});
await barcodeCapture.setEnabled(true);
</script>
</head>
<body>
<div id="app"></div>
</body>
</html>
Install via package manager
To add the packages via your preferred package manager, run the following command from your project's root folder:
- npm
- yarn
- pnpm
- bun
- deno
npm install --save @scandit/web-datacapture-core @scandit/web-datacapture-barcode
yarn add @scandit/web-datacapture-core @scandit/web-datacapture-barcode
pnpm add @scandit/web-datacapture-core @scandit/web-datacapture-barcode
bun add @scandit/web-datacapture-core @scandit/web-datacapture-barcode
deno add npm:@scandit/web-datacapture-core npm:@scandit/web-datacapture-barcode
You can also specify a version @<version>.
Then import the package in your JavaScript/TypeScript code by using:
// Importing only the necessary items is recommended
import {
DataCaptureContext,
Camera,
} from "@scandit/web-datacapture-core";
import {
BarcodeCapture,
barcodeCaptureLoader,
} from "@scandit/web-datacapture-barcode";
// Insert your code here
OR
// Import everything
import * as SDCCore from "@scandit/web-datacapture-core";
import * as SDCBarcode from "@scandit/web-datacapture-barcode";
// Insert your code here
Configure the Library
The library needs to be configured and initialized before it can be used, this is done via the DataCaptureContext forLicenseKey function.
Note that the configuration expects a valid license key as first argument.
We recommend calling forLicenseKey as soon as possible in your application so that the files can be downloaded and the DataCaptureContext initialized before the capture process starts.
The LibraryLocation configuration option must be provided and point to the location of the Scandit Data Capture sdc-lib location (external WebAssembly files): scandit-datacapture-sdk\*.js and scandit-datacapture-sdk\*.wasm.
WebAssembly requires these separate files which are loaded by our main library at runtime.
They can be found inside the sdc-lib folder you either added and installed via npm or access via a CDN.
If you installed the library through npm, these files should be copied and served correctly in a path that will be accessible by the SDK during initialization.
The configuration option that you provide should then point to the folder containing these files, either as a path of your website or an absolute URL (like the CDN one). By default the library will look at the root of your website.
The npm package version and the sdc-lib files must be from the exact same SDK version. For example, if you have @scandit/web-datacapture-barcode@8.0.0 in your package.json, you must serve the sdc-lib folder from node_modules/@scandit/web-datacapture-barcode@8.0.0/sdc-lib/. Mismatched versions will cause runtime errors and unexpected behavior.
In case a common CDN is used (jsDelivr or UNPKG) the library will automatically, internally set up the correct URLs pointing to the files needed for the matching library version. It is highly recommended to handle the serving of these files yourself on your website/server, ensuring optimal compression, correct WASM files MIME type, no request redirections, and correct caching headers usage. This will aid in faster loading.
Hosting the sdc-lib files
We recommend serving the sdc-lib folder yourself.
You must copy the entire sdc-lib folder recursively from the installed Scandit package to your server. This includes all subdirectories and files. The sdc-lib folder must come from a package version that exactly matches your npm package version. For example, if you have @scandit/web-datacapture-barcode@8.0.0, you must copy the sdc-lib from node_modules/@scandit/web-datacapture-barcode@8.0.0/sdc-lib/.
Additionally, you should copy sdc-lib from all installed Scandit packages (@scandit/web-datacapture-core, @scandit/web-datacapture-barcode, @scandit/web-datacapture-id, etc.) to the same location.
Once copied, be sure to serve the files correctly by setting up the correct MIME type for the .wasm, .model, and .js files. Some common examples are provided below:
- ASP.NET Core
- Apache
- Nginx
- Express.js
- Python Flask
app.UseStaticFiles(new StaticFileOptions()
{
ServeUnknownFileTypes = true,
DefaultContentType = "application/octet-stream"
});
Or
var provider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
provider.Mappings[".model"] = "application/octet-stream";
provider.Mappings[".js"] = "application/javascript";
provider.Mappings[".wasm"] = "application/wasm";
Add these MIME types to your .htaccess file or Apache configuration:
AddType application/wasm .wasm
AddType application/octet-stream .model
AddType application/javascript .js
Add these MIME types to your Nginx configuration file:
types {
application/wasm wasm;
application/octet-stream model;
application/javascript js;
}
For Express.js, you can configure the MIME types like this:
const express = require("express");
const app = express();
express.static.mime.define({ "application/wasm": ["wasm"] });
express.static.mime.define({ "application/octet-stream": ["model"] });
express.static.mime.define({ "application/javascript": ["js"] });
app.use(express.static("self-hosted-sdc-lib")); // Serve static files from 'public' directory
For Flask, you can set the MIME types when serving the files:
from flask import Flask, send_file
app = Flask(__name__)
@app.route('/self-hosted-sdc-lib/<path:filename>')
def serve_file(filename):
mimetype = None
if filename.endswith('.wasm'):
mimetype = 'application/wasm'
elif filename.endswith('.model'):
mimetype = 'application/octet-stream'
elif filename.endswith('.js'):
mimetype = 'application/javascript'
return send_file(
f'/self-hosted-sdc-lib/{filename}',
mimetype=mimetype
)
Show loading status with default UI
It could take a while the very first time to download the .wasm files. To show some feedback to the user about the loading status you have two options:
- use the default UI provided with the SDK
- subscribe to the loading status and update your own custom UI.
Let's see how to do it with the default UI first:
import {
DataCaptureView,
DataCaptureContext,
} from "@scandit/web-datacapture-core";
const view = new DataCaptureView();
view.connectToElement(document.getElementById("data-capture-view"));
view.showProgressBar();
view.setProgressBarMessage("Loading ...");
const context = await DataCaptureContext.forLicenseKey("-- ENTER LICENSE KEY HERE --", {
libraryLocation: "/self-hosted-sdc-lib/",
moduleLoaders: [idCaptureLoader({ enableVIZDocuments: true })],
});
view.hideProgressBar();
await view.setContext(context);
Show loading status with custom UI
You can also subscribe for the loading status of the library by simply attaching a listener like this:
import { loadingStatus, DataCaptureContext } from "@scandit/web-datacapture-core";
loadingStatus.subscribe((info) => {
// updateUI(info.percentage, info.loadedBytes)
});
const context = await DataCaptureContext.forLicenseKey("SCANDIT_LICENSE_KEY", {
libraryLocation: "/self-hosted-sdc-lib/",
moduleLoaders: [barcodeCaptureLoader()],
});
The library files should be served with the proper header Content-Length. Content-Encoding should also be set if any compression is used.
In case of missing information, the progress bar tries to show an estimated value, but can also not report progress at all for a while.
Additional Information
Server Side Rendering and Server Side Generation
If you use a web framework that also renders on the server (SSR or SSG) it's recommended to execute the library only on the client turning off the rendering on the server.
For more information:
Camera Permissions
When using the Scandit Data Capture SDK you will likely want to set the camera as the frame source for various capture modes. The camera permissions are handled by the browser, and can only be granted if a secure context is used and have been accepted by the user explicitly.
Progressive Web App (PWA)
You can configure the scanner to work offline making the web app progressive (Progressive Web App). There are some settings to consider. If you use Workbox, a tool that uses workbox under the hood like Vite PWA plugin, you must also set these options:
workbox: {
globPatterns: ["**/*.{css,html,ico,png,svg,woff2}", "**/*.{wasm,js}"],
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, // up to 10mb because of wasm files
// Don't ignore version parameters - let each version have its own cache entry
runtimeCaching: [
{
urlPattern: /^.*\.wasm(\?.*)?$/,
handler: "NetworkFirst",
options: {
cacheName: "wasm-version-cache",
expiration: {
maxEntries: 2, // Keep only 2 versions to manage storage
maxAgeSeconds: 60 * 60 * 24 * 30, // 30 days
},
// This ensures the version parameter is part of the cache key
matchOptions: {
ignoreSearch: false, // Don't ignore search parameters (like ?v=) as part of the cache key
},
networkTimeoutSeconds: 5, // Fallback to cache if network is slow
},
},
{
// Cache all other assets with NetworkFirst for example
urlPattern: /^.*\.(js|css|html|png|jpg|jpeg|svg|ico|woff2)(\?.*)?$/,
handler: "NetworkFirst",
options: {
cacheName: "app-assets-cache",
expiration: {
maxEntries: 100,
maxAgeSeconds: 60 * 60 * 24 * 7, // 7 days
},
networkTimeoutSeconds: 3, // Fallback to cache if network is slow
},
},
],
cleanupOutdatedCaches: true,
// Skip waiting to activate new service worker immediately
skipWaiting: true,
clientsClaim: true,
},
With these settings in place and the service worker correctly configured, you will be able to have a full offline scanning experience.
On iOS there's an issue while accessing the video stream inside a progressive web app. The issue is flaky and gets reopened periodically. Check the webkit tracker if you experience similar issues.
Electron
You can configure the Scandit SDK to work in an Electron app. The register method must be called inside the main.ts file passing down some dependencies and the publicKey. The publicKey will be used to decrypt the encrypted license key file that must be placed into the ConfigureOptions.licenseDataPath option:
// electron main.ts
import { register, unregister } from '@scandit/web-datacapture-core/build/electron/main';
import { app, BrowserWindow, ipcMain } from 'electron';
import fs from 'node:fs/promises';
import crypto from 'node:crypto';
import path from 'node:path';
const mainWindow = new BrowserWindow({
...,
});
register({ fs, ipcMain, app, path, crypto }, publicKey);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
unregister()
}
});
// preload.ts
import { ipcRenderer } from "electron";
import { preloadBindings } from "@scandit/web-datacapture-core/build/electron/preload";
preloadBindings(ipcRenderer);
// renderer.ts
import { DataCaptureContext } from "@scandit/web-datacapture-core";
import { barcodeCaptureLoader } from "@scandit/web-datacapture-barcode";
const context = await DataCaptureContext.forLicenseKeyInElectronPath("./out/renderer/data/sdc-license.data", {
// In Electron context the license will be decrypted internally.
// The path of the encrypted file is path.join(app.getAppPath(), licenseDataPath)
libraryLocation: new URL("self-hosted-sdc-lib", document.baseURI).toString(),
moduleLoaders: [barcodeCaptureLoader()],
});
You can encrypt your license key with this small Node.js script. Then you should copy the sdc-license.data file in the licenseDataPath in order to be correctly read at runtime during initialization.
You can also check the related sample.
const crypto = require("node:crypto");
const fs = require("node:fs/promises");
(async function createLicenseAndPublicKey() {
const data = process.env.SDC_LICENSE_KEY;
if (data == null || data === "") {
throw new Error("could not encrypt empty or null string");
}
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
const keyAndIV = `${key.toString("base64")}:${iv.toString("base64")}`;
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
let encryptedText = cipher.update(text, "utf8", "hex");
encryptedText += cipher.final("hex");
await fs.writeFile("sdc-license.data", Buffer.from(encryptedText), "utf8");
// Save the key to a file
await fs.writeFile("sdc-public-key", keyAndIV, "utf8");
})();
It is recommended to NOT store the public key locally. We also recommend you enable source code protection with bytenode.
Third-party Licenses
The Scandit Data Capture SDK relies on several third-party, open-source software libraries. Your application must display the license information for these libraries in many cases.
The Scandit SDK provides a convenient API that you can use to fetch the corresponding text and attributions for all third-party software:
DataCaptureContext.getOpenSourceSoftwareLicenseInfo()