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