SvelteKit Installation Guide
Last researched 2026-08-26
This is the canonical Virent installation guide for SvelteKit applications.
Research Notes#
src/app.htmlis the global HTML template for SvelteKit.src/hooks.server.tscan define ahandlehook that runs for server requests.- Server hooks do not run for prerendered pages or static assets, even on server deployments.
Primary references:
- https://svelte.dev/docs/kit/hooks
Human Analytics#
Add the script to src/app.html.
HTML
<!doctype html><html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <script defer data-write-key="vha_pk_..." src="https://app.virent.app/js/script.js" ></script> %sveltekit.head% </head> <body data-sveltekit-preload-data="hover"> <div style="display: contents">%sveltekit.body%</div> </body></html>Best practices:
- Keep the script near
%sveltekit.head%. - Use public env values only for publishable browser keys.
- Use the npm SDK from client modules only when custom events are needed.
Verification:
- Start or preview the app.
- Inspect the rendered head and Network requests.
- Refresh Human Analytics status.
Troubleshooting:
- If the script is absent, confirm
src/app.htmlis the active template. - If CSP blocks Virent, update deployed CSP headers.
- If localhost testing is needed, temporarily add
data-allow-localhost="true".
AI Analytics#
Set private environment values:
ENV
VIRENT_SITE_ID=site_...VIRENT_INGEST_SECRET=vha_sk_...VIRENT_INGEST_ENDPOINT=https://app.virent.app/v1/ingest/botAdd or compose a server hook:
TS
// src/hooks.server.tsimport { env } from "$env/dynamic/private"import type { Handle } from "@sveltejs/kit"const staticAssetPattern = /\.(?:png|jpg|jpeg|gif|svg|ico|webp|css|js|map|txt|xml)$/iconst aiCrawlerPattern = /GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|claudebot|Claude-Web|Claude-User|Claude-SearchBot|PerplexityBot|PerplexityBot\/|Perplexity-User|Perplexity-User\/|Google-CloudVertexBot|DeepSeekBot|DeepSeekSpider|CCBot|Applebot|Bytespider|meta-externalagent|meta-webindexer|meta-externalfetcher|Amazonbot|DuckAssistBot|PetalBot|YouBot/iexport const handle: Handle = async ({ event, resolve }) => { const response = await resolve(event) const userAgent = event.request.headers.get("user-agent") ?? "" if (!staticAssetPattern.test(event.url.pathname) && aiCrawlerPattern.test(userAgent)) { await fetch(env.VIRENT_INGEST_ENDPOINT, { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": env.VIRENT_INGEST_SECRET, }, body: JSON.stringify({ siteId: env.VIRENT_SITE_ID, url: event.url.toString(), host: event.url.host, path: event.url.pathname, method: event.request.method, referer: event.request.headers.get("referer"), userAgent, statusCode: response.status, requestId: crypto.randomUUID(), timestamp: new Date().toISOString(), }), }) } return response}Best practices:
- Compose with existing auth, i18n, or observability hooks instead of replacing them.
- Resolve the response first so the final status code is available.
- Use the hosting edge or reverse proxy for prerendered pages, static assets, and static-adapter deployments.
Verification:
SH
curl -A "GPTBot" https://your-domain.com/- Confirm the hook runs.
- Refresh AI Analytics status.
Troubleshooting:
- If hooks do not run, confirm the deployed adapter supports server-side requests.
- If existing hooks break, compose handles in sequence.
- If secrets are undefined, verify private env loading in the platform.