Quick examples

Copy-paste Cipher recipes for common needs. Grab one, adjust, ship.

Short, self-contained snippets for common needs. Each one assumes you have a Cipher client configured:

import { Cipher } from '@surbee/cipher';
const cipher = new Cipher({ apiKey: process.env.CIPHER_API_KEY!, tier: 4 });

See the SDK guide for the full walkthrough. This page grows over time, so check back for new recipes.

React: a form that captures behavior and submits

import { useEffect, useRef } from 'react';
import { startTracker } from './useBehaviorTracker';

export function SurveyForm() {
  const tracker = useRef<ReturnType<typeof startTracker>>();
  useEffect(() => { tracker.current = startTracker(); }, []);

  async function onSubmit(answers: { question: string; answer: string }[]) {
    const { metrics, device } = tracker.current!.stop();
    const res = await fetch('/api/survey/submit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ answers, metrics, device }),
    });
    if (!res.ok) showMessage('We could not verify this submission.');
  }
  // ... render your fields, call onSubmit(answers) on submit
}

Next.js: validate on submit and gate

// app/api/survey/submit/route.ts
import { Cipher } from '@surbee/cipher';
import { NextResponse } from 'next/server';

const cipher = new Cipher({ apiKey: process.env.CIPHER_API_KEY!, tier: 4 });

export async function POST(req: Request) {
  const { answers, metrics, device } = await req.json();
  const result = await cipher.validate({ responses: answers, behavioralMetrics: metrics, deviceInfo: device });

  if (result.recommendation === 'discard') {
    return NextResponse.json({ ok: false, reason: result.summary.verdict }, { status: 422 });
  }
  await saveResponse({ answers, cipher: { score: result.score, recommendation: result.recommendation, flags: result.flags } });
  return NextResponse.json({ ok: true });
}

Express: a validation endpoint

import express from 'express';
import { Cipher } from '@surbee/cipher';

const cipher = new Cipher({ apiKey: process.env.CIPHER_API_KEY!, tier: 3 });
const app = express();
app.use(express.json());

app.post('/validate', async (req, res) => {
  try {
    const result = await cipher.validate(req.body);
    res.json({ recommendation: result.recommendation, score: result.score, flags: result.flags });
  } catch (err: any) {
    res.status(err.code === 'INSUFFICIENT_CREDITS' ? 402 : 500).json({ error: err.message });
  }
});

Screen an exported dataset (CSV or JSON)

const rows = loadExport(); // your respondents
const batch = await cipher.validateBatch({
  submissions: rows.map(toValidationInput),
  crossAnalysis: true, // catch duplicate answers and shared devices across the set
});

const clean = rows.filter((_, i) => batch.results[i].recommendation === 'keep');
const flagged = rows.filter((_, i) => batch.results[i].recommendation !== 'keep');

A full version with field mapping and report output ships with the SDK at examples/researcher-walkthrough.ts.

Route reviews to a queue

switch (result.recommendation) {
  case 'keep':    await accept(response); break;
  case 'review':  await sendToReviewQueue(response, result.flags); break;
  case 'discard': await quarantine(response, result.summary); break;
}

Retry safely on transient errors

async function validateWithRetry(input: ValidationInput, tries = 3) {
  for (let i = 0; i < tries; i++) {
    try {
      return await cipher.validate(input);
    } catch (err: any) {
      // Do not retry auth, credit, or tier errors. Only network/server ones.
      if (['INVALID_API_KEY', 'INSUFFICIENT_CREDITS', 'TIER_NOT_AVAILABLE'].includes(err.code)) throw err;
      if (i === tries - 1) throw err;
      await new Promise((r) => setTimeout(r, 250 * 2 ** i));
    }
  }
}

Capture behavior in the browser

A minimal tracker that collects the signals the checks read. No extra library needed.

// useBehaviorTracker.ts
export function startTracker() {
  const startedAt = Date.now();
  let keypressCount = 0, backspaceCount = 0, pasteEvents = 0, tabSwitchCount = 0;

  const onKey = (e: KeyboardEvent) => { keypressCount++; if (e.key === 'Backspace') backspaceCount++; };
  const onPaste = () => { pasteEvents++; };
  const onBlur = () => { tabSwitchCount++; };
  document.addEventListener('keydown', onKey);
  document.addEventListener('paste', onPaste);
  window.addEventListener('blur', onBlur);

  return {
    stop() {
      document.removeEventListener('keydown', onKey);
      document.removeEventListener('paste', onPaste);
      window.removeEventListener('blur', onBlur);
      return {
        metrics: { sessionId: crypto.randomUUID(), duration: Date.now() - startedAt, keypressCount, backspaceCount, pasteEvents, tabSwitchCount },
        device: {
          userAgent: navigator.userAgent, platform: navigator.platform, language: navigator.language,
          timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
          screenWidth: screen.width, screenHeight: screen.height, webDriver: navigator.webdriver === true,
        },
      };
    },
  };
}
Quick examples | Surbee