# Personalization and A/B tests with the Next.js App Router SDK

> How the Next.js App Router SDK renders personalizations, A/B tests and visibility rules, and where it gets the Context manifest.

Source: https://docs.uniform.app/docs/sdk/nextjs-app-router/personalization

You configure personalizations and A/B tests in Uniform. You do not write code for them in your components. The SDK renders the `$personalization` and `$test` components for you.

> **Developer Preview:**
>
> In the developer preview, the middleware does not choose the variants. Each published route has one cached page for all visitors. The variants are chosen in the browser (lite mode) or at the edge (edge mode).

|  | Lite mode | Edge mode |
| --- | --- | --- |
| Middleware | `uniformMiddleware` | `vercelUniformEdgeMiddleware` or `uniformEdgeMiddleware` |
| Server HTML | The default variants | All variants, between NESI tags |
| What the visitor gets first | The default variants | The variants of the visitor |
| Variant change after hydration | Yes, if the visitor does not get the default | Not on the first load. A personalization can change later, when the scores or quirks of the visitor change. |
| Extra cost | None | One more request for each page load. Refer to [What edge mode costs](https://docs.uniform.app/docs/sdk/nextjs-app-router/edge-mode#what-edge-mode-costs). |

## Default variants in lite mode

In lite mode, the server renders these variants:

- **Personalization:** the variants that an anonymous visitor gets. The visitor has no scores and no quirks, and is not in the control group.
- **A/B test:** the winner variant from the manifest. If there is no winner, the control variant. If there is no control variant, the first variant.

After hydration, the browser Context chooses the variants of the visitor and replaces the defaults.

## Custom personalization algorithms

To use a custom personalization selection algorithm, register it in two places:

1. In `uniform.server.config.ts`, for the server defaults and for the edge:

   `uniform.server.config.ts`

   ```ts
   import type { UniformServerConfig } from "@uniformdev/next-app-router/config";
   import { myAlgorithm } from "./lib/myAlgorithm";

   const config: UniformServerConfig = {
     context: {
       personalizationSelectionAlgorithms: { myAlgorithm },
     },
   };

   export default config;
   ```
2. In the browser, with a Context plugin in a [custom client context](https://docs.uniform.app/docs/sdk/nextjs-app-router/client-context#custom-client-context).

Do not read random values or the clock in the algorithm. With Cache Components, Next.js runs the algorithm when it prerenders the page. These values then make the prerender fail.

## Visibility rules

Visibility rules run only in the browser, in lite mode and in edge mode. A component that has visibility rules is not in the server HTML. It shows after hydration, when its rules match.

> **Warning:**
>
> Search engines and visitors without JavaScript do not see components that have visibility rules. Do not put content that search engines must index in a component with visibility rules.

## Quirks from Vercel geolocation

On Vercel, the middleware makes quirks from these request headers:

| Vercel header | Quirk |
| --- | --- |
| `x-vercel-ip-country` | `vc-country` |
| `x-vercel-ip-country-region` | `vc-region` |
| `x-vercel-ip-city` | `vc-city` |

The middleware sends the quirks to the browser in the short-lived `ufqc` cookie. The edge middleware also uses them to choose variants. To add your quirks, use the [`quirks` middleware option](https://docs.uniform.app/docs/sdk/nextjs-app-router/middleware#set-quirks-in-the-middleware).

---

## Context manifest

The SDK gets the Context manifest at runtime. You do not have to download it into the project.

- **Lite mode:** `UniformContext` gets the published manifest from the Next.js data cache, with the `manifest` cache tag. The `manifest.published` webhook revalidates it.
- **Edge mode on Vercel:** `vercelManifestProvider` keeps the manifest in the Vercel runtime cache. Refer to [Edge mode execution](https://docs.uniform.app/docs/sdk/nextjs-app-router/edge-mode#the-context-manifest).

To publish the manifest from the command line, add this script to `package.json`:

`package.json`

```json
{
  "scripts": {
    "uniform:publish": "uniform context manifest publish"
  }
}
```
