Backend Integration
This guide explains how to integrate Noxtica with your backend services to look up fingerprint data for your users.
Overview
The typical integration flow:
- Browser: Embed the Noxtica collector script on your website
- Browser: The script generates a
fingerprintIdfor each visitor - Your Code: Store the
fingerprintIdin your user session or database - Backend: Use the Server API to look up the device’s fingerprint and risk score
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-collector.js"
data-site-key="pk_prod_your_site_key_here"
data-auto-init
async
></script>
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
- Log in to your Noxtica Backoffice
- Go to API Config
- Click Create API Key
- Give it a name (e.g., “Production Backend”)
- Select the scopes you need (usually
read:device) - 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 fingerprint data 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 fingerprint data for a specific device.
Authentication: Authorization: Bearer sk_prod_...
Required Scope: read:device
Response Fields:
| Field | Type | Description |
|---|---|---|
deviceId | string | The device identifier |
domainId | string | The domain where this device was last seen |
score | number | Risk score (0-100, higher = riskier) |
riskLevel | string | Risk level: minimal, low, medium, high, critical |
confidence | number | Confidence in the risk assessment (0.5-0.95) |
flags | string[] | Risk flags detected |
country | string | ISO country code |
city | string | City name |
createdAt | string | When this device was first seen |
lastSubmittedAt | string | When a full fingerprint was last submitted |
lastSeenAt | string | When this device was last active |
Error Responses:
| Status | Meaning |
|---|---|
| 401 | Invalid or missing API key |
| 403 | API key lacks required scope |
| 404 | Device not found (may be expired due to retention) |
| 429 | Rate limit exceeded |
Risk Levels Reference
| Score Range | Level | Confidence | Typical Meaning |
|---|---|---|---|
| 0-19 | minimal | 0.50 | Normal browser, no red flags |
| 20-39 | low | 0.60 | Minor anomalies detected |
| 40-59 | medium | 0.70 | Some suspicious signals |
| 60-79 | high | 0.85 | Likely automation or spoofing |
| 80-100 | critical | 0.95 | Strong bot/automation indicators |
Best Practices
Store deviceId securely
The fingerprintId is a unique identifier for a browser/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 device 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 device lookups, the Server API also provides:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/devices | GET | List all devices with filtering |
/v1/events | GET | List submission events |
/v1/visits | GET | List visit events |
/v1/exports/fingerprints | GET | Export data as CSV/JSON |
These require appropriate scopes on your API key.
Next Steps
- View your fingerprints in the Backoffice Dashboard
- Return to Getting Started for client-side setup