Skip to main content

Advanced Configurations

Customize the Overlay Appearance

To customize the appearance of the overlay, you can implement a LabelCaptureBasicOverlayListener.

The method brushForLabel() is called every time a label captured and brushForFieldOfLabel() is called for each of its fields to determine the brush for the label or field.

import { useMemo, useEffect, useRef } from 'react';
import { Brush, Color } from 'scandit-react-native-datacapture-core';
import {
LabelCaptureBasicOverlay,
LabelCaptureBasicOverlayListener,
} from 'scandit-react-native-datacapture-label';

// Create the overlay for the label capture mode.
const basicOverlay = useMemo(() => {
return new LabelCaptureBasicOverlay(labelCapture);
}, [labelCapture]);

// Create a listener to customize the appearance of captured labels and fields.
const overlayListener = useMemo<LabelCaptureBasicOverlayListener>(() => ({
/**
* Called for each field of a captured label to determine its brush.
* Return a Brush to customize the field's appearance, or null to use the default.
*/
brushForFieldOfLabel: (overlay, field, label) => {
// Create colors with transparency (alpha 0.5 = 50% opacity).
const cyanColor = Color.fromRGBA(0, 255, 255, 0.5);
const orangeColor = Color.fromRGBA(255, 165, 0, 0.5);

switch (field.name) {
case "Barcode":
// Highlight barcode fields with a cyan color.
return new Brush(cyanColor, cyanColor, 0);
case "Expiry Date":
// Highlight expiry date fields with an orange color.
return new Brush(orangeColor, orangeColor, 0);
default:
// Use a transparent brush for other fields.
return Brush.transparent;
}
},
/**
* Called for each captured label to determine its brush.
* Return a Brush to customize the label's appearance, or null to use the default.
*/
brushForLabel: (overlay, label) => {
// Use a transparent brush for the label itself.
return Brush.transparent;
},
/**
* Called when the user taps on a label.
*/
didTapLabel: (overlay, label) => {
// Handle user tap gestures on the label.
}
}), []);

// Set up the overlay with the listener and add it to the view.
useEffect(() => {
// Assign the listener to the overlay.
basicOverlay.listener = overlayListener;

// Add the overlay to the data capture view.
dataCaptureViewRef.current?.addOverlay(basicOverlay);

return () => {
// Clean up: remove the listener and overlay.
basicOverlay.listener = null;
dataCaptureViewRef.current?.removeOverlay(basicOverlay);
};
}, [basicOverlay, overlayListener]);
tip

Use brush colors with transparency (alpha < 100%) to not occlude the captured barcodes or texts.

Advanced Overlay

For more advanced use cases, such as adding custom views or implementing Augmented Reality (AR) features, you can use the LabelCaptureAdvancedOverlay. The example below creates an advanced overlay, configuring it to display a styled warning message below expiry date fields when they're close to expiring, while ignoring other fields.

import React, { useMemo } from 'react';
import { View, Text, StyleSheet } from 'react-native';

// Create an advanced overlay that allows for custom views to be added over detected label fields
// This is the key component for implementing Augmented Reality features
const advancedOverlay = useMemo(() => {
return new LabelCaptureAdvancedOverlay(labelCapture, dataCaptureView);
}, [labelCapture, dataCaptureView]);

