Skip to main content

What you will build

Conflicting same-device applications need review. This is an illustrative application policy, not a default rule that ShieldLabs applies to every customer.

Run the starting application

You need Node.js 22 or later. The starter runs without ShieldLabs keys; the final version needs a registered HTTPS hostname and matching keys. Clone the public tutorial repository, then start this standalone application:
Open http://127.0.0.1:3000. The starter has no ShieldLabs dependency or identification check. Its own SQLite state is separate from every other tutorial.

Add the integration

Stop the starter server. Follow these changes, then run the complete implementation from the final branch.
1

1. Prepare the keys and HTTPS hostname

The .env copied from starter contains no key entries yet. Add the two lines below with this domain’s real values:
Register the app’s hostname in Integration > Domains. Put its matching Public Key and Private API Key in the private loan-risk/.env as SHIELDLABS_PUBLIC_KEY and SHIELDLABS_API_KEY. Serve this app through HTTPS on that registered hostname. The Private API Key stays on the server; a customer key does not automatically authorize localhost.
2

2. Identify the action in the browser

The public/index.html page loads the locally served JS SDK. In public/index.js, each action takes a fresh Request ID and sends it with the action:
Only the Request ID goes to the server; the browser does not supply the risk result.
3

3. Verify the identification on the server

server/shieldlabs.js uses @shieldlabs-ai/node and the Private API Key to find that exact Request ID in History. The action route passes it to server/loans.js, where verifyIdentification(requestId) rejects missing, stale, replayed, automated or unusable checks before this scenario’s rule is applied.
4

4. Apply the loan application review rule

This excerpt from server/loans.js shows the decision’s core:
server/loans.js compares applications from the same Device ID over 24 hours. A changed name or income is saved as flagged and sent to manual review without an offer; the sample affordability check is separate.
5

5. Run the completed application

From the repository root, compare the two versions and start the final app:
A fresh clone has the remote origin/final ref even before its local final branch exists. Open the completed app through the registered HTTPS hostname. The Node server listens on 127.0.0.1:3000 behind your reverse proxy.

Follow the integration code

The completed source is in the loan-risk application. Read these files in order:
  1. Browser helper: loads the installed SDK, serializes checks and returns a request ID.
  2. Server verification: reads real History, checks the matching ID, rereads delayed results and rejects unusable or replayed checks.
  3. Scenario decision: applies this app’s rule using the verified identification and stores its sample state.
The finished application keeps its browser, server and SQLite state inside this folder. The tests use synthetic History responses; the normal server does not manufacture a successful identification.

Try the completed application

  1. Enter invented applicant details, a valid amount and term, then submit. The demo calculates a sample result.
  2. Change the name or income on the same observed device and submit with a fresh Request ID.
  3. The new application is flagged for manual review. No real lending or credit decision occurs.
Use Reset demo DB with DEMO_ALLOW_RESET=1 to repeat the exercise. These controls are for a disposable demonstration, not production authorization.

Check your result

In DevTools Network, inspect the /api/applications request and copy its requestId. Check the two Request IDs in History and verify they share a Device ID. The second application’s local status should be flagged, not approved. Run npm run check and npm test from loan-risk to exercise failure cases locally without making more identifications. For a real run, obtain fresh request IDs in the browser and confirm their Device IDs and signals in History. If identification returns HTTP 429, stop and check your account limits before retrying. A cookie change does not prove that the Device ID changed: compare the History rows.

Adapt it to your product

This example is a starting point, not a production-ready authorization system. Bind each action to an authenticated session where appropriate, authorize administration screens, persist state and atomically consume request IDs across all server instances. Review legitimate shared-device behavior before applying a device-based restriction. See Acting on results.