After scaffolding, open angular.json and ensure SSR and prerendering are explicitly disabled:
"options": {"prerender":false,"ssr":false}
Step 2: Install Plugin
Install the Accura IDScan Plugin package from the npm registry:
npminstallaccuraidscanplugin
Step 3: TypeScript Support
Angular enforces strict TypeScript compilation. Create a type declaration file at src/types.d.ts to declare the module and suppress resolution errors:
Ensure this file is included in your tsconfig.app.json's include array:
Step 4: Implementation
Generate the scanner component or create it manually at src/app/id-scanner/id-scanner.component.ts. The snippet below 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 typed payload object. This object 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/app/id-scanner/id-scanner.component.ts. The original logic is preserved exactly as-is.
Step 7: Usage
Register and render the component in app.component.ts:
import { Component, OnInit, OnDestroy } from '@angular/core';
export class IDScannerComponent implements OnInit, OnDestroy {
plugin: any = null;
async ngOnInit() {
// Dynamically import the plugin inside ngOnInit to ensure browser-only execution.
// Angular may invoke lifecycle hooks during SSR; dynamic import defers plugin
// loading to runtime, preventing access to unavailable browser APIs on the server.
const { default: IDCardPlugin } = await import('accuraidscanplugin');
// Instantiate the plugin with:
// 1. The capture callback: invoked when the scan session is complete
// 2. Configuration: specifies the target card, country, and UI styling options
this.plugin = new IDCardPlugin(
handleCapture, // Fired automatically upon successful ID card scan completion
{
countryCode: 'UGA', // Country code of the ID Card
cardCode: 'UGNIDF', // Card code of front ID Card
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)
}
);
// Activate the camera and commence the ID card detection session.
await this.plugin.start();
}
// Angular destruction hook — destroy the plugin to free camera resources on unmount.
ngOnDestroy() {
if (this.plugin) {
this.plugin.destroy();
}
}
}
// Utility: converts a base64 Data URL string into a binary Blob.
// Multipart form uploads require raw binary data, not text-encoded Base64 strings.
const base64ToBlob = (base64DataURL: string) => {
// Split at comma: 'data:image/jpeg;base64' | '/9j/4AAQSkZJRg...'
const [meta, content] = base64DataURL.split(',');
// Extract the MIME type from the header segment.
const match = meta.match(/:(.*?);/);
const mime = match ? match[1] : 'image/jpeg';
// Decode the base64-encoded payload into raw binary characters.
const binary = atob(content);
// Reconstruct original binary bytes as a typed Uint8Array.
const array = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
array[i] = binary.charCodeAt(i); // Map each character to its corresponding byte value
}
// Wrap the binary data in a Blob for server-compatible multipart submission.
return new Blob([array], { type: mime });
};
// Sends a scanned card image Blob to the server-side verification endpoint.
const sendToAPI = async (
blob: Blob,
isface: 'front' | 'back',
card_code: string,
filename: string,
) => {
const formData = new FormData();
formData.append('scan_image', blob, filename); // Binary image file
formData.append('isface', isface); // "front" or "back" — card side identifier
formData.append('country_code', 'UGA'); // ISO country code of the scanned ID
formData.append('card_code', card_code); // Card template identifier
formData.append('passport', 'false'); // Set "true" if the document is a passport
formData.append('webcam', 'false'); // Set "true" if captured via a webcam
try {
const response = await fetch('https://ip:port/doc_liveness.php', {
method: 'POST',
body: formData,
});
const data = await response.json();
console.log(`API Response (${isface}):`, data);
// Read the document authenticity/liveness score from the server response.
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 when plugin completes scan.
// Receives: base64 — object with optional front/back card image Data URLs.
const handleCapture = async (base64: { front?: string; back?: string }) => {
console.log('Capture result:', 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');
}
};
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-id-scanner',
standalone: true,
imports: [CommonModule],
template: ``,
styles: [``],
})
export class IDScannerComponent implements OnInit, OnDestroy {
ready = false;
plugin: any = null;
async ngOnInit() {
try {
const { default: IDCardPlugin } = await import('accuraidscanplugin');
interface CapturePayload {
front?: string;
back?: string;
}
const base64ToBlob = (base64DataURL: string) => {
const [meta, content] = base64DataURL.split(',');
const match = meta.match(/:(.*?);/);
const mime = match ? match[1] : 'image/jpeg';
const binary = atob(content);
const array = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
array[i] = binary.charCodeAt(i);
}
return new Blob([array], { type: mime });
};
// Function to send image to API and log score
const sendToAPI = async (
blob: Blob,
isface: 'front' | 'back',
card_code: string,
filename: string,
) => {
const formData = new FormData();
formData.append('scan_image', blob, filename); //Upload your image file
formData.append('isface', isface); //put card side either the card image is front or back
formData.append('country_code', 'UGA'); //put country_code of the card image
formData.append('card_code', card_code); //put card_code of the card image
formData.append('passport', 'false'); //if image is a passport put true else put false
formData.append('webcam', 'false'); //if image is captured from a webcam put true else if image is captured from a mobile put false
try {
const response = await fetch(
'https://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);
}
};
// Callback receives captured images with metadata
const handleCapture = async (base64: CapturePayload) => {
console.log('Capture result:', base64);
// Send front image
if (base64.front) {
const frontBlob = base64ToBlob(base64.front);
await sendToAPI(frontBlob, 'front', 'UGNIDF', 'front.jpg');
}
// Send back image if present
if (base64.back) {
const backBlob = base64ToBlob(base64.back);
await sendToAPI(backBlob, 'back', 'UGNIDB', 'back.jpg');
}
};
this.plugin = new IDCardPlugin(handleCapture, {
countryCode: 'UGA',
cardCode: 'UGNIDF',
topTextSize: '',
topTextColor: '',
topTextWeight: '',
bottomTextSize: '',
bottomTextColor: '',
bottomTextWeight: '',
});
await this.plugin.start();
this.ready = true;
} catch (err) {
console.error('Angular IDScan Init Error:', err);
}
}
ngOnDestroy() {
if (this.plugin) {
this.plugin.destroy();
}
}
}
import { Component } from '@angular/core';
import { IDScannerComponent } from './id-scanner/id-scanner.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [IDScannerComponent],
template: `<app-id-scanner></app-id-scanner>`
})
export class AppComponent {
title = 'angular-id';
}