Documentation
Documentation
The build fetches your public policy once and bundles it, so the server never fetches it at runtime.
The quickstart sets this up across these files:
| File | Role |
|---|---|
vite.config.ts | consentManifest from @c15t/svelte/vite fetches the policy. |
src/hooks.server.ts | c15tHandle(), whose default mode, manifest(), resolves from the fetched policy. |
src/routes/+layout.server.ts | export { loadConsent as load } resolves each visitor. |
src/routes/+layout.svelte | ConsentRoot state={data.consent} renders the result. |
The plugin's position in plugins does not matter. It fetches the policy
once Vite has resolved its config, before anything compiles. Without a
backendURL option, it reads PUBLIC_C15T_BACKEND_URL, then
PUBLIC_INTH_PROJECT_URL, from the environment or .env.
The plugin detects the sveltekit() plugin and keeps the snapshot on the
server. loadConsent and createConsentRoute() read it without an import.
The browser bundle never holds it: ConsentRoot gets the resolved policy
from loadConsent instead.
Static hosts follow build a static site instead.
The snapshot is fixed at build time:
- Rebuild after changing policies, translations or vendors. If your CI caches build output, force a fresh build.
- Consent choices still go to the backend.
The build reads the backend URL from your public backend URL variable when
the config doesn't pass one: NEXT_PUBLIC_C15T_BACKEND_URL in Next.js,
NUXT_PUBLIC_C15T_BACKEND_URL in Nuxt, PUBLIC_C15T_BACKEND_URL in Astro,
Svelte and SvelteKit, and VITE_C15T_BACKEND_URL in TanStack Start and other
Vite apps. Each also reads the matching Inth variable, such as
NEXT_PUBLIC_INTH_PROJECT_URL, when the c15t one is unset. See
set the backend URL.
The fetch waits at most 10 seconds. When it fails, or no backend URL is set, every framework does the same thing:
| Command | Default when the fetch fails |
|---|---|
Production build: next build, vite build, nuxt build, astro build | The build stops with an error. |
Dev: next dev, vite dev, nuxt dev, astro dev | A warning, and the server fetches the policy at runtime. |
Set onBuildError to use one behaviour for both. 'fail' stops dev too.
'runtime' lets a production build finish, and the server fetches the policy
at runtime. The C15T_ON_BUILD_ERROR environment variable overrides the
option, so you can deploy during a backend outage without a code change:
Turborepo's strict environment mode hides undeclared variables from tasks, so
list C15T_ON_BUILD_ERROR in the build task's passThroughEnv there.
The build skips the fetch, without an error, when it can't use a snapshot,
for example when the backend URL is relative. With onBuildError: 'fail', a
relative URL stops the build. Consent modes
lists every case.
vite build and vite dev fetch the manifest when they start. vite preview
serves the last build without fetching. The plugin writes no file into your
app, so there is nothing to keep out of Git. c15t/generated ships its own
types, so tsc, vue-tsc and svelte-check pass on a fresh checkout without
a build first.
The plugin can't see the options your app passes to manifest(). When the
app passes source: 'runtime' or manifestURL, set
consentManifest({ source: 'runtime' }) too. The build then downloads no
manifest, so it doesn't fail when the backend's /manifest is down.
On SvelteKit 3, svelte-kit sync resolves the Vite config, so it runs the
plugin and fetches the policy too, following the same rules when the fetch
fails. SvelteKit 2.68 also runs the plugin during svelte-kit sync, but logs
a failed fetch and continues.
To apply policy edits without a rebuild, set
c15tHandle({ mode: manifest({ source: 'runtime' }) }) and follow
fetch the manifest at runtime.
To have the backend resolve every visit instead, set
c15tHandle({ mode: hosted() }). The layout load then calls the backend's
/init, and so does the browser on pages the server did not resolve.