> 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/html-vanilla-js.md).

# HTML - Vanilla JS

## Accura IDScan Plugin — Vanilla HTML Integration Guide

This guide walks you through integrating the **Accura IDScan Plugin** into a standard HTML project using native ES Modules.

### Step 1: Implementation

Create an `index.html` file in your project directory and add the following **import and initialization code** inside a `<script type="module">` block.

```html
<script type="module">
  // Import the IDCardPlugin class directly from the Accura CDN using ESM syntax.
  // No npm install is required for plain HTML projects.
  import IDCardPlugin from "https://unpkg.com/accuraidscanplugin/dist/accuramain.js";

  // Declare a variable to hold the active plugin instance.
  // This allows us to safely call destroy() before re-initializing.
  let currentPlugin = null;

  // Destroy any previously active instance before creating a new one.
  // This prevents duplicate camera sessions or memory leaks.
  if (currentPlugin) currentPlugin.destroy();

  // Instantiate the IDCardPlugin with two required arguments:
  //   1. The callback function that receives captured card images as base64 Data URLs
  //   2. A configuration object specifying the target card and UI appearance
  currentPlugin = new IDCardPlugin(
    handleCapture,   // Callback invoked upon successful ID card scan completion
    {
      countryCode: "UGA",    // country code of the card being scanned
      cardCode: "UGNIDF",    // card code for the front side of the ID
      topTextSize: "",       // Size of the top instruction overlay text (default if empty)
      topTextColor: "",      // Color of the top instruction overlay text (default if empty)
      topTextWeight: "",     // Font weight of the top instruction text (default if empty)
      bottomTextSize: "",    // Size of the bottom instruction overlay text (default if empty)
      bottomTextColor: "",   // Color of the bottom instruction overlay text (default if empty)
      bottomTextWeight: "",  // Font weight of the bottom instruction text (default if empty)
    }
  );

  // Start the plugin engine. This opens the camera and begins card detection.
  try {
    await currentPlugin.start();
  } catch (error) {
    console.error("Failed to start plugin:", error);
  }
</script>
```

***

### Step 2: Response Handling

When the plugin completes an ID card scan, it invokes the **`handleCapture`** callback with a single 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 captured card image is delivered as a Data URL string (e.g., `data:image/jpeg;base64,/9j/...`), which combines the 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.

```js
const base64ToBlob = (base64DataURL) => {
          // Split the Data URL at the comma to separate the metadata header from the payload.
          // meta  = "data:image/jpeg;base64"
          // content = "/9j/4AAQSkZJRgAB..."
          const [meta, content] = base64DataURL.split(",");

          // Extract the MIME type from the header segment (e.g., "image/jpeg").
          const mimeMatch = meta.match(/:(.*?);/);
          const mime = mimeMatch ? mimeMatch[1] : "image/jpeg";

          // Decode the Base64-encoded string into raw binary data using atob().
          const binary = atob(content);

          // Allocate a typed binary array of the same length as the decoded data.
          const array = new Uint8Array(binary.length);

          // Populate the array by converting each character to its Unicode code point —
          // effectively reconstructing the original binary image bytes.
          for (let i = 0; i < binary.length; i++) {
              array[i] = binary.charCodeAt(i);
          }

          // Return a Blob with the correct MIME type for proper server-side handling.
          return new Blob([array], { type: mime });
      };

      // Dispatches a scanned card image (as a 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" — identifies card side
          formData.append("country_code", "UGA");         // Country code of the ID Card
          formData.append("card_code", card_code);        // Card code of ID Card
          formData.append("passport", "false");           // Set "true" if the document is a passport
          formData.append("webcam", "false");             // Set "true" if captured via 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);

              // Inspect the liveness/authenticity score returned by the verification service.
              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.
      // Receives: base64 — an object containing front and/or back card image Data URLs.
      const handleCapture = async (base64) => {
          // Process the front side of the card if present in the payload.
          if (base64.front) {
              const frontBlob = base64ToBlob(base64.front); // Convert to binary Blob
              await sendToAPI(frontBlob, "front", "UGNIDF", "front.jpg");
          }

          // Process the back side of the card if present in the payload.
          if (base64.back) {
              const backBlob = base64ToBlob(base64.back);   // Convert to binary Blob
              await sendToAPI(backBlob, "back", "UGNIDB", "back.jpg");
          }
      };
```

***

### Step 3: Demo Implementation