// Configure the advanced overlay with a listener that handles AR content creation and positioning
const advancedOverlayListener = useMemo(() => ({
// This method is called when a label is detected - we return null since we're only adding AR elements to specific fields, not the entire label
viewForCapturedLabel: (overlay, capturedLabel) => {
return null;
},

// This defines where on the detected label the AR view would be anchored
anchorForCapturedLabel: (overlay, capturedLabel) => {
return Anchor.Center;
},

// This defines the offset from the anchor point for the label's AR view
offsetForCapturedLabel: (overlay, capturedLabel, view) => {
return new PointWithUnit(0, 0, MeasureUnit.Pixel);
},

// This method is called when a field is detected in a label
viewForCapturedLabelField: (overlay, labelField) => {
// We only want to create AR elements for expiry date fields that are text-based
if (labelField.name.toLowerCase().includes("expiry") && labelField.type === LabelFieldType.Text) {

// Check if scanned expiry date is too close to actual date
const daysUntilExpiry = daysUntilExpiryFunction(labelField.text); // Your method
const dayLimit = 3;

if (daysUntilExpiry < dayLimit) {
// Create and configure the AR element - a React Native View with appropriate styling
// This view will appear as an overlay on the camera feed
return (
<View style={styles.warningContainer}>
<Text style={styles.warningText}>Item expires soon!</Text>
</View>
);
}
}
// Return null for any fields that aren't expiry dates, which means no AR overlay
return null;
},

// This defines where on the detected field the AR view should be anchored
// BottomCenter places it right below the expiry date text for better visibility
anchorForCapturedLabelField: (overlay, labelField) => {
return Anchor.BottomCenter;
},

// This defines the offset from the anchor point
offsetForCapturedLabelField: (overlay, labelField, view) => {
return new PointWithUnit(0, 22, MeasureUnit.Dip);
}
}), []);

const styles = StyleSheet.create({
warningContainer: {
backgroundColor: 'red',
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 8,
flexDirection: 'row',
alignItems: 'center',
},
warningText: {
color: 'white',
fontWeight: 'bold',
fontSize: 14,
},
});

useEffect(() => {
// Assign the overlay listener to the overlay
advancedOverlay.listener = advancedOverlayListener;

return () => {
// Clean up
advancedOverlay.listener = null;
};
}, [advancedOverlay, advancedOverlayListener]);

Validation Flow

How It Works

The Validation Flow provides a guided label scanning experience. An always-present checklist shows users exactly which fields have been captured and which are still missing, making the scanning process transparent and efficient. Scanning is the fastest way to capture all label content — whether all fields are visible at once or spread across different sides of a package.

The fields shown in the checklist are driven by your Label Definition — the configuration that tells Label Capture which fields to recognize and extract. See the Label Definitions guide for details on how to set them up.

The Validation Flow overlay is a UI component built on top of Label Capture. To use it, create a LabelCaptureValidationFlowOverlay and add it to your data capture view.

Single-Step ScanMulti-Step Scan
All fields are visible togetherFields on different sides of the package
Single-step scan capturing all fields at onceMulti-step scan capturing fields from different sides
import React, { useMemo } from 'react';

const validationFlowOverlay = useMemo(() => {
return new LabelCaptureValidationFlowOverlay(labelCapture, dataCaptureView);
}, [labelCapture, dataCaptureView]);

// Set the listener to receive validation events
useEffect(() => {
validationFlowOverlay.listener = validationFlowListener;

return () => {
validationFlowOverlay.listener = null;
};
}, [validationFlowOverlay, validationFlowListener]);

Define a Listener

When the user has verified that all fields are correctly captured and presses the finish button, the Validation Flow triggers a callback with the final results. To receive these results, implement the LabelCaptureValidationFlowOverlayListener interface:

const validationFlowListener = useMemo(() => ({
// This is called by the validation flow overlay when a label has been fully captured and validated
onValidationFlowLabelCaptured: (fields) => {
let barcodeData = null;
let expiryDate = null;

fields.forEach(field => {
if (field.name === "<your-barcode-field-name>") {
barcodeData = field.barcode?.data;
} else if (field.name === "<your-expiry-date-field-name>") {
expiryDate = field.text;
}
});

// Handle the captured values
}
}), []);

Required and Optional Fields

The Validation Flow clearly indicates which fields must be captured and which are optional. Required fields are visually highlighted and the flow can only be completed once all of them have been successfully scanned or manually entered. Optional fields are shown but do not block the user from finishing.

Required FieldOptional Field
Must be captured to finish the flowDoes not block finishing
Required fields must be captured to finishOptional fields do not block finishing

Typing Hints

If neither on-device nor cloud-based scanning can capture a field, the user can always manually enter the value. To make manual input easier and reduce errors, you can configure placeholder text (typing hints) that show the expected format directly in the input field.

Typing hints showing expected input format

The field name in the label definition is used as the reference for setting placeholder text:

const validationFlowOverlaySettings = useMemo(() => {
const settings = new LabelCaptureValidationFlowSettings();
settings.setPlaceholderTextForLabelDefinition("Expiry Date", "MM/DD/YYYY");
return settings;
}, []);

