npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@bynn-intelligence/agemin-sdk

v5.8.4

Published

agemin.com SDK for age verification

Readme

Agemin SDK

npm version License: MIT

A secure, type-safe JavaScript/TypeScript SDK for integrating Agemin biometric age verification into your web applications.

🔒 Security-First Design: This SDK uses a secure architecture where verification results are only accessible server-side using your private API key, preventing abuse and ensuring billing security.

📝 Prerequisites:

  1. Create a free account on agemin.com
  2. Get your Asset ID from agemin.com/app/websites (format: ast_HfQNoqfkqJdT5m8akPNKaXYu)
  3. Get your Private Key from agemin.com/app/api-keys
  4. Keep your Private Key secure on your backend server

Features

  • 🚀 Easy Integration - Simple API with automatic initialization support
  • 📱 Cross-Platform - Works on desktop and mobile browsers
  • 🎨 Customizable - Theme support (light/dark/auto) and localization
  • 🔒 Secure - Cross-origin communication with trusted domain validation
  • 📦 Lightweight - Zero runtime dependencies
  • 💪 TypeScript - Full TypeScript support with comprehensive type definitions
  • 🎯 Flexible - Multiple verification modes (modal, popup, redirect)
  • ⚛️ React Compatible - Singleton pattern prevents duplicate modals in StrictMode (v5.0+)

Getting Started

  1. Sign up for a free account at agemin.com
  2. Get your Asset ID at agemin.com/app/websites
    • Each website/app has a unique Asset ID (e.g., ast_HfQNoqfkqJdT5m8akPNKaXYu)
    • Use this Asset ID in your frontend SDK
  3. Get your Private Key at agemin.com/app/api-keys
    • Keep this secure on your backend only
  4. Install the SDK using your preferred package manager
  5. Generate reference IDs server-side for each verification
  6. Initialize SDK with Asset ID and Reference ID
  7. Verify results server-side using your Private Key

Installation

NPM

npm install @bynn-intelligence/agemin-sdk

Yarn

yarn add @bynn-intelligence/agemin-sdk

pnpm

pnpm add @bynn-intelligence/agemin-sdk

CDN

<!-- Latest version -->
<script src="https://unpkg.com/@bynn-intelligence/agemin-sdk/dist/agemin-sdk.umd.js"></script>

<!-- Specific version -->
<script src="https://unpkg.com/@bynn-intelligence/[email protected]/dist/agemin-sdk.umd.js"></script>

<!-- Minified version -->
<script src="https://unpkg.com/@bynn-intelligence/agemin-sdk/dist/agemin-sdk.min.js"></script>

Quick Start

Frontend Implementation

import Agemin from '@bynn-intelligence/agemin-sdk';

// 1. Get reference ID from your backend
const response = await fetch('/api/agemin/reference', { method: 'POST' });
const { referenceId } = await response.json();

// 2. Initialize SDK with Asset ID and Reference ID
// Note: In v5.x, only the first call creates an instance
const agemin = new Agemin({
  assetId: 'ast_5b08b274353b92f4',    // Your Asset ID from agemin.com/app/websites
  referenceId: referenceId,           // Unique reference ID from your backend (max 50 bytes)
  metadata: { userId: 123 },          // Optional metadata (max 256 bytes when stringified)
  debug: true
});

// Alternative: Use getInstance() to get existing instance
const agemin = Agemin.getInstance(); // Get existing instance
// or create if doesn't exist:
const agemin = Agemin.getInstance(config);

// 3. Optional: Register event listeners for real-time updates
agemin.onAppReady(() => {
  console.log('Verification app loaded successfully');
});

agemin.onProgress((data) => {
  console.log(`Progress: ${data.percentage}% - ${data.stage}`);
  // Update your UI with progress information
});

agemin.onStateChange((data) => {
  console.log(`State changed from ${data.from} to ${data.to}`);
});

agemin.onUserAction((data) => {
  console.log(`User action: ${data.type} on ${data.target}`);
  // Track user interactions for analytics
});

