Skip to main content
Checkout is a high-friction action with a real revenue cost for false positives. Treat Tripwire as one signal alongside your existing fraud stack (Stripe Radar, Sift, a custom rules engine) rather than a standalone blocker. The most useful field on this surface isn’t the top-level verdict — it’s decision.manipulation.

The threat

Payment fraud at checkout comes in a few shapes, and Tripwire is relevant to a subset:
  • Card testing. Script runs a stolen card list against a cheap SKU, looking for valid cards. This is high-volume and very automation-shaped — Tripwire catches it well.
  • Account-based carding. Attacker takes over an account with a saved card and checks out from a real browser. Account takeover is a login problem; see Login & credential stuffing. Once they’re logged in and paying, Tripwire mostly contributes manipulation evidence rather than a bot verdict.
  • Reshipping / mule fraud. A real human at a real keyboard using a stolen card. Tripwire will return human and that’s correct — this is a chargeback and identity problem, not a bot problem.
Integration strategy: pass Tripwire evidence into the same decision that already consumes your payment processor’s risk score. Don’t block on Tripwire alone unless you’re seeing decision.verdict === "bot" on a checkout, which is specifically a card-testing signal.

The flow

1

Start Tripwire when the cart page loads

Users often land on checkout directly from email or a deep link, so start as early as you can in the journey.
2

Best-effort waitForFingerprint()

Gate submission on it if you can, but don’t hang the UI forever — users arriving hot should still be able to pay.
3

Call getSession() at payment submit

Right before the PaymentIntent confirm (or equivalent) fires.
4

Verify and extract fraud-relevant fields

Pull decision.verdict, decision.risk_score, and decision.manipulation.verdict before the payment gateway call.
5

Attach metadata to the payment

Put sessionId on the PaymentIntent so your fraud team can correlate Tripwire and processor evidence later.

Client integration

Race waitForFingerprint() with a short deadline so slow or failed fingerprinting doesn’t block a sale.
<script type="module">
  const tripwirePromise = import("https://cdn.tripwirejs.com/t.js").then(
    (Tripwire) =>
      Tripwire.start({
        publishableKey: "pk_live_your_publishable_key",
      }),
  );

  async function waitForFingerprintWithTimeout(tripwire, ms) {
    return Promise.race([
      tripwire.waitForFingerprint(),
      new Promise((resolve) => setTimeout(resolve, ms)),
    ]);
  }

  async function submitPayment(formData) {
    const tripwire = await tripwirePromise;
    await waitForFingerprintWithTimeout(tripwire, 2000);

    const { sessionId, sealedToken } = await tripwire.getSession();

    return fetch("/api/checkout", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        ...formData,
        tripwire: { sessionId, sealedToken },
      }),
    });
  }
</script>
If the timeout fires before fingerprint freeze, getSession() still returns a handoff — the verified result just won’t carry a durable visitor_fingerprint, and the score will lean more on environment and behavioral signals. That’s a worse input than a fully-frozen session, but it’s still useful, and it’s vastly better than failing the checkout.

Server verification and fraud-stack handoff

The example below uses Stripe. The pattern is identical with any processor: compute Tripwire’s signal, pass it in as metadata alongside the payment, and let your fraud rules engine combine it with the processor’s own risk score.
const Stripe = require("stripe");
const { safeVerifyTripwireToken } = require("@abxy/tripwire-server");
const stripe = Stripe(process.env.STRIPE_SECRET_KEY);

app.post("/api/checkout", async (req, res) => {
  const result = safeVerifyTripwireToken(
    req.body.tripwire.sealedToken,
    process.env.TRIPWIRE_SECRET_KEY,
  );

  // Card testing is near-100% automation. A bot verdict here is almost
  // always right — block before touching the payment processor.
  if (result.ok && result.data.decision.verdict === "bot") {
    return res.status(403).json({ error: "Payment declined" });
  }

  // Everything else goes to the processor with Tripwire signal attached.
  const decision = result.ok ? result.data.decision : null;
  const intent = await stripe.paymentIntents.create({
    amount: req.body.amountCents,
    currency: "usd",
    payment_method: req.body.paymentMethodId,
    confirm: true,
    metadata: {
      tripwire_session_id: req.body.tripwire.sessionId,
      tripwire_verdict: decision?.verdict ?? "unavailable",
      tripwire_risk_score: decision?.risk_score?.toFixed(3) ?? "unavailable",
      tripwire_manipulation: decision?.manipulation?.verdict ?? "unavailable",
    },
  });

  res.json({ intent });
});

The manipulation score

decision.manipulation is distinct from the top-level verdict and often more relevant at checkout.
FieldTypeMeaning
decision.manipulation.scorenumber | null0–1 measure of active environment tampering (spoofed user agent, patched navigator properties, canvas/audio noise injection, anti-detect browsers).
decision.manipulation.verdict"none" | "low" | "medium" | "high" | nullBucketed version of the score.
A real customer with a legitimate card has manipulation.verdict === "none". A sophisticated fraudster using an anti-detect browser (Multilogin, GoLogin) to make the same account look like a new device on every checkout will score medium or high — even when they pass decision.verdict === "human" because the behavioral signals look real. Feed both into your rules engine. A reasonable starter policy:
  • decision.verdict === "bot" → decline.
  • decision.manipulation.verdict === "high" → always send to manual review.
  • decision.manipulation.verdict === "medium" + processor risk elevated → decline or step up to 3-D Secure.
  • Otherwise → follow the processor’s decision.

Correlating later

Putting tripwire_session_id (and the verdict snapshot) on the PaymentIntent pays off when you investigate a chargeback weeks later. Stripe’s metadata surfaces in the dashboard, and you can pull the durable Tripwire session back via GET /v1/sessions/:sessionId with your secret key to recover the full fingerprint, attribution, and signal list. See Server verification for the readback shape.

What’s next

Login protection

Stop credential stuffing before it reaches checkout.

Signup protection

Block account-based carding at the account-creation step.

Verdicts & scoring

Deep-dive on risk_score and manipulation.

Going to production

Rollout plan for enforcement on a revenue-critical surface.