Environments
We recommend creating a separate domain in the ShieldLabs dashboard for each environment.
Recommended setup
| Environment | Domain | Public Key |
|---|
| Development | dev.example.com | SLPUB_dev_... |
| Staging | staging.example.com | SLPUB_staging_... |
| Production | example.com | SLPUB_prod_... |
Each domain gets its own public key, secret key, and webhook URL — so you can test without polluting production data.
Development: testing webhooks locally
Use ngrok or a similar tunnel to expose your local server:
ngrok http 3000
# → https://abc123.ngrok.io
Register the tunnel URL as your webhook:
curl -X POST "https://api.shieldlabs.ai/dev.example.com:YOUR_DEV_SECRET/callback" \
-H "Content-Type: text/plain" \
-d "https://abc123.ngrok.io/shieldlabs/webhook"
Environment variables
# .env.development
SHIELD_PUBLIC_KEY=d932476e-9f95-4ad9-820e-6f2118b1d27a
SHIELD_SECRET=89jb7aadzp6uuph5yo3pttw4
# .env.production
SHIELD_PUBLIC_KEY=a1b2c3d4-...
SHIELD_SECRET=xk9p2mzqwerty...
The SHIELD_PUBLIC_KEY is used in your frontend build. The SHIELD_SECRET must stay server-side only.
Next.js example
// lib/shield.js
export const SHIELD_PUBLIC_KEY = process.env.NEXT_PUBLIC_SHIELD_PUBLIC_KEY;
export const SHIELD_SECRET = process.env.SHIELD_SECRET; // server-side only
// components/ShieldTracker.jsx
'use client';
import { useEffect } from 'react';
import { SHIELD_PUBLIC_KEY } from '@/lib/shield';
export function ShieldTracker({ userHashedId }) {
useEffect(() => {
let cancelled = false;
(async () => {
const mod = await import(
`https://cdn.shieldlabs.ai/snippet.js?publicKey=${SHIELD_PUBLIC_KEY}`
);
if (!cancelled) {
userHashedId
? mod.checkAuthenticatedUser(userHashedId)
: mod.checkAnonymous();
}
})();
return () => { cancelled = true; };
}, [userHashedId]);
return null;
}