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.