Skip to main content
tracenow protects your app at two layers: an edge layer (no code, via Cloudflare) and an in-app layer (one backend call). Both layers call the same /trace endpoint. Together they cover every attack surface: bots and bad inputs at the door, per-user account-takeover signals inside your app.

The two layers

Edge (no code)

A managed Cloudflare Worker on your zone intercepts every login, signup, and OTP before it reaches your app. It injects the device fingerprint script, extracts signals, and calls /trace. On deny, it blocks at the edge. No code required.

In-app (one call)

After you authenticate the user, call /trace from your backend with the real subject_user_id and confirmed status. This unlocks per-user signals the edge can never see: new device for this account, impossible travel, per-user failed-login velocity.
The edge cannot know who is logging in because the user isn’t authenticated yet. The in-app call fills that gap with one small backend call after authentication.
You can start with the edge today (no code, no deploy) and add the in-app call later. The device token is already on the request as x-tn-device-token, so there’s nothing extra to wire up on the frontend.

Architecture

Request lifecycle (edge layer)

Here is the full sequence for a protected route in Enforce mode.

What happens at each step

1

Inject trace.min.js

The Worker serves the device fingerprint script from a path on your own domain. The script runs in the browser, collects device signals (canvas, timing, automation indicators), and calls /identify.
2

Classify the event

The Worker checks if the request matches a configured route and method. GET requests are not monitored by default. Matched requests are classified as login, signup, or otp.
3

Extract signals and call /trace

The Worker reads the email/phone from the request body, the IP from headers, and the device token from x-tn-device-token (or tn_device_token form field). It calls POST /trace synchronously (Enforce mode) or asynchronously (Monitor mode).
4

Enforce the verdict

In Enforce mode: deny → return the configured block response (default 403, or a custom status, redirect, or body). allow and challenge → forward to origin. In Monitor mode: always forward; the trace is logged.
5

Outcome trace (async, non-blocking)

After the origin responds, the Worker fires a second /trace call to record the real outcome, mapping the HTTP response code to succeeded or failed. This is what powers failed-login velocity rules at the edge. It does not block the user.
The Cloudflare Worker cannot render your app’s MFA or CAPTCHA flow. A challenge verdict is always forwarded to your origin. Handle step-up friction in your app. Only deny blocks at the edge.

Fail-open

If /trace is slow or unreachable, the Worker forwards the request to your origin without enforcing. tracenow never breaks your site.

The device-token round-trip

Device fingerprinting is stateful: the injected script collects signals, fetches a device token from /identify, and the browser attaches that token to every subsequent same-origin request automatically, as the x-tn-device-token header or tn_device_token form field. You never manage this. The Worker injects the script, the script fetches the token, and the token arrives at your server as a request header. When you make the in-app /trace call, you just read it off:
The device token lets tracenow recognize the same physical device across sessions and users. This is what powers device.is_new_for_user, device.automation_detected, and velocity.device.distinct_user_ids_24h.

How /identify and /trace relate

/identify and /trace are two distinct calls with distinct purposes: You never call /identify yourself. The Worker injects the script that calls it. The device token the script receives is what you (or the Worker) forward to /trace as device_token.

In-app layer: the one call that adds per-user depth

Call POST /trace from your backend after authenticating the user. Pass the real subject_user_id and the confirmed status. These are things the edge will never know.
TypeScript (Node)
Per-user signals that only unlock here:
  • device.is_new_for_user: this device has never been seen for this account
  • ip.is_new_country_for_user: login from a country this user has never used
  • ip.impossible_travel: physically impossible to have moved between the last location and this one
  • velocity.user.*: counts scoped to this specific user ID

Where to go next

Verdicts

What allow, challenge, and deny mean, and how to handle each in your app.

Cloudflare integration

Connect Cloudflare, configure route rules, and deploy the Worker.

Rules and policies

Build conditions that trigger challenge or deny: fields, operators, logic.

Server-side integration

The full in-app /trace contract, every field, and verdict handling patterns.