// 4. Start verification
agemin.verify({
  onSuccess: (result) => {
    // Verification process completed (doesn't mean user passed)
    // For extra security against injection attacks, check status from backend via API
    // GET https://api.agemin.com/v1/agemin/check/status/${result.sessionToken} (see api doc)
    console.log('Verification completed:', result.referenceId);
  },
  
  onAgePass: (result) => {
    // User passed age verification (JWT present and is_of_age = true)
    console.log('Age verification passed');
    window.location.href = '/protected-content';
  },
  
  onAgeFail: (result) => {
    // User failed age verification (JWT present but is_of_age = false)
    console.log('Age verification failed');
    window.location.href = '/age-restricted';
  },
  
  onError: (error) => {
    // Technical error - show fallback
    console.error('Technical error:', error);
    showFallbackAgeModal();
  },
  
  onCancel: () => {
    console.log('User cancelled verification');
  }
});

Age Gating Every Page

To ensure all your pages are properly age-gated, use the validateSession method at the top of each protected page:

// On every age-restricted page
const agemin = new Agemin({
  assetId: 'ast_A6ctvqk5egQtCoZhr5LrWkRm',
  referenceId: 'unique-reference-id' // Use visitor ID, session ID, or UUID
});

// Check for existing valid session or launch verification
const result = await agemin.validateSession({
  onSuccess: (data) => {
    console.log('Verification completed');
    // For extra security against injection attacks, check status from backend via API
    // GET https://api.agemin.com/v1/agemin/check/status/${data.sessionToken} (see api doc)
  },
  
  onAgePass: (data) => {
    console.log('User is age verified');
    // Allow access to content
  },
  
  onAgeFail: (data) => {
    console.log('User did not meet age requirement');
    // Redirect to age-restricted page
    window.location.href = '/age-restricted';
  },
  
  onError: (err) => {
    console.error('Verification error:', err);
    // Show fallback age gate
    showFallbackAgeModal();
  }
});

// If result is true, user already has valid session
if (result === true) {
  console.log('User already age verified from previous session');
  // Content is accessible
}

The validateSession method will:

  • Return true immediately if a valid age verification cookie exists
  • Automatically launch verification if:
    • No verification cookie exists
    • The JWT is expired or invalid
    • The user previously failed age verification

React Integration (v5.0+ Singleton Pattern)

The SDK v5.0+ uses a singleton pattern to prevent duplicate modals in React StrictMode:

import { useEffect, useRef } from 'react';
import Agemin from '@bynn-intelligence/agemin-sdk';

function AgeGate({ children }) {
  const initialized = useRef(false);
  
  useEffect(() => {
    // React StrictMode will call this twice, but SDK handles it
    if (initialized.current) return;
    initialized.current = true;
    
    // Create Agemin instance (singleton - only first call creates instance)
    const agemin = new Agemin({
      assetId: 'ast_A6ctvqk5egQtCoZhr5LrWkRm',
      referenceId: generateUniqueId(),
      debug: true
    });
    
    // Validate session
    agemin.validateSession({
      onAgePass: () => {
        console.log('User is verified');
      },
      onAgeFail: () => {
        window.location.href = '/age-restricted';
      }
    });
    
    // Cleanup (optional - for testing)
    return () => {
      // Only reset if you need to create a new instance
      // Agemin.reset();
    };
  }, []);
  
  return children;
}

Key Points for React:

  • The SDK automatically handles multiple new Agemin() calls by returning the same instance
  • Only one verification modal will ever be shown, even in StrictMode
  • Use Agemin.reset() only when you need to create a completely new instance
  • The singleton pattern prevents race conditions and duplicate modals

Backend Implementation (Node.js Example) (optional but more secure)

// Generate reference endpoint
app.post('/api/agemin/reference', (req, res) => {
  // Generate unique reference ID
  const referenceId = crypto.randomUUID();
  
  // Store reference in database with user context
  await db.references.create({
    id: referenceId,
    userId: req.user?.id,
    createdAt: new Date()
  });
  
  res.json({ referenceId });
});

// Verify result endpoint
app.post('/api/agemin/verify', async (req, res) => {
  const { referenceId } = req.body;
  
  // Fetch verification result from Agemin API using Private Key
  const result = await fetch(`https://api.agemin.com/v1/agemin/result?referenceId=${referenceId}`, {
    headers: {
      'Authorization': `Bearer ${process.env.AGEMIN_PRIVATE_KEY}` // Private key from agemin.com/app/api-keys
    }
  });
  
  const verification = await result.json();
  
  // Check if user meets age requirement
  const verified = verification.status === 'verified';
  
  // Update reference in database
  await db.references.update(referenceId, {
    verified,
    completedAt: new Date()
  });
  
  res.json({ 
    verified,
    age: verification.age // Only if needed
  });
});

Auto-Initialization

