Skip to main content
Virent

SvelteKit Installation Guide

Last researched 2026-08-26

This is the canonical Virent installation guide for SvelteKit applications.

Research Notes#

  • src/app.html is the global HTML template for SvelteKit.
  • src/hooks.server.ts can define a handle hook 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.html is 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/bot

Add 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.