Skip to main content

Environments

We recommend creating a separate domain in the ShieldLabs dashboard for each environment.
EnvironmentDomainDashboard
Developmentdev.example.comdev.account.shieldlabs.ai
Stagingstaging.example.comaccount.shieldlabs.ai
Productionexample.comaccount.shieldlabs.ai
Each domain gets its own public key (32 hex chars), 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 via the Dashboard or JWT API:
curl -X PUT "https://dev.account.shieldlabs.ai/api/domains/{domain_id}/webhook" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"callback": "https://abc123.ngrok.io/shieldlabs/webhook"}'
Alternative (Core Management API):
curl -X POST "https://dev.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=a3f8c2d1e9b0476a8c5d2f1e0b9a8c7d
SHIELD_SECRET=7e4b9a2c8d1f6e0a3b5c9d2e7f4a1b8c

# .env.production
SHIELD_PUBLIC_KEY=...
SHIELD_SECRET=...
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;
}