You can configure the SDK directly in HTML using data attributes:

<script src="https://unpkg.com/@bynn-intelligence/agemin-sdk/dist/agemin-sdk.min.js"
  data-agemin-asset-id="ast_5b08b274353b92f4"
  data-agemin-reference-id="unique-reference-id"
  data-agemin-theme="auto"
  data-agemin-locale="en"
  data-agemin-debug="true">
</script>

<!-- Any button with data-agemin-trigger will automatically start verification -->
<button data-agemin-trigger>Verify My Age</button>

Note: The reference ID must be generated server-side and injected into the HTML for security.

Configuration Options

SDK Initialization

const agemin = new Agemin({
  // Required
  assetId: string;           // Your Asset ID from agemin.com/app/websites (e.g., 'ast_5b08b274353b92f4')
  referenceId: string;       // Unique reference ID (max 50 bytes, generate server-side)
  
  // Optional
  metadata?: Record<string, any>;  // Custom metadata (max 256 bytes when stringified)
  theme?: 'light' | 'dark' | 'auto';  // UI theme (default: 'auto')
  locale?: string;            // Language locale (default: 'en')
  errorUrl?: string;          // URL to redirect on error
  successUrl?: string;        // URL to redirect on success
  cancelUrl?: string;         // URL to redirect on cancellation
  debug?: boolean;            // Enable debug logging (default: false)
  allowSearchEngineBypass?: boolean;  // Allow search engines to bypass age verification (default: false)
  searchEngineDetection?: 'ua' | 'headless' | 'cookies' | 'combined' | 'strict';  // Detection mode (default: 'ua')
});

Size Limits:

  • referenceId: Maximum 50 bytes
  • metadata: Maximum 256 bytes when JSON stringified

These limits ensure efficient data transmission and prevent abuse.

SEO Configuration - Search Engine Bypass

For SEO optimization, you can allow search engine crawlers to bypass age verification while keeping it active for regular users:

const agemin = new Agemin({
  assetId: 'ast_xxx',
  referenceId: 'ref_xxx',
  allowSearchEngineBypass: true,  // Enable bypass for crawlers
  searchEngineDetection: 'combined'  // Detection mode (default: 'ua')
});

// When validateSession() is called:
// - Search engines → Automatic bypass, returns true
// - Regular users → Normal age verification flow

Detection Modes

The SDK offers multiple crawler detection strategies to balance accuracy and performance:

| Mode | Description | Use Case | |------|-------------|----------| | 'ua' | User agent string detection only | Default. Fast, reliable for most crawlers | | 'headless' | Detects headless browser characteristics | Catches sophisticated crawlers using headless Chrome | | 'cookies' | Checks if cookies are supported | Googlebot typically doesn't support cookies | | 'combined' | Any detection method triggers bypass | Most inclusive. Best for SEO but may have false positives | | 'strict' | Requires multiple detection signals | Most accurate. Reduces false positives |

Detection Methods Explained

1. User Agent Detection ('ua')

  • Checks for known crawler patterns in user agent string
  • Covers Google, Bing, social media bots, SEO tools
  • Fast but can be spoofed

2. Headless Browser Detection ('headless')

  • Checks navigator.plugins.length === 0
  • Checks empty navigator.languages
  • Detects WebGL signatures (Mesa OffScreen, SwiftShader)
  • Effective against headless Chrome/Puppeteer

3. Cookie Support Detection ('cookies')

  • Tests if browser can set/read cookies
  • Googlebot generally doesn't support cookies
  • May trigger on privacy-focused users

4. Combined Detection ('combined')

  • Uses OR logic: any method detecting a bot triggers bypass
  • Best for maximum SEO coverage
  • May bypass for some privacy-conscious users

5. Strict Detection ('strict')

  • Requires bot user agent AND (headless OR no cookies)
  • Minimizes false positives
  • May miss some legitimate crawlers

Example Configurations

// Maximum SEO coverage (recommended for content sites)
const agemin = new Agemin({
  assetId: 'ast_xxx',
  referenceId: 'ref_xxx',
  allowSearchEngineBypass: true,
  searchEngineDetection: 'combined'
});

// Balanced approach (default)
const agemin = new Agemin({
  assetId: 'ast_xxx',
  referenceId: 'ref_xxx',
  allowSearchEngineBypass: true
  // searchEngineDetection defaults to 'ua'
});