useEffect(() => {
validationFlowOverlay.applySettings(validationFlowOverlaySettings);
}, [validationFlowOverlay, validationFlowOverlaySettings]);

Customization

All text in the Validation Flow overlay can be adjusted to match your application's needs. This is useful for localization, adapting terminology, or removing text entirely for a minimal interface.

Buttons

The text on the restart, pause, and finish buttons can be customized or removed entirely.

English (Default)Custom LanguageCompany SlangNo Text
Button text in EnglishButton text in SpanishButton text in FrenchButtons with no text
const validationFlowOverlaySettings = useMemo(() => {
const settings = new LabelCaptureValidationFlowSettings();
settings.restartButtonText = "Borrar todo";
settings.pauseButtonText = "Pausar";
settings.finishButtonText = "Finalizar";

return settings;
}, []);

useEffect(() => {
validationFlowOverlay.applySettings(validationFlowOverlaySettings);
}, [validationFlowOverlay, validationFlowOverlaySettings]);

Toasts

Toast messages appear at the top of the camera preview to inform the user about a scanning state change. The standby toast is shown when the camera is auto-paused after no label is detected for a long time. The validation toast shows how many fields have been captured so far after a scan.

StandbyValidation
Standby toast shown when no label is detectedValidation toast showing captured field count
import React, { useMemo } from 'react';

const validationFlowOverlaySettings = useMemo(() => {
const settings = new LabelCaptureValidationFlowSettings();
settings.standbyHintText = "No label detected, camera paused";
settings.validationHintText = "data fields collected"; // X/Y (X fields out of total Y) is shown in front of this string

return settings;
}, []);

useEffect(() => {
validationFlowOverlay.applySettings(validationFlowOverlaySettings);
}, [validationFlowOverlay, validationFlowOverlaySettings]);

Field

The field state texts are shown inside the input field itself during different phases of scanning.

Invalid InputScanning TextAdaptive Scanning Text
Shown when manual input does not match the expected formatShown while the camera is actively scanningShown while cloud-based recognition is processing
Invalid input state showing error stylingScanning text shown while camera is activeAdaptive scanning text shown during cloud processing
const validationFlowOverlaySettings = useMemo(() => {
const settings = new LabelCaptureValidationFlowSettings();
settings.validationErrorText = "Incorrect format.";
settings.scanningText = "Scan in progress";
settings.adaptiveScanningText = "Processing";

return settings;
}, []);

useEffect(() => {
validationFlowOverlay.applySettings(validationFlowOverlaySettings);
}, [validationFlowOverlay, validationFlowOverlaySettings]);

Cloud Fallback

Beta

The Adaptive Recognition API is still in beta and may change in future versions of Scandit Data Capture SDK. To enable it on your subscription, please contact support@scandit.com.

The Adaptive Recognition Engine helps making Smart Label Capture more robust and scalable thanks to its larger, more capable model hosted in the cloud. Whenever Smart Label Capture's on-device model fails to capture data, the SDK will automatically trigger the Adaptive Recognition Engine to capture complex, unforeseen data and process it with high accuracy and reliability — avoiding the need for the user to type data manually.

Cloud fallback using Adaptive Recognition

Enable Adaptive Recognition by setting the mode to .auto on the label definition. This is a single extra line added to your existing label definition configuration:

const customBarcode = CustomBarcode.initWithNameAndSymbologies('Barcode', [
Symbology.EAN13UPCA,
Symbology.GS1DatabarExpanded,
Symbology.Code128,
]);
customBarcode.optional = false;

const expiryDateText = new ExpiryDateText('Expiry Date');
expiryDateText.labelDateFormat = new LabelDateFormat(LabelDateComponentFormat.MDY, false);
expiryDateText.optional = false;

const label = new LabelDefinition('Retail Item');
label.fields = [customBarcode, expiryDateText];
label.adaptiveRecognitionMode = AdaptiveRecognitionMode.Auto;

const settings = LabelCaptureSettings.settingsFromLabelDefinitions([label], {});

See AdaptiveRecognitionMode for available options.