> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reelevant.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SvelteKit Integration

> Integrate server-side personalisation with SvelteKit using server load functions and hooks

## Installation

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @rlvt/web-sdk
```

No additional dependencies. The adapter uses structural typing — it does not import from `@sveltejs/kit`.

## Setup

### 1. Create the client instance

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// src/lib/server/reelevant.ts
import { ReelevantClient } from '@rlvt/web-sdk'

export const rlvt = new ReelevantClient({
  timeout: 50,
})
```

### 2. Add identity hook

Ensure every visitor has an identity cookie using a server hook:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// src/hooks.server.ts
import { ensureIdentity } from '@rlvt/web-sdk/sveltekit'

export async function handle({ event, resolve }) {
  ensureIdentity(event)
  return resolve(event)
}
```

## Request flow

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
sequenceDiagram
    participant Client as Browser
    participant SK as SvelteKit Server
    participant Hook as hooks.server.ts
    participant Load as +page.server.ts
    participant SDK as @rlvt/web-sdk
    participant Runner as Reelevant Runner

    Client->>SK: GET /page
    SK->>Hook: handle({ event, resolve })
    Hook->>SDK: ensureIdentity(event)
    alt No identity cookie
        SDK->>SDK: Generate rlvt_tmpId
        SDK->>Hook: event.cookies.set('rlvt_tmpId', ...)
    end
    SK->>Load: load(event)
    Load->>SDK: createLoad({ client, event })
    SDK->>SDK: Extract userId, userAgent, IP from event
    Load->>SDK: run({ workflowId, entrypoint })
    SDK->>Runner: GET /{workflowId}/{entrypoint}?rlvt-u={userId}
    Runner-->>SDK: HTML / JSON / Image
    SDK-->>Load: RunResult
    Load-->>SK: { hero }
    SK-->>Client: SSR page with personalised content
```

## Using createLoad

The `createLoad` helper auto-extracts visitor identity and context from the SvelteKit event:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// src/routes/+page.server.ts
import { createLoad } from '@rlvt/web-sdk/sveltekit'
import { rlvt } from '$lib/server/reelevant'

export async function load(event) {
  const { run, runAll } = createLoad({ client: rlvt, event })

  const hero = await run({ workflowId: 'wf-hero', entrypoint: '43a490a0' })
  return { hero }
}
```

Then use the data in your page:

```svelte theme={"theme":{"light":"github-light","dark":"github-dark"}}
<!-- src/routes/+page.svelte -->
<script lang="ts">
  let { data } = $props()
</script>

{#if data.hero.body.type === 'html'}
  <div data-rlvt-ssr="true">
    {@html data.hero.body.content}
  </div>
{:else}
  <DefaultHero />
{/if}
```

### Multiple zones

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
export async function load(event) {
  const { runAll } = createLoad({ client: rlvt, event })

  const [hero, sidebar] = await runAll([
    { workflowId: 'wf-hero', entrypoint: '43a490a0' },
    { workflowId: 'wf-sidebar', entrypoint: 'b7e21f3c' },
  ])

  return { hero, sidebar }
}
```

## Lower-level helpers

### `runOptionsFromEvent(event)`

Extract identity and context fields manually:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { runOptionsFromEvent } from '@rlvt/web-sdk/sveltekit'

export async function load(event) {
  const context = runOptionsFromEvent(event)
  // context = { userId, userAgent, ip, referer }

  const result = await rlvt.run({
    workflowId: 'wf-hero',
    entrypoint: '43a490a0',
    ...context,
  })

  return { result }
}
```

### `ensureIdentity(event)`

Sets an `rlvt_tmpId` cookie on the event if no identity cookie exists. Use in hooks or load functions:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { ensureIdentity } from '@rlvt/web-sdk/sveltekit'

export async function handle({ event, resolve }) {
  ensureIdentity(event)
  return resolve(event)
}
```

## Handling JSON responses

```svelte theme={"theme":{"light":"github-light","dark":"github-dark"}}
<script lang="ts">
  let { data } = $props()

  const products = $derived(
    data.zone.body.type === 'json'
      ? (data.zone.body.content as { products: Product[] }).products
      : []
  )
</script>

<div class="grid grid-cols-3 gap-4">
  {#each products as product (product.id)}
    <ProductCard {product} />
  {/each}
</div>
```

## Click tracking

<Warning>
  **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.
</Warning>

Every `RunResult` includes `redirectionUrl` and `trackClick()`. Two patterns:

```svelte theme={"theme":{"light":"github-light","dark":"github-dark"}}
<!-- Redirect link -->
{#if data.hero.body.type === 'html'}
  <div data-rlvt-ssr="true">
    {@html data.hero.body.content}
    <a href={data.hero.redirectionUrl}>Shop now</a>
  </div>
{/if}
```

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Server-side fire-and-forget (in a form action)
// src/routes/+page.server.ts
import { createLoad } from '@rlvt/web-sdk/sveltekit'
import { rlvt } from '$lib/server/reelevant'

export const actions = {
  trackClick: async (event) => {
    const { run } = createLoad({ client: rlvt, event })
    const result = await run({ workflowId: 'wf-hero', entrypoint: '43a490a0' })
    await result.trackClick()
  }
}
```

See [Core SDK — Click tracking](/developer-docs/web-integration/server-side-sdk/core#click-tracking) for full details.

## Compatibility with the client tracker

Add `data-rlvt-ssr="true"` to your wrapper element. The client-side tracker automatically skips server-rendered zones.