// Strict validation (e-commerce, sensitive content)
const agemin = new Agemin({
  assetId: 'ast_xxx',
  referenceId: 'ref_xxx',
  allowSearchEngineBypass: true,
  searchEngineDetection: 'strict'
});

Important Notes:

  • Detection results are cached for 1 minute to improve performance
  • This only affects client-side validation
  • Search engines still won't have valid JWT cookies for server-side verification
  • Test with Google's Mobile-Friendly Test tool to verify your configuration

Verification Options

agemin.verify({
  // Display mode
  mode?: 'modal' | 'redirect';  // How to show verification (default: modal)
  
  // Callbacks
  onSuccess?: (result: VerificationResult) => void;  // Verification completed (process finished)
  onAgePass?: (result: VerificationResult) => void;  // User passed age check (JWT present, is_of_age = true)
  onAgeFail?: (result: VerificationResult) => void;  // User failed age check (JWT present, is_of_age = false)
  onError?: (error: VerificationError) => void;      // Technical error (API, network, etc.)
  onCancel?: () => void;                            // User cancelled verification
  onClose?: () => void;                             // Modal closed
  
  // Customization
  theme?: 'light' | 'dark' | 'auto';  // Override default theme
  locale?: string;                     // Override default locale (use 'auto' for browser detection)
  metadata?: Record<string, any>;      // Custom metadata to attach
});

VerificationResult Object

interface VerificationResult {
  referenceId: string;    // Reference ID to verify on backend
  sessionToken?: string;  // Session token for backend API verification
  completed: boolean;     // Verification process completed
  timestamp: number;      // Completion timestamp
}

Important: The onSuccess callback only indicates the verification process completed. It does NOT mean the user passed the age check. Use onAgePass and onAgeFail for age-specific results, or verify server-side using your Private Key for strong API security.

Event Listeners

The SDK provides event listeners for real-time updates during the verification process:

onAppReady(callback)

Called when the verification app has loaded and is ready.

agemin.onAppReady(() => {
  console.log('App is ready');
  // Hide loading spinner, enable buttons, etc.
});

onProgress(callback)

Receive real-time progress updates during face scanning.

agemin.onProgress((data) => {
  console.log(`Progress: ${data.percentage}%`);
  console.log(`Stage: ${data.stage}`);     // e.g., "Hold still", "Move closer"
  console.log(`Message: ${data.message}`); // e.g., "Capture 3/5"
  
  // Update your progress bar
  updateProgressBar(data.percentage);
});

onStateChange(callback)

Track state transitions in the verification flow.

agemin.onStateChange((data) => {
  console.log(`From: ${data.from}`);
  console.log(`To: ${data.to}`);
  console.log(`Data: ${data.data}`);
  
  // Handle state-specific logic
  if (data.to === 'completed') {
    showSuccessMessage();
  }
});

onUserAction(callback)

Monitor user interactions for analytics or UX improvements.

agemin.onUserAction((data) => {
  console.log(`Action: ${data.type}`);    // e.g., "cancel", "click"
  console.log(`Target: ${data.target}`);  // e.g., "consent_page", "face_scan_page"
  
  // Track with analytics
  analytics.track('agemin_user_action', data);
});

API Reference

Methods

verify(options?: VerifyOptions): string

Starts the verification process. Returns the reference ID.

validateSession(options?: VerifyOptions): Promise<boolean | string>

Validates if a user has a valid age verification session stored in cookies.

  • Returns true if a valid session exists and the user is of age
  • Automatically launches verification and returns the reference ID if:
    • No verification cookie exists
    • The JWT token is expired
    • The JWT signature is invalid
    • The user is not of age (is_of_age: false)

This method is useful for automatically checking and maintaining age verification across page loads:

// Simple usage - automatically handles everything
const result = await agemin.validateSession();
if (result === true) {
  // User already age verified, allow access
  console.log('User has valid age verification');
} else {
  // Verification was launched, result is the referenceId
  console.log('Verification launched with ID:', result);
}

// With callbacks for the verification flow
const result = await agemin.validateSession({
  onSuccess: (data) => {
    console.log('Age verification successful');
    // User is now verified
    // For extra security against injection attacks, check status from backend via API
    // GET https://api.agemin.com/v1/agemin/check/status/${data.sessionToken} (see api doc)
  },
  onError: (err) => {
    console.error('Verification error:', err);
    // Show fallback age gate
  }
});

Note: This method requires cookies to be enabled. The verification is stored as a JWT in the agemin_verification cookie, with the duration controlled by your website's security settings in the Agemin dashboard.

