Installation
npm install @rlvt/web-sdk
No additional dependencies are needed. The Nuxt adapter uses structural typing — it does not import from the nuxt or h3 packages.
Setup
1. Create the client instance
// server/utils/reelevant.ts
import { ReelevantClient } from '@rlvt/web-sdk'
export const rlvt = new ReelevantClient({
timeout: 50,
})
2. Add identity middleware
Create a server middleware that ensures every visitor has an identity cookie:
// server/middleware/reelevant-identity.ts
import { ensureIdentity } from '@rlvt/web-sdk/nuxt'
export default defineEventHandler((event) => {
ensureIdentity(event, useCookies(event))
})
Request flow
Using useReelevant
The useReelevant helper auto-extracts visitor identity, user-agent, IP, and referer from the H3 event:
// server/api/personalise.ts
import { useReelevant } from '@rlvt/web-sdk/nuxt'
import { rlvt } from '~/server/utils/reelevant'
export default defineEventHandler(async (event) => {
const { run, runAll } = useReelevant({ client: rlvt, event })
const hero = await run({ workflowId: 'wf-hero', entrypoint: '43a490a0' })
return { hero }
})
Fetching multiple zones
export default defineEventHandler(async (event) => {
const { runAll } = useReelevant({ client: rlvt, event })
const [hero, sidebar, footer] = await runAll([
{ workflowId: 'wf-hero', entrypoint: '43a490a0' },
{ workflowId: 'wf-sidebar', entrypoint: 'b7e21f3c' },
{ workflowId: 'wf-footer', entrypoint: 'd9c84e1a' },
])
return { hero, sidebar, footer }
})
In a Nuxt page (SSR)
Fetch personalised content in a server route or plugin, then use it in your page:
<!-- pages/index.vue -->
<script setup lang="ts">
const { data } = await useFetch('/api/personalise')
</script>
<template>
<main>
<div
v-if="data?.hero?.body?.type === 'html'"
data-rlvt-ssr="true"
v-html="data.hero.body.content"
/>
<DefaultHero v-else />
</main>
</template>
Lower-level helpers
Extract the user ID directly from an H3 event’s cookie header:
import { extractUserIdFromEvent } from '@rlvt/web-sdk/nuxt'
export default defineEventHandler((event) => {
const userId = extractUserIdFromEvent(event)
// ...
})
runOptionsFromEvent(event)
Get all context fields (userId, userAgent, ip, referer) from an event:
import { runOptionsFromEvent } from '@rlvt/web-sdk/nuxt'
export default defineEventHandler(async (event) => {
const context = runOptionsFromEvent(event)
const result = await rlvt.run({
workflowId: 'wf-hero',
entrypoint: '43a490a0',
...context,
})
return result
})
Handling JSON responses
For headless personalisation where the workflow returns JSON:
<script setup lang="ts">
const { data } = await useFetch('/api/personalise')
const products = computed(() => {
if (data.value?.hero?.body?.type === 'json') {
return (data.value.hero.body.content as { products: Product[] }).products
}
return []
})
</script>
<template>
<div class="grid grid-cols-3 gap-4">
<ProductCard v-for="p in products" :key="p.id" :product="p" />
</div>
</template>
Click tracking
Click tracking must always be set up after display. Every content display should have a corresponding click tracking mechanism — either a redirect link or a trackClick() call.
Every RunResult includes redirectionUrl and trackClick(). Use one of the two patterns:
<!-- Redirect link -->
<template>
<div v-if="data?.hero?.body?.type === 'html'" data-rlvt-ssr="true">
<div v-html="data.hero.body.content" />
<a :href="data.hero.redirectionUrl">Shop now</a>
</div>
</template>
// Server-side fire-and-forget (in an API route)
export default defineEventHandler(async (event) => {
const { run } = useReelevant({ client: rlvt, event })
const result = await run({ workflowId: 'wf-hero', entrypoint: '43a490a0' })
// Later, when the user clicks (must be after display):
await result.trackClick()
})
See Core SDK — Click tracking for full details.
Compatibility with the client tracker
Server-rendered zones should include data-rlvt-ssr="true" in the wrapper element. The client-side tracker automatically skips these zones.