# Nuxt (/docs/getting-started/nuxt)

Within the browser the [Vue SDK](/docs/getting-started/vue) will do everything you need it to do. If you are only running your A/B tests client side, you don't need this package. However Nuxt also renders on the server, where you might also want to decide a test.

This package is for Nuxt's server (Nitro) only. On React Router, and on Shopify Oxygen, the loader decides instead: see [React Router](/docs/getting-started/react-router).

## When to use [#when-to-use]

A good scenario to use this is when you want to A/B test part of a single page, above the fold. Like on [the homepage of Improve](https://improve.obelism.studio). With a client side test there would be layout shift, since the first paint has to be the same for everyone. This can have a negative impact on alternative versions. That's why we need a server side test: the server decides what version the visitor gets, and the first paint matches it.

## How it works [#how-it-works]

The Improve Nuxt SDK is a server middleware: it runs before every page renders, decides the variant from cookies or query parameters (or buckets a new visitor), keeps it in cookies, and leaves it on the request for the page.

Unlike the [Next.js SDK](/docs/getting-started/nextjs), it doesn't rewrite to another route. Nuxt hydrates the route the browser shows, so the page renders the variant itself, and the browser reads the same variant from the cookie to record the exposure.

## Install [#install]

```bash
npm i @obelism/improve-sdk @obelism/improve-sdk-nuxt @obelism/improve-sdk-vue
```

## Middleware [#middleware]

Create the middleware by passing it the Improve server SDK and a list of the A/B tests that you want to decide on the server, each with the page route it runs on.

```ts title="server/middleware/improve.ts"
import { ImproveServerSDK } from '@obelism/improve-sdk/server'
import { generateImproveNuxtMiddleware } from '@obelism/improve-sdk-nuxt'

const improveSdk = new ImproveServerSDK({
	organizationId: 'org_…',
	environment: 'production',
	// `imp_…` from Settings → API tokens, as `NUXT_IMPROVE_API_TOKEN`.
	token: () => useRuntimeConfig().improveApiToken,
	configRetries: 0,
})

export default generateImproveNuxtMiddleware({
	improveSdk,
	serverABtests: [{ slug: 'startpage-visual', routeHandler: '/' }],
})
```

Declare `improveApiToken: ''` under `runtimeConfig` in `nuxt.config.ts`, so the token stays on the server.

## Render the variant [#render-the-variant]

```vue title="app/pages/index.vue"
<script setup lang="ts">
import { getImproveContext } from '@obelism/improve-sdk-nuxt'

import { useTestValue } from '~/improve'

const decided = useState('improve:startpage-visual', () => {
	const event = useRequestEvent()
	return (event && getImproveContext(event)['startpage-visual']) || null
})
const variant = useTestValue('startpage-visual', decided.value ?? 'control')
</script>

<template>
	<HeroVariation v-if="variant === 'variation'" />
	<HeroControl v-else />
</template>
```

`useState` hands the server's decision to the browser. `useTestValue` comes from the provider the [Vue SDK](/docs/getting-started/vue) generates: it renders the server's value until the SDK is set up, then reads the same value from the cookie, which records the exposure. After a client-side navigation no request reached the middleware, so the browser decides.

Keep tested routes out of prerendering and route caches (`prerender`, `swr`, `isr` in `routeRules`): a cached page shows one variant to everyone.

## Example [#example]

The [Nuxt example](/docs/examples/nuxt) puts it together, with tracking.