close(): void

Programmatically closes the verification modal/popup.

isOpen(): boolean

Checks if a verification session is currently active.

getReferenceId(): string

Returns the reference ID for the current verification.

Static Methods

Agemin.version: string

Returns the SDK version.

Agemin.isSupported(): boolean

Checks if the current browser is supported.

TypeScript Support

The SDK includes comprehensive TypeScript definitions:

import Agemin, { 
  AgeminConfig, 
  VerifyOptions, 
  VerificationResult,
  VerificationError 
} from '@bynn-intelligence/agemin-sdk';

// Full type safety and IntelliSense support
const config: AgeminConfig = {
  assetId: 'ast_HfQNoqfkqJdT5m8akPNKaXYu',
  referenceId: 'unique-reference-id',  // Required: generate server-side
  theme: 'dark'
};

const agemin = new Agemin(config);

Verification Modes

Modal (Default)

Opens verification in an iframe overlay within the current page. Works seamlessly on both desktop and mobile devices.

agemin.verify({ mode: 'modal' });

Redirect

Redirects the entire page to the verification URL. Useful for single-page flows or when iframe is not suitable.

agemin.verify({ mode: 'redirect' });

Event Handling

The SDK provides comprehensive event callbacks for different scenarios:

agemin.verify({
  onSuccess: (result) => {
    // Verification process completed successfully
    console.log('Reference ID:', result.referenceId);
    console.log('Session Token:', result.sessionToken);
    console.log('Completed:', result.completed); // true
    // Note: This doesn't indicate if user passed age check
    // For extra security against injection attacks, check status from backend via API
    // GET https://api.agemin.com/v1/agemin/check/status/${result.sessionToken} (see api doc)
  },
  
  onAgePass: (result) => {
    // User passed age verification (JWT present and is_of_age = true)
    console.log('User meets age requirement');
    // Allow access to age-restricted content
  },
  
  onAgeFail: (result) => {
    // User failed age verification (JWT present but is_of_age = false)
    console.log('User does not meet age requirement');
    // Redirect to age-appropriate content or show restriction message
  },
  
  onError: (error) => {
    // Technical error occurred (API, network, model error, etc.)
    console.error('Error code:', error.code);
    console.error('Error message:', error.message);
    
    // IMPORTANT: Show fallback age confirmation to avoid losing visitors
    // Example: Display a simple "Are you 18+" modal as backup
    showBackupAgeGate();
  },
  
  onCancel: () => {
    // User explicitly cancelled the verification process
    console.log('User cancelled');
  },
  
  onClose: () => {
    // Modal/popup was closed (fired after other callbacks)
    console.log('Verification window closed');
  }
});

Important: Handling Technical Errors

When onError is triggered (technical issues), we strongly recommend showing a fallback age confirmation modal to ensure you don't lose potential visitors due to temporary technical issues:

function showBackupAgeGate() {
  // Simple fallback when Agemin verification has technical issues
  const confirmed = confirm('Please confirm you are 18 or older to continue');
  if (confirmed) {
    // Allow access with degraded verification
    allowAccess();
  } else {
    // Redirect to age-appropriate content
    window.location.href = '/underage';
  }
}

Examples

React Integration

import React, { useEffect, useState } from 'react';
import Agemin from '@bynn-intelligence/agemin-sdk';

function AgeVerification() {
  const [agemin, setAgemin] = useState(null);
  const [isVerified, setIsVerified] = useState(false);
  
  useEffect(() => {
    const sdk = new Agemin({
      assetId: process.env.REACT_APP_AGEMIN_ASSET_ID,
      referenceId: generateUniqueId()  // Required: generate unique ID
    });
    setAgemin(sdk);
  }, []);
  
  const handleVerify = () => {
    agemin?.verify({
      onSuccess: (result) => {
        console.log('Verification completed');
        // For extra security against injection attacks, check status from backend via API
        // GET https://api.agemin.com/v1/agemin/check/status/${result.sessionToken} (see api doc)
      },
      onAgePass: (result) => {
        setIsVerified(true);
        // User passed age verification
      },
      onAgeFail: (result) => {
        // User is underage
        alert('You must be 18 or older to access this content');
        window.location.href = '/age-restricted';
      },
      onError: (error) => {
        // Technical error - show fallback
        if (confirm('Please confirm you are 18 or older')) {
          setIsVerified(true);
        }
      }
    });
  };
  
  return (
    <div>
      {!isVerified ? (
        <button onClick={handleVerify}>Verify Age</button>
      ) : (
        <p>✅ Age verified!</p>
      )}
    </div>
  );
}

