---
title: Scripts
description: Load vendor scripts by consent category in a TanStack Start app
  with ConsentRoot, and clear stored data or reload the page when a visitor
  withdraws consent.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Register vendor scripts

Pass vendor loaders to `ConsentRoot` through its `scripts` prop. `ConsentRoot`
loads each script in the browser when its category is allowed and removes it
when the category is denied. The [quickstart](/docs/frameworks/tanstack-start/quickstart)
registers PostHog in the root route:

```tsx title="src/routes/__root.tsx"
const scripts = [
	posthog({
		id: 'phc_your_project_key',
		initOptions: { cookieless_mode: 'never' },
		loadMode: 'after-consent',
	}),
];
```

and passes the array to `ConsentRoot`:

```tsx title="src/routes/__root.tsx"
<ConsentRoot state={consent} scripts={scripts}>
```

To share the array with other modules, move it to its own file, such as
`src/scripts.ts`, and import it in the root route.

Import vendor helpers in route modules, not in a server function. A server
function's return value must be serializable, and vendor loaders contain
functions. Scripts only load in the browser, so importing them in the root
route adds nothing to the server HTML.

Each helper from `@c15t/integrations` sets its own category and a stable `id`.
Remove every other loader for the same vendor, such as a `scripts` entry in a
route's `head()` or an SDK you initialize at module level, so the vendor loads
once and only through c15t. [Integrations](/docs/integrations/overview) lists
every helper, and [building integrations](/docs/integrations/building-integrations)
covers a vendor without one.

## What happens when consent changes

* **Allowed.** The script loads, or its SDK starts, the first time its category
  is allowed. With an awaited root loader, a returning visitor's allowed
  scripts start right after hydration.
* **Denied later.** The script element is removed. Code that already ran keeps
  running, so after the visitor turns off a category they had allowed, the page
  reloads once the save finishes. Set `reloadOnConsentRevoked: false` in
  `ConsentRoot`'s `options` only if every gated vendor stops itself.
* **`alwaysLoad` helpers.** Some integrations, such as the Google Consent Mode
  helpers by default, load before consent and pass the visitor's choice to the
  vendor. Read the vendor's guide; a category on a script does not always mean
  zero requests.

## Embeds and other requests

Scripts cover vendor code c15t loads for you. For the rest:

* [Embeds](/docs/frameworks/tanstack-start/embeds) keeps iframes out of the
  page with `ConsentGate` or the iframe blocker.
* [Network blocker](/docs/frameworks/tanstack-start/network-blocker) holds
  `fetch` and XHR calls that match a rule until their category is allowed.

## Clear stored data after revocation

Removing a script does not delete the cookies or storage entries it wrote. Pass
`clearOnRevocation` to `ConsentRoot` to delete the entries you list for each
category when it is denied. `ConsentRoot` reads it once, when it mounts.
[Clear on revocation](/docs/frameworks/tanstack-start/clear-on-revocation) covers
configuration and browser limits.

## Let visitors turn off one vendor

A visitor can allow marketing and still switch off one vendor in it. Pass
`vendors` to `ConsentRoot`. Helpers from `@c15t/integrations` already carry
their vendor slug. See [vendor consent](/docs/frameworks/tanstack-start/vendor-consent).

## Check the scripts

Open DevTools Network in a private window, filter by each vendor's domain and
reload.

1. Before a choice under an opt-in policy, no vendor script loads. The page
   source has no vendor `<script>` tags.
2. Allow one category. Only that category's vendors load.
3. Turn the category off. The page reloads and the vendor stays absent.
4. Reload again. The rejection holds, and the server HTML shows no banner.

[Verify consent](/docs/guides/verify-consent) has the full checklist.
