/trace call (one backend call after authentication) unlocks the per-user signals that detect a real account accessed from a new country, a new device, or an impossible location. You need both to fully close the gap.
Which event this protects
ATO maps to thelogin event. The Worker fires it on every POST to your login route. The in-app call fires it again after your authentication handler runs, this time with the confirmed subject_user_id and real status.
How it works
Edge layer (no code)
The Worker fires on every POST to your login route:- Reads the submitted email and IP.
- Attaches the device fingerprint from the
x-tn-device-tokenheader. - Calls
/tracewithevent: login, status: attempted. - Evaluates your ATO policy against velocity and device/IP signals.
deny→ blocks at the edge.challenge/allow→ forwarded to origin.
subject_user_id is null because no one is authenticated yet. User-keyed signals (velocity.user.*, is_new_for_user, is_new_country_for_user) fall back to the submitted email. That’s enough to catch stuffing and bots, but not enough to catch a legitimate-looking login from a stolen password.
In-app layer (one backend call)
After your authentication handler confirms the password and issues a session, send a second/trace with the real subject_user_id and confirmed status. This call unlocks the full per-user signal set. The edge trace is already in the system, so this merges the history correctly.
Act on the verdict immediately: challenge means require step-up (MFA, CAPTCHA); deny means block the session.
Signals used
See Signals for the full field reference.
Set it up
1
Connect Cloudflare (if you haven't already)
In the dashboard under Integration, paste a Cloudflare API token with Workers Scripts: Edit
and Zone → DNS: Read scopes. tracenow validates the token and lists your zones.
2
Add a route rule for your login endpoint
Under Integration → Routes, add a rule:
- Route pattern: e.g.
yourdomain.com/api/auth/loginoryourdomain.com/login - Method:
POST - Event:
login - Response mapping: map HTTP
200→succeeded,401/403→failed - Mode: start with
Monitor
succeeded/failed status.3
Enable the Account takeover policies
Under Guard, enable the pre-built Account takeover policy templates for the
login event in Monitor mode. To customize or add your own rules, see Rules.4
Add the in-app call for full per-user coverage
In your authentication handler, after confirming credentials and resolving the user, call
/trace with the real subject_user_id and confirmed status. See Going further below.This is what unlocks new-device, new-country, impossible-travel, and distinct-IP signals.5
Switch to Enforce mode
After reviewing Monitor traces, go to Integration → Routes, change the login route to
Enforce, and click Deploy.In Enforce mode, only
deny verdicts are enforced at the edge. challenge verdicts flow to your origin; enforce them in your authentication handler via the in-app call verdict.Rules
You don’t build these by hand. The pre-built Account takeover policy templates cover these patterns and enable in one click. See Rules to customize them or add your own.What a caught attempt looks like
A stuffing wave produces many traces like this in the event feed: A suspicious successful login (new country) looks different:Going further
The edge layer stops bots and stuffing without per-user history. The in-app call is what makes tracenow aware of this specific user’s normal behavior: their usual countries, devices, and login patterns. Add this call to your authentication handler after you’ve confirmed the user’s identity:subject_user_id, signals like ip.is_new_country_for_user, ip.impossible_travel, device.is_new_for_user, and velocity.user.distinct_ips_24h have no per-user history to compare against. With it, tracenow builds a behavioral baseline per account from the first login.
See server-side integration for the full request and response reference.