Skip to main content

TanStack Start Scripts and embeds

Scripts

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 registers PostHog in the root route:

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:

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 lists every helper, and building integrations covers a vendor without one.

  • 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 keeps iframes out of the page with ConsentGate or the iframe blocker.
  • 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 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.

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 has the full checklist.