Gineadh an t-aistriúchán seo le meaisín agus tá sé ar feitheamh athbhreithnithe. Athraigh go Béarla
Deais

Backend Integration

This guide explains how to connect Noxtica to your backend so you can look up a visitor’s risk and make decisions server-side.

Overview

The typical integration flow:

  1. Browser: Add the Noxtica collector script to your website
  2. Browser: The script assigns a fingerprintId to each visitor
  3. Your Code: Store the fingerprintId in your user session or database
  4. Backend: Use the Server API to look up that visitor’s risk score whenever you need it

Step 1: Embed the Collector

Add the Noxtica collector to your website. You can get the exact snippet from the API Config page in your Backoffice.

<script
	src="https://collect.noxtica.com/collector/noxtica.js"
	data-site-key="pk_prod_your_site_key_here"
	data-auto-init
	async
></script>

Using a content-security-policy? You’ll need to allow Noxtica to load and run its tamper-resistant runtime, the KHAN VM. See Getting Started → Content Security Policy for the exact snippet and troubleshooting.

Or initialize manually for more control:

const client = NoxticaCollector.createClient({
	siteKey: 'pk_prod_your_site_key_here',
});

// Recommended: Use checkOnce() which respects the collection interval
const result = await client.checkOnce();

console.log('Fingerprint ID:', result.fingerprintId);
console.log('Risk Score:', result.score);
console.log('Risk Level:', result.risk_level);

Step 2: Store the Fingerprint ID

After collecting, store the fingerprintId in your user session or database:

// Frontend: Send to your backend
const result = await client.checkOnce();

await fetch('/api/login', {
	method: 'POST',
	headers: { 'Content-Type': 'application/json' },
	body: JSON.stringify({
		email: userEmail,
		password: userPassword,
		deviceId: result.fingerprintId, // Include the fingerprint ID
	}),
});

On your backend, store this with the user session:

// Backend: Store in session or database
app.post('/api/login', async (req, res) => {
	const { email, password, deviceId } = req.body;

	// Authenticate user...

	// Store deviceId with session
	req.session.deviceId = deviceId;

	// Or store in your database
	await db.updateUser(userId, { lastDeviceId: deviceId });
});

Step 3: Create a Server API Key

  1. Log in to your Noxtica Backoffice
  2. Go to API Config
  3. Click Create API Key
  4. Give it a name (e.g., “Production Backend”)
  5. Select the scopes you need (usually read:device)
  6. Save the secret key - it’s only shown once!

API keys are prefixed with sk_prod_ and should be stored securely (e.g., environment variables).

Step 4: Look Up Device Data

Use the Server API to look up a visitor’s risk from your backend:

// Node.js example
const NOXTICA_API = 'https://collect.noxtica.com';
const SECRET_KEY = process.env.NOXTICA_API_KEY; // sk_prod_...

async function lookupDevice(deviceId) {
	const response = await fetch(`${NOXTICA_API}/v1/device/${encodeURIComponent(deviceId)}`, {
		headers: {
			Authorization: `Bearer ${SECRET_KEY}`,
		},
	});

	if (response.status === 404) {
		// Device not found - may be new or expired due to retention policy
		return null;
	}

	if (response.status === 401) {
		throw new Error('Invalid API key');
	}

	if (response.status === 403) {
		throw new Error('API key does not have read:device scope');
	}

	if (!response.ok) {
		throw new Error(`Device lookup failed: ${response.status}`);
	}

	return response.json();
}

Example response:

{
	"ok": true,
	"device": {
		"deviceId": "abc123...",
		"domainId": "d_xyz...",
		"score": 25,
		"riskLevel": "low",
		"confidence": 0.6,
		"flags": [],
		"country": "US",
		"city": "San Francisco",
		"createdAt": "2025-01-01T00:00:00.000Z",
		"lastSubmittedAt": "2025-01-05T12:00:00.000Z",
		"lastSeenAt": "2025-01-07T08:30:00.000Z"
	}
}

Step 5: Use the Data

Make decisions based on the fingerprint data:

async function processTransaction(userId, amount) {
	const user = await db.getUser(userId);

	// Look up device fingerprint
	const result = await lookupDevice(user.lastDeviceId);

	if (!result) {
		// Unknown device - require additional verification
		return { status: 'pending', reason: 'unknown_device' };
	}

	const { device } = result;

	// Risk-based decisions
	if (device.riskLevel === 'critical' || device.riskLevel === 'high') {
		// Require additional verification
		return { status: 'pending', reason: 'high_risk_device' };
	}

	if (device.flags.includes('headless_browser')) {
		// Block automated transactions
		return { status: 'blocked', reason: 'automated_access_detected' };
	}

	if (device.score >= 40) {
		// Flag for manual review
		await flagForReview(userId, 'elevated_risk_device');
	}

	// Process transaction
	return processPayment(userId, amount);
}

API Reference

GET /v1/device/:deviceId

Look up the risk data for a specific visitor.

Authentication: Authorization: Bearer sk_prod_...

Required Scope: read:device

Response Fields:

FieldTypeDescription
deviceIdstringThe device identifier
domainIdstringThe domain where this device was last seen
scorenumberRisk score (0-100, higher = riskier)
riskLevelstringRisk level: minimal, low, medium, high, critical
confidencenumberConfidence in the risk assessment (0.5-0.95)
flagsstring[]Risk flags detected
countrystringISO country code
citystringCity name
createdAtstringWhen this device was first seen
lastSubmittedAtstringWhen a full fingerprint was last submitted
lastSeenAtstringWhen this device was last active

Error Responses:

StatusMeaning
401Invalid or missing API key
403API key lacks required scope
404Device not found (may be expired due to retention)
429Rate limit exceeded

Risk Levels Reference

Score RangeLevelConfidenceTypical Meaning
0-19minimal0.50Normal browser, no red flags
20-39low0.60Minor anomalies detected
40-59medium0.70Some suspicious signals
60-79high0.85Likely automation or spoofing
80-100critical0.95Strong bot/automation indicators

Best Practices

Store deviceId securely

The fingerprintId is a unique identifier for a visitor’s browser or device. Store it:

  • In encrypted session cookies
  • In your database linked to user accounts
  • Never expose it in URLs or logs

Handle missing devices gracefully

If a device is not found (404), it may mean:

  • The device cleared its browser storage
  • The data was deleted due to retention policy
  • It’s a new device that hasn’t submitted yet
const result = await lookupDevice(deviceId);
if (!result) {
	// Treat as new/unknown device
	return { riskLevel: 'unknown', requiresVerification: true };
}

Respect rate limits

The API rate limits are:

  • 20 requests per minute per IP for global endpoints
  • 100 requests per minute per tenant+IP for tenant-scoped operations

If you receive a 429 response, honor the Retry-After header.

Cache lookup results

For high-traffic applications, consider caching visitor lookups:

const cache = new Map();
const CACHE_TTL = 60 * 1000; // 1 minute

async function getCachedDevice(deviceId) {
	const cached = cache.get(deviceId);
	if (cached && Date.now() < cached.expiresAt) {
		return cached.data;
	}

	const result = await lookupDevice(deviceId);
	if (result) {
		cache.set(deviceId, {
			data: result,
			expiresAt: Date.now() + CACHE_TTL,
		});
	}
	return result;
}

Other API Endpoints

Beyond visitor lookups, the Server API also provides:

EndpointMethodPurpose
/v1/devicesGETList all devices with filtering
/v1/eventsGETList submission events
/v1/visitsGETList visit events
/v1/exports/fingerprintsGETExport data as CSV/JSON

These require appropriate scopes on your API key.

Next Steps