Nuxt gives you a browser app and a Nitro server in one project, which maps perfectly onto how device intelligence should work: collect the signal in the client, decide on the server. Adding Prynt gives every sensitive action a verifiable visitor ID and bot score.
This guide wires Prynt into Nuxt 3 as a client plugin, exposes it through a composable, and verifies events inside a Nitro route. Because Nuxt owns both halves of the request in one codebase, you avoid the usual friction of coordinating a separate frontend and backend for something as cross-cutting as fraud signals.
Load the agent in a client plugin
A .client.js plugin loads the agent once, in the browser only, and makes it available through Nuxt’s injection helper.
// plugins/prynt.client.js
import Prynt from '@prynt/js'
export default defineNuxtPlugin(async () => {
const agent = await Prynt.load({
apiKey: useRuntimeConfig().public.pryntKey,
endpoint: 'https://api.pryntid.com'
})
return { provide: { prynt: agent } }
})
Expose the public key through runtimeConfig.public. Loading is asynchronous and never blocks hydration.
Identify with a composable
Wrap identification in a composable so components stay clean and reuse the same logic.
// composables/usePrynt.js
export function usePrynt() {
const { $prynt } = useNuxtApp()
async function identify() {
const result = await $prynt.identify()
return result.requestId
}
return { identify }
}
A login page calls identify() on submit and sends the requestId with the credentials. The browser only gathers the signal.
Verify in a Nitro server route
Your server/api route looks up the event with the secret key and branches on the result. This is the trustworthy decision point.
// server/api/login.post.js
export default defineEventHandler(async (event) => {
const { pryntId } = await readBody(event)
const data = await $fetch(
`https://api.pryntid.com/v1/events/${pryntId}`,
{ headers: { Authorization: `Bearer ${process.env.PRYNT_SECRET}` } }
)
if (data.bot.result === 'automated') {
throw createError({ statusCode: 403, message: 'blocked' })
}
// store data.visitorId with the account
return { ok: true }
})
Persisting visitorId lets you spot one device farming many accounts. The available fields, including proxy and ASN intelligence, are in the bot detection guide.
Keep your secret key in runtimeConfig without the public prefix so it stays server-only and never leaks into the client bundle. This split is the whole point of the client-plugin plus Nitro-route pattern: the public key loads the agent in the browser, and the secret key verifies the result on the server, where a bot cannot reach it. If you deploy to an edge runtime, the same $fetch call to the Prynt API works unchanged, so the integration survives a hosting change without a rewrite.
Guard forms directly
For signup or contact forms, let Form Shield watch the element and add behavioral signals for scripted fills.
const { $prynt } = useNuxtApp()
$prynt.protectForm(document.querySelector('#signup'), {
autoGuard: true,
expectedScripts: ['latin']
})
expectedScripts flags submissions in unexpected writing systems, a low-cost signal against generic spam. Use it alongside server verification, not instead of it.
Route on the score
Use the score to branch rather than hard-block: clean sessions pass, borderline ones get a challenge. Because Prynt is a managed cloud service, geolocation, VPN detection, and bot scoring arrive with no infrastructure on your side, and the free tier covers early traffic while you validate the setup.
Add a key, drop in the plugin, and verify inside your Nitro routes. See the pricing and free plan to get started, and your Nuxt app will make fraud decisions on signals a bot cannot fake.
Try it free
Prynt is device intelligence with a free tier — visitor IDs, bot & fraud Smart Signals, and behavioral biometrics, powered by a cross-site network. Start free.