Conçu pour s'intégrer à votre stack
REST simple avec un seul en-tête, un client Node typé, un serveur MCP, des webhooks signés et des domaines personnalisés. Rien à installer sur votre serveur, sauf si vous le souhaitez.
Cinq façons de commencer
Le même événement, depuis un shell, votre code, un assistant ou un push.
curl "https://api.zeno.id/events/1792578564800.yU4Ety" \
-H "Auth-API-Key: sk_..."const event = await fetch(`https://api.zeno.id/events/${requestId}`, {
headers: { 'Auth-API-Key': process.env.FP_SECRET_KEY },
}).then(response => response.json())import { createClient } from '@zeno-id/server'
const fingerprint = createClient({ secretKey: process.env.FP_SECRET_KEY, endpoint: 'https://api.zeno.id' })
const event = await fingerprint.getEvent(requestId)
const page = await fingerprint.searchEvents({ externalId: user.id, signal: 'vpn' })
await fingerprint.updateEvent(requestId, { action: 'checkout' })
await fingerprint.forgetExternalId(user.id)# Your project's API as tools for Claude Code, Cursor or any MCP client.
claude mcp add zeno --env FP_SECRET_KEY=sk_... --env FP_ENDPOINT=https://api.zeno.id -- npx -y @zeno-id/mcpimport { verifyWebhook } from '@zeno-id/server'
app.post('/fingerprint', express.text({ type: 'application/json' }), (request, response) => {
if (!verifyWebhook(request.body, request.header('fingerprint-signature') ?? '', process.env.FP_WEBHOOK_SECRET)) {
return response.sendStatus(401)
}
const event = JSON.parse(request.body)
response.sendStatus(200)
})// Serve the agent and identify from a subdomain of your own site, so content
// blockers that list ours don't drop identifications. Add it in Settings ›
// Custom domain, create the one DNS record it shows, then:
import { start } from 'zeno-id'
const agent = start({ publicKey: 'pk_...', endpoint: 'https://metrics.example.com' })- API serveur Lisez, recherchez et supprimez événements et visiteurs avec un seul header.
- SDK serveur Client Node typé avec vérification des webhooks et ouverture des résultats scellés.
- Serveur MCP L'API de votre projet sous forme d'outils pour un assistant IA.
- Webhooks Chaque nouvel événement envoyé en POST à votre serveur, signé, avec nouvelles tentatives.
- Domaine personnalisé Servez l'agent depuis un sous-domaine du vôtre avec un seul enregistrement DNS, comme tout site en production devrait le faire.
- Résultats scellés Un résultat chiffré que votre serveur ouvre sans appeler l'API.
L'agent sur chaque page
Démarrez-le à l'ouverture du formulaire et demandez un request ID dès que l'utilisateur agit. Il s'exécute en arrière-plan sans jamais bloquer la page.
- Aucune dépendance
- /agent.js comme balise script pour essayer, ou un petit chargeur npm qui récupère l'agent actuel via votre propre domaine.
- Tout framework
- React, Svelte, Vue, Next.js, Nuxt, Angular, ou aucun.
- Environ un kilo-octet
- Le rapport qu'il envoie. Il ne lit jamais les adresses réseau WebRTC.
- En cache
- Un résultat peut être conservé pour la session, ainsi la connexion et le paiement qui suit ne coûtent qu'une identification.
<script src="https://zenocdn.net/agent.js"></script>
<script>
const agent = FingerprintAgent.start({ endpoint: 'https://zenocdn.net', publicKey: 'pk_...' })
// Once the user logs in, hand the request ID to your server:
agent.get({ externalId: user.id }).then(({ requestId }) => verifyOnServer(requestId))
</script>Vos données, vos règles
Conçu pour les demandes de données que vous recevrez.
Hébergé dans l'UE
Les événements sont stockés sur AWS eu-west-1 jusqu'à ce que vous les supprimiez, ou pendant 1, 3 ou 5 ans si vous choisissez cette option.
Supprimer un external ID en un seul appel
Supprimer un ID externe supprime tous ses événements et liens d'appareil, pour une demande de données ou un compte fermé.
Rien sur quoi le navigateur puisse s'appuyer
Les flags n'atteignent jamais le navigateur. Le mode zero trust va plus loin : le navigateur ne reçoit qu'un request ID.
Votre première identification, en quelques minutes
Une public key dans le navigateur, une secret key sur votre serveur.