> 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
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.accurascan.com/language/web-plugin/id-plugin/angular.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
