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:

  1. Browser: Embed the Noxtica collector script on your website
  2. Browser: The script generates a fingerprintId for each visitor
  3. Your Code: Store the fingerprintId in your user session or database
  4. 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

  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 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:

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 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:

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