> For the complete documentation index, see [llms.txt](https://docs.accurascan.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.accurascan.com/language/web-plugin/id-plugin/angular.md).

# Angular

## Accura IDScan Plugin — Angular Integration Guide

This guide walks you through integrating the **Accura IDScan Plugin** into an Angular project using standalone components.

### Step 1: Initialize Project

Create a new Angular project with standalone component architecture. When prompted, select **No** for Server-Side Rendering (SSR):

```bash
npx ng new my-id-app --standalone
cd my-id-app
npm install
```

After scaffolding, open `angular.json` and ensure SSR and prerendering are explicitly disabled:

```json
"options": {
  "prerender": false,
  "ssr": false
}
```

***

### Step 2: Install Plugin

Install the Accura IDScan Plugin package from the npm registry:

```bash
npm install accuraidscanplugin
```

***

### 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:

```typescript
declare module 'accuraidscanplugin';
```

Ensure this file is included in your `tsconfig.app.json`'s `include` array:

```json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": [
      "node"
    ]
  },
  "files": [
    "src/main.ts",
    "src/main.server.ts",
    "server.ts"
  ],
  "include": [
    "src/**/*.d.ts"
  ]
}
```

***

### 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:

```typescript
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();
    }
  }
}
```

***

### 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:

```typescript
// 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');
  }
};
```

***

### 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.

```typescript
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();
    }
  }
}
```

***

### Step 7: Usage

Register and render the component in `app.component.ts`:

```typescript
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';
}
```

***

### Step 8: Running the Project

```bash
npm start
```
