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

synclay-fraud-shield

v1.0.1

Published

Synclay Fraud Shield SDK for Next.js and modern e-commerce storefronts

Readme

synclay-fraud-shield

Synclay Fraud Shield — drop-in checkout protection for Next.js and modern e-commerce storefronts.

Score every order with Bangladesh courier success rates, device signals, behavior heuristics, OTP, and Turnstile — without building fraud infra yourself.

npm install synclay-fraud-shield

How it works

sequenceDiagram
  participant Shopper
  participant Next as Your Next.js app
  participant SDK as Fraud Shield SDK
  participant API as Synclay Connect API

  Shopper->>Next: Open checkout
  Next->>SDK: boot() → POST /api/fraud-shield/initial
  SDK->>API: POST /v1/connect/fraud/initial (PAT)
  API-->>SDK: ALLOW / BLOCK
  Shopper->>Next: Place order
  Next->>SDK: evaluate(phone, …)
  SDK->>API: POST /v1/connect/fraud/check
  alt OTP / Captcha
    API-->>SDK: OTP_REQUIRED / captchaRequired
    Shopper->>SDK: Complete challenge
  else Clean
    API-->>SDK: ALLOW
    Next->>Next: Create order
  end

Your Personal Access Token stays on the server. The browser only talks to your Next.js route handlers.


1. Environment

# Server only — never NEXT_PUBLIC_
SYNCLAY_API_KEY=sc_live_xxxxxxxx
SYNCLAY_SHOP_ID=your_shop_id

# Optional (default https://api.synclay.com)
# SYNCLAY_API_BASE_URL=https://api.synclay.com

Create a PAT in Synclay with scope connect:fraud:read (or connect:*).

Turnstile (captcha challenges)

Load Cloudflare Turnstile in your app root / layout — the SDK never injects remote scripts:

// app/layout.tsx
import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Script
          src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"
          strategy="afterInteractive"
        />
      </body>
    </html>
  );
}

2. Next.js App Router — one API file

// app/api/fraud-shield/[action]/route.ts
import { createFraudShieldHandlers } from "synclay-fraud-shield/next";

const handlers = createFraudShieldHandlers({
  apiKey: process.env.SYNCLAY_API_KEY!,
  shopId: process.env.SYNCLAY_SHOP_ID!,
  baseUrl: process.env.SYNCLAY_API_BASE_URL, // optional
});

export const GET = handlers.GET;
export const POST = handlers.POST;

Routes created for you:

| Method | Path | Purpose | |--------|------|---------| | GET | /api/fraud-shield/config | Settings + Turnstile site key | | POST | /api/fraud-shield/initial | Early IP / blocklist check | | POST | /api/fraud-shield/check | Full checkout evaluation | | POST | /api/fraud-shield/otp-send | Send OTP | | POST | /api/fraud-shield/otp-verify | Verify OTP | | POST | /api/fraud-shield/captcha-verify | Verify Turnstile |


3. Checkout UI

// app/checkout/page.tsx  (or your checkout component)
"use client";

import "synclay-fraud-shield/styles.css";
import {
  FraudShieldProvider,
  FraudChallenge,
  FraudHoneypot,
  useFraudShield,
} from "synclay-fraud-shield/react";

function CheckoutForm() {
  const { evaluate, status, sessionToken, blocked } = useFraudShield();

  async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    if (blocked) return;

    const fd = new FormData(e.currentTarget);
    const result = await evaluate({
      phone: String(fd.get("phone") || ""),
      email: String(fd.get("email") || ""),
      name: String(fd.get("name") || ""),
      address: String(fd.get("address") || ""),
      orderTotal: Number(fd.get("total") || 0),
    });

    // Wait for OTP / captcha UI if challenged
    if (!result || result.blocked || result.decision !== "ALLOW") return;

    // Attach session token to the order for Synclay learning / analytics
    await fetch("/api/orders", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        /* …cart… */
        synclaySessionToken: sessionToken,
      }),
    });
  }

  return (
    <>
      <form onSubmit={onSubmit}>
        <input name="phone" data-synclay-field="phone" required />
        <input name="email" data-synclay-field="email" type="email" />
        <input name="name" data-synclay-field="name" />
        <textarea name="address" data-synclay-field="address" />
        <FraudHoneypot />
        <button type="submit" disabled={status === "checking" || blocked}>
          {status === "checking" ? "Securing…" : "Place order"}
        </button>
      </form>

      <FraudChallenge
        phone={/* same phone state */}
        onResolved={() => {
          /* re-submit or continue checkout */
        }}
      />
    </>
  );
}

export default function CheckoutPage() {
  return (
    <FraudShieldProvider>
      <CheckoutForm />
    </FraudShieldProvider>
  );
}

Mark checkout inputs with data-synclay-field so typing / paste behavior is scored automatically.


4. Server-only client (no React)

import { createFraudShield, createFraudShieldFromEnv } from "synclay-fraud-shield";

const shield = createFraudShieldFromEnv(process.env);
// or: createFraudShield({ apiKey, shopId })

const result = await shield.check({
  phone: "01712345678",
  sessionToken: "…",
  orderTotal: 1490,
});

if (result.decision === "BLOCK") {
  // reject order
}

Package exports

| Import | Use | |--------|-----| | synclay-fraud-shield | Core client, types, session helpers | | synclay-fraud-shield/next | createFraudShieldHandlers | | synclay-fraud-shield/react | Provider, hooks, challenge UI, honeypot | | synclay-fraud-shield/styles.css | Challenge modal styles |


Decisions

| decision | Meaning | |------------|---------| | ALLOW | Safe to place the order | | BLOCK | Reject checkout | | OTP_REQUIRED | Show phone OTP (FraudChallenge) | | captchaRequired: true | Show Turnstile |

Scores and signals (finalScore, triggeredSignals) are returned for logging / admin UI.


Security checklist

  • Keep SYNCLAY_API_KEY server-side only
  • Prefer fail-closed settings in the Synclay dashboard for high-risk stores
  • Always send sessionToken with the created order (_synclay_session_token / meta) so Synclay can learn from outcomes
  • Never call api.synclay.com with your PAT from the browser

Local development

cd packages/fraud-shield
npm install
npm run build

Point SYNCLAY_API_BASE_URL at your local API when testing against a local Synclay stack.


License

MIT © Synclay