Install the Accura IDScan Plugin package from the npm registry:
npminstallaccuraidscanplugin
Step 3: TypeScript Support (Recommended)
If your project uses TypeScript, create a type declaration file at src/types.d.ts to suppress module resolution warnings:
declaremodule'accuraidscanplugin';
Step 4: Implementation
Create a dedicated component file src/IDScanner.jsx (or .tsx). The following snippet shows only the plugin import and instantiation logic:
Step 5: Response Handling
When the plugin completes an ID card scan, it invokes the handleCapture callback with a payload object that may contain one or both of the following properties:
Property
Type
Description
front
string
Base64 Data URL of the front side of the ID card
back
string
Base64 Data URL of the back side of the ID card (if applicable)
What is Base64? Base64 is a binary-to-text encoding scheme that converts raw binary image data into a sequence of printable ASCII characters. Each scanned card image is delivered as a Data URL string (e.g., data:image/jpeg;base64,/9j/...), combining a MIME type prefix with the encoded image payload. Before transmitting to a server, this string must be decoded back into binary form (a Blob) to construct a valid multipart HTTP request.
The following demonstrates the base64-to-Blob conversion and API submission:
Step 6: Demo Implementation
The following is the complete, production-ready component. Copy and paste it directly into src/IDScanner.jsx. The original logic is preserved exactly as-is.
Step 7: Usage
Import and render the component in App.jsx:
Note: Remove the <StrictMode> wrapper from main.jsx or main.tsx if present, as React Strict Mode invokes lifecycle hooks twice in development, which can cause duplicate plugin initialization.
import { useEffect, useRef } from 'react';
const IDScanner = () => {
const pluginRef = useRef(null); // Holds the active plugin instance across renders
const initialized = useRef(false); // Guards against double-initialization in Strict Mode
useEffect(() => {
// Prevent re-initialization caused by React Strict Mode's double-invocation behavior
if (initialized.current) return;
initialized.current = true;
// Dynamically import the plugin to ensure it runs only in the browser context.
// This prevents errors in SSR environments and improves initial bundle performance.
import("accuraidscanplugin").then((Module) => {
const IDCardPlugin = Module.default;
// Instantiate the IDCardPlugin with:
// 1. The capture callback invoked on successful ID scan completion
// 2. A configuration object specifying the target card and UI appearance
pluginRef.current = new IDCardPlugin(
handleCapture, // Fired automatically when the scan is complete
{
countryCode: "UGA", // country code of the card
cardCode: "UGNIDF", // Card code for the front-side ID
topTextSize: "", // Top overlay text size (default if empty)
topTextColor: "", // Top overlay text color (default if empty)
topTextWeight: "", // Top overlay font weight (default if empty)
bottomTextSize: "", // Bottom overlay text size (default if empty)
bottomTextColor: "", // Bottom overlay text color (default if empty)
bottomTextWeight: "", // Bottom overlay font weight (default if empty)
}
);
// Initialize the camera and begin the ID card detection session.
pluginRef.current.start().then(() => {
console.log("ID Scanner Engine Ready");
});
});
// Cleanup: destroy the plugin instance when the component unmounts
return () => {
if (pluginRef.current) {
pluginRef.current.destroy();
pluginRef.current = null;
}
};
}, []);
return <></>;
};
// Utility: converts a base64 Data URL string into a binary Blob.
// MultiPart form uploads require raw binary data rather than base64-encoded text.
const base64ToBlob = (base64DataURL) => {
// Split at the comma: left = MIME header, right = encoded payload
const [meta, content] = base64DataURL.split(",");
// Extract the MIME type (e.g., "image/jpeg") from the header
const mimeMatch = meta.match(/:(.*?);/);
const mime = mimeMatch ? mimeMatch[1] : "image/jpeg";
// Decode the base64 payload back into raw binary characters
const binary = atob(content);
// Re-construct binary data as a typed array of unsigned 8-bit integers
const array = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
array[i] = binary.charCodeAt(i); // Convert each character to its byte value
}
// Wrap the binary array in a Blob with the correct MIME type
return new Blob([array], { type: mime });
};
// Sends a card image Blob to the server-side verification endpoint.
const sendToAPI = async (blob, isface, card_code, filename) => {
const formData = new FormData();
formData.append("scan_image", blob, filename); // The binary image file
formData.append("isface", isface); // "front" or "back"
formData.append("country_code", "UGA"); // ISO country code
formData.append("card_code", card_code); // Card template identifier
formData.append("passport", "false"); // "true" for passport documents
formData.append("webcam", "false"); // "true" if captured via webcam
try {
const response = await fetch("http://ip:port/doc_liveness.php", {
method: "POST",
body: formData,
});
const data = await response.json();
console.log(`API Response (${isface}):`, data);
if (data && data.score !== undefined) {
console.log(`Score (${isface}): ${data.score}`);
}
} catch (error) {
console.error(`Error sending ${isface} to API:`, error);
}
};
// Primary capture callback — invoked by the plugin when scanning is complete.
const handleCapture = async (base64) => {
if (base64.front) {
const frontBlob = base64ToBlob(base64.front);
await sendToAPI(frontBlob, "front", "UGNIDF", "front.jpg");
}
if (base64.back) {
const backBlob = base64ToBlob(base64.back);
await sendToAPI(backBlob, "back", "UGNIDB", "back.jpg");
}
};