# Hypertune Toolbar

## Overview

The Hypertune Toolbar lets you view and override feature flags directly in your frontend.

<figure><img src="https://2048905609-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWa3rQLiu4JZhBRkiyoKz%2Fuploads%2FmQa9s87MPoEPjrt4Etwi%2FScreenshot%202025-09-04%20at%2017.36.19.png?alt=media&#x26;token=ce63dc0b-5a72-4be4-8592-547fc8e314a3" alt=""><figcaption></figcaption></figure>

## Setup

### 1. Ensure Tailwind CSS is set up

Make sure your project has Tailwind CSS set up and that you are importing its base styles.

### 2. Create a flag to control visibility

In the Hypertune UI, create a flag called `showHypertuneToolbar`. This flag will control whether the Hypertune Toolbar is visible.

<figure><img src="https://2048905609-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWa3rQLiu4JZhBRkiyoKz%2Fuploads%2FkDWWn9PFaAGm0E3Hw6qf%2FScreenshot%202025-09-04%20at%2017.32.15.png?alt=media&#x26;token=6f0a0f58-8d56-4ca2-9e92-3545fe2bb572" alt=""><figcaption></figcaption></figure>

### 3. Set the environment variable

Set the `HYPERTUNE_INCLUDE_TOOLBAR` environment variable to `true`:

{% code title=".env" %}

```bash
HYPERTUNE_INCLUDE_TOOLBAR=true
```

{% endcode %}

### 4. Regenerate the client

Regenerate the client:

{% tabs %}
{% tab title="npm" %}

```bash
npx hypertune
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn hypertune
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm hypertune
```

{% endtab %}
{% endtabs %}

### 5. Add the `<HypertuneToolbar>` component

Add the generated `<HypertuneToolbar>` component to your app, passing it the path to the flag you created earlier via the `showFlagPath` prop:

{% code title="app/layout.tsx" %}

```typescript
import { HypertuneProvider } from '@/generated/hypertune.react'
import { HypertuneToolbar } from '@/generated/HypertuneToolbar'
import getHypertune from '@/lib/getHypertune'
import './globals.css'

export default async function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode
}>) {
  const hypertune = await getHypertune()

  const dehydratedState = hypertune.dehydrate()
  const rootArgs = hypertune.getRootArgs()

  return (
    <HypertuneProvider
      createSourceOptions={{
        token: process.env.NEXT_PUBLIC_HYPERTUNE_TOKEN!,
      }}
      dehydratedState={dehydratedState}
      rootArgs={rootArgs}
    >
      <html lang="en">
        <body>
          {children}
          <HypertuneToolbar showFlagPath="showHypertuneToolbar" />
        </body>
      </html>
    </HypertuneProvider>
  )
}
```

{% endcode %}

### 6. Handle overrides on the server

Overrides are stored in a cookie called `hypertuneOverride`. If you're using Next.js or hydrating the SDK from the server, update your `getHypertune` function to read this cookie and pass it to `hypertuneSource.setOverride`:

{% code title="lib/getHypertune.ts" %}

```typescript
import 'server-only'
import { DeepPartial } from 'hypertune'
import { unstable_noStore as noStore } from 'next/cache'
import { cookies } from 'next/headers'
import {
  createSource,
  overrideCookieName,
  Source,
} from '@/generated/hypertune'

const hypertuneSource = createSource({
  token: process.env.NEXT_PUBLIC_HYPERTUNE_TOKEN!,
})

export default async function getHypertune({
  isRouteHandler = false,
}: {
  isRouteHandler?: boolean
} = {}) {
  noStore()

  await hypertuneSource.initIfNeeded()

  hypertuneSource.setRemoteLoggingMode(
    isRouteHandler ? 'normal' : 'off'
  )

  hypertuneSource.setOverride(await getOverrideFromCookie())

  return hypertuneSource.root({
    args: {
      context: {
        environment: process.env.NODE_ENV,
        user: {
          id: 'e23cc9a8-0287-40aa-8500-6802df91e56a',
          name: 'Example User',
          email: 'user@example.com',
        },
      },
    },
  })
}

async function getOverrideFromCookie(): Promise<DeepPartial<Source> | null> {
  try {
    const cookieStore = await cookies()
    const overrideCookie = cookieStore.get(overrideCookieName)

    if (!overrideCookie?.value) {
      return null
    }

    return JSON.parse(overrideCookie.value)
  } catch (error) {
    console.warn(
      `Failed to parse ${overrideCookieName} cookie:`,
      error
    )
    return null
  }
}
```

{% endcode %}