The following is a complete, ready-to-use `index.html` file. Copy and paste it as-is into your project. **No modifications have been made to the original logic.**

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Accura IDScan Plugin - HTML Demo</title>
    <style></style>
  </head>
  <body>
    <script type="module">
      // Import the IDCardPlugin class directly from the Accura CDN using ESM syntax.
      // No npm install is required for plain HTML projects.
      import IDCardPlugin from "https://unpkg.com/accuraidscanplugin/dist/accuramain.js";

      // Declare a variable to hold the active plugin instance.
      // This allows us to safely call destroy() before re-initializing.
      let currentPlugin = null;

      // The following handler demonstrates the **base64-to-Blob conversion** and subsequent API submission:

      // Utility function: converts a base64 Data URL string into a binary Blob object.
      // This is necessary because multipart form uploads expect raw binary data,
      // not the text-encoded base64 representation.
      const base64ToBlob = (base64DataURL) => {
          // Split the Data URL at the comma to separate the metadata header from the payload.
          // meta  = "data:image/jpeg;base64"
          // content = "/9j/4AAQSkZJRgAB..."
          const [meta, content] = base64DataURL.split(",");

          // Extract the MIME type from the header segment (e.g., "image/jpeg").
          const mimeMatch = meta.match(/:(.*?);/);
          const mime = mimeMatch ? mimeMatch[1] : "image/jpeg";

          // Decode the Base64-encoded string into raw binary data using atob().
          const binary = atob(content);

          // Allocate a typed binary array of the same length as the decoded data.
          const array = new Uint8Array(binary.length);

          // Populate the array by converting each character to its Unicode code point —
          // effectively reconstructing the original binary image bytes.
          for (let i = 0; i < binary.length; i++) {
              array[i] = binary.charCodeAt(i);
          }

          // Return a Blob with the correct MIME type for proper server-side handling.
          return new Blob([array], { type: mime });
      };

      // Dispatches a scanned card image (as a 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" — identifies card side
          formData.append("country_code", "UGA");         // Country code of the ID Card
          formData.append("card_code", card_code);        // Card code of ID Card
          formData.append("passport", "false");           // Set "true" if the document is a passport
          formData.append("webcam", "false");             // Set "true" if captured via 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);

              // Inspect the liveness/authenticity score returned by the verification service.
              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.
      // Receives: base64 — an object containing front and/or back card image Data URLs.
      const handleCapture = async (base64) => {
          // Process the front side of the card if present in the payload.
          if (base64.front) {
              const frontBlob = base64ToBlob(base64.front); // Convert to binary Blob
              await sendToAPI(frontBlob, "front", "UGNIDF", "front.jpg");
          }

          // Process the back side of the card if present in the payload.
          if (base64.back) {
              const backBlob = base64ToBlob(base64.back);   // Convert to binary Blob
              await sendToAPI(backBlob, "back", "UGNIDB", "back.jpg");
          }
      };

      // Destroy any previously active instance before creating a new one.
      // This prevents duplicate camera sessions or memory leaks.
      if (currentPlugin) currentPlugin.destroy();

      // Instantiate the IDCardPlugin with two required arguments:
      //   1. The callback function that receives captured card images as base64 Data URLs
      //   2. A configuration object specifying the target card and UI appearance
      currentPlugin = new IDCardPlugin(
        handleCapture,   // Callback invoked upon successful ID card scan completion
        {
          countryCode: "UGA",    // country code of the card being scanned
          cardCode: "UGNIDF",    // card code for the front side of the ID
          topTextSize: "",       // Size of the top instruction overlay text (default if empty)
          topTextColor: "",      // Color of the top instruction overlay text (default if empty)
          topTextWeight: "",     // Font weight of the top instruction text (default if empty)
          bottomTextSize: "",    // Size of the bottom instruction overlay text (default if empty)
          bottomTextColor: "",   // Color of the bottom instruction overlay text (default if empty)
          bottomTextWeight: "",  // Font weight of the bottom instruction text (default if empty)
        }
      );

      // Start the plugin engine. This opens the camera and begins card detection.
      try {
        await currentPlugin.start();
      } catch (error) {
        console.error("Failed to start plugin:", error);
      }
    </script>
  </body>
</html>
```

***

> **Note:** Since this uses ESM imports, you must serve the file via a local server (e.g., using Live Server in VS Code or `npx serve .`). Opening the file directly via `file://` may cause CORS or module issues.


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.accurascan.com/language/web-plugin/id-plugin/html-vanilla-js.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