Vue.js Integration

<template>
  <div>
    <button @click="verifyAge" v-if="!isVerified">
      Verify Age
    </button>
    <p v-else>✅ Age verified!</p>
  </div>
</template>

<script>
import Agemin from '@bynn-intelligence/agemin-sdk';

export default {
  data() {
    return {
      agemin: null,
      isVerified: false
    };
  },
  
  mounted() {
    this.agemin = new Agemin({
      assetId: process.env.VUE_APP_AGEMIN_ASSET_ID,
      referenceId: this.generateUniqueId()  // Required: generate unique ID
    });
  },
  
  methods: {
    verifyAge() {
      this.agemin.verify({
        onSuccess: (result) => {
          console.log('Verification completed');
          // For extra security against injection attacks, check status from backend via API
          // GET https://api.agemin.com/v1/agemin/check/status/${result.sessionToken} (see api doc)
        },
        onAgePass: (result) => {
          this.isVerified = true;
          // User passed age verification
        },
        onAgeFail: (result) => {
          alert('You must be 18 or older to access this content');
          window.location.href = '/age-restricted';
        },
        onError: (error) => {
          alert(`Verification failed: ${error.message}`);
        }
      });
    }
  }
};
</script>

Custom Metadata

You can attach custom metadata to verification sessions:

agemin.verify({
  metadata: {
    source: 'checkout-page',
    productId: 'ABC123',
    userId: 'user-456',
    timestamp: Date.now()
  },
  onSuccess: (result) => {
    // Metadata is included in the verification result
    console.log('Verification completed with metadata');
  }
});

Browser Support

The SDK supports all modern browsers:

  • Chrome 90+
  • Firefox 88+
  • Safari 14+
  • Edge 90+
  • Mobile Safari (iOS 14+)
  • Chrome Mobile (Android)

Development

Building from Source

# Clone the repository
git clone https://github.com/Bynn-Intelligence/agemin-sdk.git
cd agemin-sdk

# Install dependencies
npm install

# Build the SDK
npm run build

# Watch mode for development
npm run dev

Running Examples

# Build the SDK first
npm run build

# Open an example in your browser
open examples/basic.html

Security Architecture

Why Server-Side Verification?

This SDK uses a secure two-step verification process:

  1. Frontend handles the UI/UX of age verification
  2. Backend fetches and validates the actual results

This architecture prevents:

  • Billing fraud: Others can't use your Asset ID without your knowledge
  • Result tampering: Verification results can't be faked client-side
  • API key exposure: Your Private Key never leaves your server

Security Flow

sequenceDiagram
    participant User
    participant Frontend
    participant YourBackend
    participant AgeminAPI
    
    User->>Frontend: Initiate verification
    Frontend->>YourBackend: Request session ID
    YourBackend->>Frontend: Return unique session ID
    Frontend->>AgeminAPI: Start verification (Asset ID + Session ID)
    User->>AgeminAPI: Complete verification
    AgeminAPI->>Frontend: Verification completed
    Frontend->>YourBackend: Check result (Session ID)
    YourBackend->>AgeminAPI: GET /result (Private Key + Session ID)
    AgeminAPI->>YourBackend: Return actual result
    YourBackend->>Frontend: Return verified/not verified

API Keys

  • Asset ID: Get from agemin.com/app/websites
    • Each website/app has a unique Asset ID (format: ast_HfQNoqfkqJdT5m8akPNKaXYu)
    • Safe to use in frontend code
  • Private Key: Get from agemin.com/app/api-keys
    • NEVER expose in frontend code, keep on backend only

Best Practices

  1. Generate Session IDs server-side: Use cryptographically secure random generators
  2. Validate sessions: Track sessions in your database to prevent replay attacks
  3. Set session expiry: Expire unused sessions after a reasonable time
  4. Use HTTPS: Always use HTTPS in production
  5. Secure your Private Key: Store in environment variables, never commit to code

Error Handling

Technical Errors

Technical errors trigger onError and should be handled with a fallback:

