npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@preverus/node

v0.1.2

Published

Node.js backend client for Preverus fraud decisions, events, lookups, and webhooks.

Readme

Preverus Node

Node.js backend client for Preverus fraud decisions, events, lookups, and webhooks.

Website: https://preverus.com
Documentation: https://preverus.com/docs

This package is for server-side code only. It uses your private server key and must never be imported into browser bundles.

Install

npm install @preverus/node

Requires Node.js 18+.

Browser And Server Flow

Load the hosted browser script on server-rendered or frontend pages:

<script
  src="https://api.preverus.com/v1/preverus.js"
  data-preverus-key="pk_live_xxx"
  data-preverus-auto="true"
  data-preverus-track-forms="true"
></script>

<form method="POST" action="/register" data-preverus-action="signup">
  <input name="email" type="email">
  <button type="submit">Create account</button>
</form>

Before submit, the script attaches:

preverus_fingerprint
preverus_visitor_id
preverus_risk_session_token
preverus_browser_session_event_id

Your Node backend sends those values to Preverus with a private server key before approving sensitive actions.

Quick Start

import { createPreverusNode } from "@preverus/node";

const preverus = createPreverusNode({
  serverKey: process.env.PREVERUS_SERVER_KEY!,
});

const decision = await preverus.evaluate(
  {
    event_type: "signup",
    user_id: "acct_42",
    ip: req.ip,
    risk_session_token: req.body.preverus_risk_session_token,
    fingerprint: req.body.preverus_fingerprint,
    metadata: {
      email: req.body.email,
      browser_session_event_id: req.body.preverus_browser_session_event_id,
    },
  },
  {
    visitorId: req.body.preverus_visitor_id,
    idempotencyKey: req.id,
  },
);

if (decision.recommended_action === "block" || decision.recommended_action === "deny") {
  res.status(403).send("Unable to create account.");
  return;
}

if (decision.recommended_action === "review") {
  res.redirect("/verify");
  return;
}

Prefer risk_session_token when available. It links the trusted backend action to the browser session collected moments earlier.

Configuration

const preverus = createPreverusNode({
  serverKey: process.env.PREVERUS_SERVER_KEY!,
  endpoint: "https://api.preverus.com",
  timeoutMs: 1500,
  retries: 2,
  retryDelayMs: 150,
  maxRetryDelayMs: 1000,
});

The client retries transient network failures and retryable statuses:

408, 409, 425, 429, 500, 502, 503, 504

It does not retry validation or authentication errors such as 400, 401, 403, or 422.

Use idempotency keys for retried POST requests.

Express Example

app.post("/register", async (req, res) => {
  const decision = await preverus.evaluate(
    {
      event_type: "signup",
      user_id: req.body.user_id,
      ip: req.ip,
      risk_session_token: req.body.preverus_risk_session_token,
      fingerprint: req.body.preverus_fingerprint,
      metadata: {
        email: req.body.email,
        user_agent: req.get("user-agent"),
      },
    },
    {
      visitorId: req.body.preverus_visitor_id,
      idempotencyKey: req.id,
    },
  );

  if (decision.recommended_action === "block" || decision.recommended_action === "deny") {
    return res.status(403).send("Unable to create account.");
  }

  if (decision.recommended_action === "review") {
    return res.redirect("/verify");
  }

  // Continue registration.
});

Next.js Route Handler Example

import { createPreverusNode } from "@preverus/node";
import { NextResponse } from "next/server";

const preverus = createPreverusNode({
  serverKey: process.env.PREVERUS_SERVER_KEY!,
});

export async function POST(request: Request) {
  const body = await request.json();
  const decision = await preverus.evaluate(
    {
      event_type: "checkout",
      user_id: body.user_id,
      ip: request.headers.get("x-forwarded-for")?.split(",")[0],
      risk_session_token: body.preverus_risk_session_token,
      fingerprint: body.preverus_fingerprint,
      metadata: {
        email: body.email,
        order_id: body.order_id,
      },
    },
    {
      visitorId: body.preverus_visitor_id,
      idempotencyKey: request.headers.get("x-request-id") ?? crypto.randomUUID(),
    },
  );

  if (decision.recommended_action === "block" || decision.recommended_action === "deny") {
    return NextResponse.json({ error: "blocked" }, { status: 403 });
  }

  return NextResponse.json({ decision });
}

Events

Use events for non-blocking fraud telemetry:

await preverus.trackEvent(
  {
    event_type: "login",
    user_id: "acct_42",
    ip: "203.0.113.10",
    fingerprint: "fp_hash",
    metadata: { email: "[email protected]" },
  },
  { visitorId: "v_abc123", idempotencyKey: "login:acct_42:req_123" },
);

Lookups

const visitor = await preverus.lookupVisitor({ visitorId: "v_abc123" });
const visitorByFingerprint = await preverus.lookupVisitor({ fingerprint: "fp_hash" });

const metadata = await preverus.lookupMetadata({ key: "email", value: "[email protected]" });
const graph = await preverus.metadataGraph({ visitorId: "v_abc123" });

const userRiskProfile = await preverus.lookupUserRiskProfile({ externalUserId: "acct_42" });

Use lookups for investigation and context. Use evaluate() for final enforcement.

Webhook Verification

Use the raw request body for verification.

const valid = preverus.verifyWebhook({
  rawBody,
  timestamp: req.get("X-Fraud-Webhook-Timestamp") ?? "",
  signatureHeader: req.get("X-Fraud-Webhook-Signature") ?? "",
  secret: process.env.PREVERUS_WEBHOOK_SECRET!,
});

if (!valid) {
  res.status(400).send("Invalid signature");
  return;
}

Webhook delivery is at-least-once. Dedupe by X-Fraud-Webhook-Id or payload id.

You can also verify, parse, and dispatch by event type:

const event = preverus.constructWebhookEvent({
  rawBody,
  headers: req.headers,
  secret: process.env.PREVERUS_WEBHOOK_SECRET!,
});

if (await alreadyProcessed(event.id)) {
  res.status(204).end();
  return;
}

await preverus.dispatchWebhook(event, {
  'decision.high_risk': async (event) => {
    await openCase(event.payload);
  },
  '*': async (event) => {
    console.log('Preverus webhook', event.type);
  },
});

The package verifies and parses the event, but your app should store processed event IDs in your database or cache.

Failure Handling

The package throws ApiError and NetworkError:

import { ApiError, NetworkError } from "@preverus/node";

try {
  const decision = await preverus.evaluate(...);
} catch (error) {
  if (error instanceof ApiError) {
    console.warn(error.statusCode, error.errorCode);
  }
  if (error instanceof NetworkError) {
    // Apply your app's fail-open, fail-review, or fail-closed policy.
  }
}

For high-risk flows like withdrawals and payouts, a common policy is fail-review. For signup/login/checkout, many businesses prefer fail-open so the site keeps working during transient failures.

Production Checklist

  • Never import this package into browser code.
  • Keep PREVERUS_SERVER_KEY private.
  • Use the browser key only with the hosted script or browser SDK.
  • Prefer risk_session_token when present.
  • Include visitorId when available.
  • Send your real customer account ID as user_id.
  • Include IP and metadata such as email, phone, username, and payment address.
  • Use idempotency keys for retried POST requests.
  • Treat review as step-up/manual review, not as automatic allow.