SSentriq

Templates

Integration recipes for @sentriq/browser

Six real, copy-pasteable patterns for wiring Sentriq into common flows. Each snippet uses the actual SDK API — nothing here is aspirational.

Login Protection

Call track() with the "login" event right after credentials are verified but before the session is issued, so the risk decision can gate the login itself.

import { Sentriq } from '@sentriq/browser';

const sentriq = await Sentriq.init({ publicKey: 'pub_test_xxx' });

const result = await sentriq.track('login', {
  account: { id: user.id }, // your own opaque reference, never an email/password
});

switch (result.risk.decision) {
  case 'block':
    // deny the login
    break;
  case 'challenge':
    // step up — your own 2FA/verification flow (Sentriq returns a
    // decision, not a challenge UI)
    break;
  case 'monitor':
  case 'allow':
    // proceed, optionally log result.risk.score/level for review
    break;
}

Signup Protection

Call track() with the "signup" event when the account is created, before you treat the new account as fully activated.

import { Sentriq } from '@sentriq/browser';

const sentriq = await Sentriq.init({ publicKey: 'pub_test_xxx' });

const result = await sentriq.track('signup', {
  account: { id: newAccount.id },
});

if (result.risk.decision === 'block') {
  // hold the account for review instead of activating it immediately
} else {
  // activate normally; result.device.is_new tells you if this is a
  // first-seen device
}

Trusted Device

After a login, check result.device.trusted to skip extra friction for a device your team has explicitly marked trusted from the dashboard. Trust is device-wide and control-plane-only — the SDK never sets it.

import { Sentriq } from '@sentriq/browser';

const sentriq = await Sentriq.init({ publicKey: 'pub_test_xxx' });

const result = await sentriq.track('login', {
  account: { id: user.id },
});

if (result.device.trusted) {
  // a trusted device still gets a risk decision — this only informs
  // how much friction you layer on top of it
}

console.log(result.device.id, result.device.is_new);

Credential Stuffing Detection

Call track() with "login_failed" on every failed login attempt — that's the signal that feeds Sentriq's BRUTE_FORCE_SUSPECTED and CREDENTIAL_STUFFING_SUSPECTED velocity patterns (one account/few sources vs. one IP/many accounts). A single failed attempt won't trip these; they need a real pattern.

import { Sentriq } from '@sentriq/browser';

const sentriq = await Sentriq.init({ publicKey: 'pub_test_xxx' });

const result = await sentriq.track('login_failed', {
  account: { id: attemptedAccountId },
});

const patternCodes = result.risk.signals
  .map((s) => s.code)
  .filter((code) =>
    ['BRUTE_FORCE_SUSPECTED', 'CREDENTIAL_STUFFING_SUSPECTED', 'ACCOUNT_ATTACK_SUSPECTED'].includes(
      code,
    ),
  );

if (patternCodes.length > 0) {
  // e.g. rate-limit this IP/account harder, or require step-up on the
  // next successful login
}

Bot Risk

For any event, inspect result.risk.signals for automation-related codes. This reflects three basic heuristics (webdriver flag, headless pattern, viewport consistency) — not a dedicated bot-detection suite, so treat it as one input, not a verdict.

The automation signal codes above are the ones Sentriq currently emits — see the Bot & Automation section on the Product page for exactly what each heuristic checks.

import { Sentriq } from '@sentriq/browser';

const sentriq = await Sentriq.init({ publicKey: 'pub_test_xxx' });

const result = await sentriq.track('sensitive_action', {
  account: { id: user.id },
});

const automationSignals = result.risk.signals.filter((s) =>
  ['WEBDRIVER_DETECTED', 'BROWSER_INCONSISTENCY', 'AUTOMATION_SUSPECTED'].includes(s.code),
);

if (automationSignals.length > 0) {
  // weight this into your own decision alongside result.risk.decision —
  // these are heuristics the server treats as evidence, not proof
}

Payment Risk

Call track() with the "payment" event using only risk-relevant metadata — an order/transaction reference, currency, amount tier, whatever is useful for your own review. Sentriq does not collect card numbers, CVVs, or any other payment credential, and has no payment-specific signal logic yet — this event type exists in the taxonomy today, so treat the risk result the same as any other event.

import { Sentriq } from '@sentriq/browser';

const sentriq = await Sentriq.init({ publicKey: 'pub_test_xxx' });

const result = await sentriq.track('payment', {
  account: { id: user.id },
  // Never pass card numbers, CVVs, or other payment credentials here —
  // Sentriq does not collect payment data. Pass only your own opaque,
  // risk-relevant reference (e.g. an order id) if you need one.
});

if (result.risk.decision === 'block' || result.risk.decision === 'challenge') {
  // hold or step-up the payment using your existing device/account/
  // velocity risk signals — there is no payment-specific scoring yet
}