Skip to main content
Most recipes in this Cookbook use the Risk Score to raise friction on a suspicious visit. This one runs the same machinery in the opposite direction: a visit that arrives clean and on a device you already trust is a good moment to remove friction, not add it. You can skip a redundant check, restore preferences, or smooth the path for someone who has been here before. The two ingredients are already in every webhook: a low Risk Score and a durable DeviceID. When both point at a device you have associated with a verified account, treat the visit as a recognized return. When either is missing, fall back to your normal flow with no downside.
This recognizes a device, not a person. It is a convenience signal, not a credential, and you should read the guardrails at the end of this page before you wire it to anything sensitive.

Why the DeviceID makes this work

The DeviceID is server-derived and durable. ShieldLabs computes it from the browser itself, so it stays stable when a visitor clears cookies, opens an incognito window, or rotates their IP. A returning person on the same browser keeps the same DeviceID even after their cookie resets, which is exactly the case where a cookie-only “remember me” falls apart. The Identification reference covers how the DeviceID and VisitorID differ and which one survives what. That durability is what lets you recognize a return without asking the visitor to log in again first. The DeviceID arrives on the webhook, or you can read it back from the History API by request_id, alongside the Risk Score for that same visit.

The pattern

1

Identify on the page

Load the snippet where the return matters, for example a returning visitor landing on your app or starting a routine action. Keep the requestID to join the browser check to the webhook.
2

Receive the score and DeviceID

Verify the webhook and read the visit back by RequestID. The same Data object carries both the Score and the DeviceID you will match on.
3

Match a clean DeviceID to a trusted account

If the score lands in the Clean band with no anonymity signals, and the DeviceID is one you have already associated with a verified account, treat it as a recognized returning device.
4

Lighten the experience

Skip a redundant step, restore preferences, or shorten the path. If the device is new or the score is not clean, run your normal flow unchanged.

Step 1: associate a DeviceID with a trusted account

Recognition only works once you have something to recognize. The association is yours to build: whenever a visitor completes a real, authenticated action you trust (a login behind your own auth, a verified purchase, an email confirmation), store the DeviceID that arrived on that visit against that account.
Build the trust list on a verified action
// Call this from a flow you already trust: a successful login, a confirmed
// purchase, an email verification. The DeviceID rides in on the same webhook.
async function rememberTrustedDevice(accountId, shield) {
  // Only remember devices seen on a clean, signal-free visit. Anything else
  // is noise you do not want to recognize later.
  if (shield.score > 9 || shield.details.length > 0) return;

  await trustedDevices.add({
    accountId,
    deviceId: shield.deviceID,
    firstSeen: Date.now(),
  });
}
Over time each account accumulates a small set of devices it has genuinely used. That set is the list you match against on the next visit.

Step 2: recognize the return

On the next visit, wait briefly for the score, then check two things together: the band and the device. A clean score on its own is an ordinary visit. A known DeviceID on its own is not enough either. The recognition is the intersection.
api/enter.js
app.post('/api/enter', async (req, res) => {
  const { accountId, shieldRequestId } = req.body;

  // Poll the cache, then fall back to a History API read by request_id.
  const shield = await waitForScore(shieldRequestId, 2000);

  // No score yet is not the same as "trusted". When in doubt, run the full flow.
  if (!shield) return res.json({ recognized: false });

  // A Clean band (0-9) with no anonymity signals is a low-risk, ordinary visit.
  const isClean = shield.score <= 9 && shield.details.length === 0;

  // Is this DeviceID one we already tied to this verified account?
  const isKnownDevice = await trustedDevices.has(accountId, shield.deviceID);

  if (isClean && isKnownDevice) {
    // Recognized returning device: lighten the experience.
    // Skip a redundant check, restore preferences, smooth the path.
    return res.json({ recognized: true, deviceId: shield.deviceID });
  }

  // New device, or a score that is not clean: your normal flow, unchanged.
  return res.json({ recognized: false });
});
waitForScore is the shared webhook-cache read (poll the cache, then fall back to a History API read by request_id); the Cookbook defines it once alongside the handler that populates the cache, so this recipe does not repeat it.
Match on the band plus the DeviceID, never the DeviceID alone. A returning device with a Medium or High score is a returning device on a riskier connection, and the riskier connection is the part that should drive your decision.

What “lighten the experience” can mean

Recognition buys you room to remove friction for a known-good return. A few safe places to spend it:
  • Skip a redundant check. A second-factor prompt that the same trusted device already cleared this week can be relaxed, while staying on for anything sensitive.
  • Restore preferences. Re-apply the visitor’s layout, language, or saved cart before they ask.
  • Shorten the path. Pre-fill what you already know for this device, or drop a returning visitor straight onto the screen they last used.
  • Soften rate limits. A recognized device earns more headroom than an anonymous one on the same endpoint.
Each of these is a convenience, and each one degrades gracefully: if recognition fails, the visitor simply gets your normal flow.

Guardrails

A returning device is a convenience signal, not a credential. State the limits plainly and design around them.
  • This recognizes a device, not a person. Anyone using that browser inherits the recognition. A shared family laptop or a borrowed machine will match.
  • It is probabilistic, an estimate, not proof of identity. ShieldLabs reports Accuracy as up to 99%, which is high enough to smooth a path and far too low to be the only thing standing between a stranger and an account.
  • Never make it the sole gate for anything sensitive. Money movement, password and email changes, and data exports must always sit behind real authentication. Pair recognition with a login, a second factor, or a re-verification step. Use it to remove a redundant step, never to remove the only step.
  • Fail closed. No score, a new device, or a non-clean band all fall back to your full flow. Recognition is the bonus, not the baseline.
Read this the way you would a “remember this device” checkbox: it makes the common case pleasant for people you already trust, and it carries no authority of its own.

Next

Tighten the friction direction with Step-up 2FA on Risky Logins, which uses the same Score and DeviceID to raise friction when a session is not clean.