Skip to main content

Document Scanner | Web Document Scanner

Document Scanner UI

Configuration & Styling

To start the document scanner, we must first create a DocumentScannerConfiguration object, or simply a dictionary in vanilla javascript, as follows.

const config = {
containerId: containerId,

The only required property is the containerId, string, that should match the container where you want the document scanner to pop up.

DocumentScannerConfiguration inherits the base properties:

  • containerId – The id of the containing HTML element where the Document Scanner will be initialized. Required
  • videoConstraints – The desired video resolution. Optional, defaults to 3840x2160
  • mirrored - Whether the screen should be mirrored. Useful when using a user-facing camera. false by default
  • preferredCamera - Camera label or camera device id. If not available, a default camera is used as fallback
  • onError – Callback when something went wrong. Optional

The configuration object also accepts the following parameters (values displayed are defaults):

acceptedAngleScore: 75,
acceptedSizeScore: 75,
autoCaptureSensitivity: 0.66,
autoCaptureEnabled: true,
ignoreBadAspectRatio: true,
acceptedBrightnessThreshold: 0, // Ranges from 0 to 255. Only accept scans with an averageBrightness (see below) of x or higher.

Additionally, you can also use the configuration object for react-like styling. It accepts the following parameters for document outline, hint text label and capture button color (values displayed are defaults):

style: {
outline: {
polygon: {
strokeCapturing: "green",
strokeSearching: "yellow",
fillCapturing: "transparent",
fillSearching: "transparent",
strokeWidth: "2px"
label: {
position: "absolute",
top: "90%",
left: "50%",
transform: "translate(-50%, -50%)",
textAlign: "center",
backgroundColor: "rgba(0, 0, 0, 0.7)",
color: "white",
borderRadius: "0.25em",
padding: "0.5em",
fontFamily: "sans-serif",
fontSize: "1em"
path: {
stroke: "green";
strokeWidth: 4;
captureButton: {
color: "white"

Note that if you wish to do your styling in css, and not in a reactive design pattern, you are more than welcome to.

The defaults bundled with the SDK, that you are welcome to override, are as follows:

.scanbot-document-outline {
stroke: yellow !important;
stroke-width: 2px !important;
fill: none !important;

.scanbot-document-outline-ok {
stroke: green !important;

.scanbot-document-outline-visible {
opacity: 1 !important;
transition: opacity .3s ease-in-out !important;

.scanbot-document-outline-hidden {
opacity: 0 !important;
transition: opacity .3s ease-in-out !important;

.scanbot-document-outline-path {
stroke: green !important;
stroke-width: 4px !important;

.scanbot-document-hint-text {
position: absolute !important;
top: 90% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
text-align: center !important;
background-color: rgba(0, 0, 0, 0.7) !important;
color: white !important;
border-radius: 0.25em !important;
padding: 0.5em !important;
font-family: sans-serif !important;
font-size: 1em !important;

The capture/shutter button can be repositioned by overriding the following css class:

.scanbot-shutter-button {
/* ... */

Moreover, the hint texts can also be configured via the same configuration object (values displayed are defaults):

text: {
hint: {
OK: 'Capturing your document... Please do not move the camera.',
OK_SmallSize: 'The document is too small. Try moving closer.',
OK_BadAngles: 'This is a bad camera angle. Hold the device straight over the document.',
OK_BadAspectRatio: 'Rotate the device sideways, so that the document fits better into the screen.',
OK_OffCenter: 'Try holding the device at the center of the document.',
Error_NothingDetected: 'Please hold the device over a document to start scanning.',
Error_Brightness: 'It is too dark. Try turning on a light.',
Error_Noise: 'Please move the document to a clear surface.'

The document scanner works at the maximum available camera resolution for the highest quality scans by default. You can further configure the camera video stream by specifying the videoConstraints property of the document scanner configuration. Most video constraints are directly given to getUserMedia*

The default video constraints are as follows:

videoConstraints: MediaTrackConstraints = {
facingMode: "environment",
resizeMode: "none",
width: { ideal: 3840 },
height: { ideal: 2160 },
experimental: {
focusMode: "continous",
focusDistance: 0

*Everything except experimental is passed directly to getUserMedia, because they are advanced constraints they will not work on all browsers and thus require special application. All advanced constraints, however, are passed to the video stream in the same fashion. You can add additional advanced constraints.


To receive detection results define onDocumentDetected in the configuration:

onDocumentDetected: result => {
console.log("Detected Document:", result);

The result object contains the following properties:

  • detectionStatus – DetectionStatus, contains the same keys as the hint texts mentioned earlier
  • success – boolean, whether detection was successful or not
  • original – If success, contains the cropped document ArrayBuffer (UInt8Array)
  • cropped – If success, contains the cropped document ArrayBuffer (UInt8Array)
  • polygon – Polygon, The page's cropping polygon as calculated by a document detection operation
  • averageBrightness - Ranges from 0 to 255. Average brightness, calculated as the average of the Value channel in the HSV color space of:
    • the whole image, if no document was detected
    • the document crop, if a document was detected
enum DetectionStatus {
NotAcquired = 'NotAcquired',
OK = 'OK',
OK_SmallSize = 'OK_SmallSize',
OK_BadAngles = 'OK_BadAngles',
OK_BadAspectRatio ='OK_BadAspectRatio',
OK_OffCenter = 'OK_OffCenter',
Error_NothingDetected = 'Error_NothingDetected',
Error_Brightness = 'Error_Brightness',
Error_Noise = 'Error_Noise',
type Polygon = [Point, Point, Point, Point];

Note that this will be called every time a document is detected, until you stop detection or dispose of the camera.

Creating the Scanner

After you are done configuring the scanner, simply refer back to your SDK object and create the scanner object as follows:

documentScanner = await scanbotSDK.createDocumentScanner(config);

An exception is thrown if camera streaming is not supported or the user blocks the camera.

Handling Automatic Capture

There is the option to disable automatic capture on the fly (for example image processing between document captures). You can also use these calls to create your own custom auto-capture on/off switch.

Call to disable auto-capture:


And when processing is complete, or the switch is flicked, re-enable it with the following command:


To verify whether auto-capture is enabled or not, call:


Switching between the front and rear camera

swapCameraFacing(force?: boolean): void;

swapCameraFacing(true) indicates that only the swapped camera (e.g. front camera) is acceptable; if the swapped camera is not available, or the user declines the permission to use that camera, the media request will fail.


Firefox on Android: Due to current Firefox browser limitations, we highly recommend checking the running browser and disabling this feature for Firebox browsers.

Switching to a specific available camera

fetchAvailableCameras(): Promise<CameraInfo[]>;
switchCamera(deviceId: string, mirrored?: boolean): void;
getActiveCameraInfo(): CameraInfo | undefined;
interface CameraInfo {
deviceId: string;
label: string;
facingMode?: CameraFacingMode;
supportsTorchControl?: boolean;

type CameraFacingMode = 'front' | 'back' | 'unknown';

You can search for available cameras on the running browser by using fetchAvailableCameras method of a scanner. You can retrieve the label, device id and the camera facing mode information of the active camera of a scanner by using getActiveCameraInfo method. And, you can switch to another available camera by utilizing its device id, by using switchCamera method.

const cameras = await scanner.fetchAvailableCameras()
if (cameras) {
const currentCameraInfo = scanner.getActiveCameraInfo();
if (currentCameraInfo) {
const cameraIndex = cameras.findIndex((cameraInfo) => { return cameraInfo.deviceId == currentCameraInfo.deviceId });
const newCameraIndex = (cameraIndex + 1) % (cameras.length);


Controlling the torch (flashlight)

On some mobile devices, the browser can control the torch (flashlight). Check scanner.getActiveCameraInfo().supportsTorchControl to see if the browser can control the torch for the currently active camera. If true, you can control the torch by using the setTorchState method of the scanner.

setTorchState(state: boolean): Promise<void>;

On Android devices, only Chrome supports torch control. Starting with iOS 17.4, all supported browsers on iOS offer torch control functionality.


Always dispose of the document scanner after it is no longer needed

await documentScanner.dispose();

Want to scan longer than one minute?

Generate a free trial license to test the Scanbot SDK thoroughly.

Get your free Trial License

What do you think of this documentation?

On this page

Scroll to top