---
title: Optimization
description: Improve c15t startup performance in React with prefetching, proxy rewrites, and rendering tradeoffs.
lastModified: 2026-04-14
---
Use this guide when you care about banner visibility speed, route static-ness, and reducing backend round-trip cost.

## Start Here

Apply the optimizations in this order:

|Situation|Use|Why|Tradeoff|
|--|--|--|--|
|Any production app using hosted mode|Same-origin `/api/c15t` proxy|Lowers browser startup overhead and keeps the backend origin out of client config|Requires framework or platform proxy setup|
|Banner speed matters on cold loads|`buildPrefetchScript()`|Starts `/init` before your app hydrates|Still a browser-side fetch, not SSR|
|Your app navigates client-side|Keep the provider mounted at the app root|Avoids remounting and re-running init work|Requires provider placement discipline|
|You cannot proxy and must stay cross-origin|`<link rel="preconnect">`|Starts DNS/TLS work earlier|Smaller gain than same-origin proxying|
|You are using Next.js and want SSR or static-route-specific guidance|Next.js optimization docs|Covers `C15tPrefetch`, `fetchInitialData()`, and rendering tradeoffs|Next-specific|

> ℹ️ **Info:**
> Treat same-origin proxying as the baseline optimization. The others are situational layers you add when startup timing or route behavior justifies them.

## 1) Prefer Same-Origin Proxy

Proxy c15t requests through your app server so the browser calls your own origin instead of a third-party domain.

How you configure this depends on your framework — Vite has `server.proxy`, Remix has resource routes, and most deployment platforms support rewrite rules.

Then use:

```tsx
<ConsentManagerProvider options={{ backendURL: '/api/c15t', mode: 'hosted' }}>
```

Why this helps:

* Same-origin requests avoid extra DNS/TLS setup in many deployments
* Ad blockers are less likely to block your init endpoint
* You can change backend infrastructure without touching client code

If you can only do one optimization, do this one first.

## 2) Prefetch Init Data Early

Use `buildPrefetchScript()` from the `c15t` core package to start the `/init` request before your app hydrates. Inject the script as early as possible in your HTML `<head>`.

In production benchmarks with a same-origin rewrite, prefetching strategies show measurable improvement over client-only init:

|Strategy|Scripts loaded|Data request starts|Banner visible|
|--|--|--|--|
|Client-only (no prefetch)|baseline|baseline|baseline|
|Browser prefetch|\~1.3x faster|\~2.6x earlier|\~1.25x faster|
|Server prefetch|\~2x faster|before page loads|\~1.9x faster|

Use this when:

* The app is client-rendered
* You want a faster first banner without introducing SSR complexity
* You control the HTML template or document `<head>`

### Inline Script Prefetch

```tsx
import { buildPrefetchScript } from 'c15t';

const prefetchScript = buildPrefetchScript({
  backendURL: '/api/c15t',
});

// In your HTML template or root component:
<head>
  <script dangerouslySetInnerHTML={{ __html: prefetchScript }} />
</head>
```

Then initialize your provider normally. Matching prefetched data is consumed automatically by the runtime during first store initialization:

```tsx
import {
  ConsentManagerProvider,
  ConsentBanner,
  ConsentDialog,
} from '@c15t/react';

export default function App({ children }: { children: React.ReactNode }) {
  return (
    <ConsentManagerProvider
      options={{
        mode: 'hosted',
        backendURL: '/api/c15t',
      }}
    >
      <ConsentBanner />
      <ConsentDialog />
      {children}
    </ConsentManagerProvider>
  );
}
```

> ℹ️ **Info:**
> If overrides.gpc conflicts with the browser's ambient GPC signal, the prefetched entry is not reused and c15t falls back to a normal client /init.

## Keep The Provider Mounted Across Navigation

Mount the consent provider at the app root so route transitions do not remount it.

Why this helps:

* Avoids re-running init work on client-side navigation
* Prevents extra callback churn from remount cycles
* Keeps banner/dialog state stable between route transitions

Mount `ConsentManagerProvider` as high in the tree as possible so route transitions do not recreate it.

## Animation Performance

The default motion tokens are tuned for speed-first product UI:

|Token|Duration|Used for|
|--|--|--|
|`fast`|80ms|Banner slide + overlay, card scale, button hover, widget entry/exit|
|`normal`|150ms|Accordion, switch toggle|
|`slow`|200ms|Dialog trigger snap, tab indicator|

These defaults follow the principle that product UI should be fast and purposeful — animations exist for spatial continuity, not decoration. In benchmarks, animation duration contributes a constant floor to "data fetched → banner visible" timing. The default tokens sit at the lower end of standard UI ranges (80-200ms) to minimize that floor.

To customize motion durations and easing, see [Styling](/docs/frameworks/react/styling/overview).

## Reduce Network Overhead

If your browser must call a cross-origin backend URL directly, add `preconnect` so the browser can warm up the connection earlier. This is a fallback optimization when same-origin proxying is not possible.

If you must use a cross-origin backend URL, add preconnect so the browser starts DNS/TLS early:

```tsx
<head>
  <link rel="preconnect" href="https://your-instance.c15t.dev" crossOrigin="" />
</head>
```

## Next.js-Specific SSR And Static Routes

This page is intentionally React-generic. If you are using Next.js and need SSR or static-route-specific guidance:

* See [Next.js Optimization](/docs/frameworks/next/optimization) for the static-vs-dynamic decision guide
* See [Next.js Server-Side Data Fetching](/docs/frameworks/next/server-side) for `fetchInitialData()`
