API Armor LogoAPI Armor
Argus Fingerprinting

Framework Guides

Copy-paste Argus integration for plain HTML, Next.js, React, and Vue/Nuxt.

Every integration loads the same CDN tag and reads the asynchronously-populated window.AAArgus. Pick your stack.

Plain HTML

Put the tag before </body> (or in <head> with async):

<script
  site-id="aa-argus-YOUR-SITE-ID"
  src="https://fpcdn.api-armor.com/js/dfs.min.js"
  async
></script>
<script>
  function onArgus(cb, timeoutMs = 8000) {
    const start = Date.now();
    (function poll() {
      if (typeof window.AAArgus !== 'undefined') return cb(window.AAArgus);
      if (Date.now() - start > timeoutMs) return cb(null);
      setTimeout(poll, 100);
    })();
  }
  onArgus((r) => r && console.log('Visitor:', r.argus_visitor_id));
</script>

Next.js

Use next/script with strategy="afterInteractive". Custom attributes like site-id pass straight through.

// app/layout.tsx
import Script from 'next/script';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script
          src="https://fpcdn.api-armor.com/js/dfs.min.js"
          strategy="afterInteractive"
          site-id="aa-argus-YOUR-SITE-ID"
        />
      </body>
    </html>
  );
}

React (Vite / CRA)

Drop this typed hook into your project, then read { result, status } from any component:

import { useEffect, useState } from 'react';

// What the Argus CDN bundle assigns to window.AAArgus.
export interface ArgusResult {
  argus_visitor_id: string;
  match_score: number;
  id_source: 'cookie' | 'storage' | 'fingerprint' | 'new';
  confidence: number;
  bot_score: number;
  network: {
    ja3?: string;
    ja3_hash?: string;
    ja4?: string;
    aa_dfs?: string;
    akamai?: string;
    http_version?: string;
    ip?: string;
    user_agent?: string;
  };
}

declare global {
  interface Window {
    AAArgus?: ArgusResult | null;
  }
}

type Status = 'loading' | 'ready' | 'failed';

// Injects the Argus tag once, then polls window.AAArgus until it
// resolves (`ready`) or fails / times out (`failed`).
export function useArgus(siteId: string, timeoutMs = 8000) {
  const [result, setResult] = useState<ArgusResult | null>(null);
  const [status, setStatus] = useState<Status>('loading');

  useEffect(() => {
    let script = document.querySelector<HTMLScriptElement>('script[data-argus]');
    if (!script) {
      script = document.createElement('script');
      script.src = 'https://fpcdn.api-armor.com/js/dfs.min.js';
      script.async = true;
      script.setAttribute('site-id', siteId);
      // Uncomment to print a colored fingerprint readout to the console:
      // script.setAttribute('debug', 'true');
      script.setAttribute('data-argus', '1');
      document.body.appendChild(script);
    }

    const started = Date.now();
    const id = window.setInterval(() => {
      if (window.AAArgus !== undefined) {
        clearInterval(id);
        if (window.AAArgus === null) setStatus('failed');
        else {
          setResult(window.AAArgus);
          setStatus('ready');
        }
      } else if (Date.now() - started > timeoutMs) {
        clearInterval(id);
        setStatus('failed');
      }
    }, 100);

    return () => clearInterval(id);
  }, [siteId, timeoutMs]);

  return { result, status };
}

Vue / Nuxt

import { onMounted, onUnmounted, ref } from 'vue';

export function useArgus(siteId: string) {
  const argus = ref<any>(null);
  let id: ReturnType<typeof setInterval> | undefined;
  onMounted(() => {
    if (!document.querySelector('script[data-argus]')) {
      const s = document.createElement('script');
      s.src = 'https://fpcdn.api-armor.com/js/dfs.min.js';
      s.async = true;
      s.setAttribute('site-id', siteId);
      s.setAttribute('data-argus', '1');
      document.body.appendChild(s);
    }
    const start = Date.now();
    id = setInterval(() => {
      if (typeof (window as any).AAArgus !== 'undefined') {
        clearInterval(id);
        argus.value = (window as any).AAArgus;
      } else if (Date.now() - start > 8000) {
        clearInterval(id);
      }
    }, 100);
  });
  onUnmounted(() => clearInterval(id));
  return argus;
}

Single-page apps

The tag fingerprints once per full page load, not per client-side route change. To re-identify on navigation, see Advanced usage.

Next

On this page