agemin.verify({
  onError: (error) => {
    // Log the technical error for debugging
    console.error('Technical error:', error.code, error.message);
    
    // Show fallback age gate to avoid losing visitors
    switch (error.code) {
      case 'POPUP_BLOCKED':
        alert('Please allow popups for age verification');
        showSimpleAgeGate();
        break;
      
      case 'NETWORK_ERROR':
      case 'API_ERROR':
      case 'MODEL_ERROR':
        // Don't lose the visitor - show backup age confirmation
        showSimpleAgeGate();
        break;
      
      default:
        showSimpleAgeGate();
    }
  }
});

function showSimpleAgeGate() {
  // Fallback for when Agemin verification has technical issues
  const isAdult = confirm('Are you 18 years or older?');
  if (isAdult) {
    // Grant degraded access
    grantAccess(/* limited = */ true);
  } else {
    redirectToAgeAppropriate();
  }
}

Guide for AI Assistants (LLMs)

This section helps AI assistants understand how to guide developers in integrating the Agemin SDK.

What This SDK Does

The Agemin SDK provides age verification through facial scanning. It offers two main methods for integration, each suited for different use cases.

Two Ways to Verify Age

Method 1: Manual Verification (verify)

User clicks button → Modal opens → Face scan → Result callbacks

When to use: User explicitly triggers verification (e.g., "Verify Age" button)

Callbacks flow:

  • onSuccess - Always fires when verification completes
  • onAgePass - Fires if user meets age requirement
  • onAgeFail - Fires if user doesn't meet requirement
  • onError - Fires on technical problems
  • onCancel - Fires if user closes modal

Method 2: Automatic Verification (validateSession)

Page loads → Check saved session → If valid: continue | If not: auto-launch verify

When to use: Protecting multiple pages automatically

Returns:

  • true if user already verified (has valid session)
  • Launches verification modal if no valid session exists

Simple Decision Guide

Single "Verify Age" button?          → Use verify()
Protect every page automatically?    → Use validateSession()  
Want seamless multi-page experience? → Use validateSession()

Understanding the Callbacks

Verification Process Flow:
┌─────────────────┐
│ Verification    │
│ Completes       │ → onSuccess (always called)
└────────┬────────┘
         │
    ┌────┴────┐
    │ Result? │
    └────┬────┘
         │
    ┌────┴────────────┐
    │                 │
    ↓                 ↓
onAgePass         onAgeFail
(Age met)         (Age not met)

Technical Error → onError
User Closes    → onCancel

Integration Checklist for AI Assistants

When helping developers integrate this SDK:

  • [ ] Asset ID: Ensure developer has Asset ID from agemin.com/app/websites
  • [ ] Reference ID: Each verification needs a unique reference ID
  • [ ] Choose method:
    • Single button/trigger → Use verify()
    • Automatic page protection → Use validateSession()
  • [ ] Prevent infinite loops: Age-fail redirect pages must NOT be age-gated
  • [ ] Session persistence: validateSession() remembers users across pages
  • [ ] Callback handling: Implement appropriate callbacks for the use case

Common Integration Patterns

| Use Case | Recommended Method | Why | |----------|-------------------|-----| | E-commerce checkout | validateSession() | Seamless multi-step process | | Content website | validateSession() | Protects all restricted pages | | Single landing page | verify() | One-time verification | | Terms acceptance | verify() | Explicit user action | | Gaming platform | validateSession() | Persistent access control |

Key Concepts to Explain

  1. Session Management: The SDK handles session storage automatically - developers don't manage cookies or tokens

  2. Verification Flow:

    • User's age is verified through face scanning
    • Result is stored securely
    • Future page visits check this stored result
  3. Security Models:

    • Strong API Security: Results only available server-side (onSuccess fires, no age result in frontend)
    • Standard Security: Age result available in callbacks (onAgePass/onAgeFail)

Common Pitfalls to Warn About

  1. Infinite Loop: Never use validateSession() on the age-fail redirect page
  2. Unique IDs: Each user needs a unique reference ID (use session ID or user ID)
  3. Method Confusion: Don't use verify() for automatic page protection
  4. Callback Misunderstanding: onSuccess ≠ user passed age check

Guidance Summary

When an LLM helps a developer:

  1. First, understand if they need single-trigger or automatic protection
  2. For automatic protection across pages → validateSession()
  3. For button-triggered verification → verify()
  4. Always warn about the infinite loop risk with age-fail pages
  5. Emphasize that the SDK handles all session management internally

License

MIT License - see LICENSE file for details.

Support

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Changelog

See CHANGELOG.md for a list of changes in each version.