Add web analytics to your SvelteKit app with one command. Choose Plausible, Google Analytics, or PostHog with --provider; the generator writes a single src/lib/components/analytics/analytics.svelte component, mounts it in the root layout, and appends the provider's PUBLIC_* keys to .env. The component reads its configuration through $env/dynamic/public and stays inert while the keys are blank, so nothing loads until you fill them in. Google Analytics sends a page_view on every client-side navigation, and PostHog initialises posthog-js with your project key and host.
<script lang="ts">
import { env } from "$env/dynamic/public";
// PUBLIC_PLAUSIBLE_DOMAIN is the site as registered in Plausible, e.g.
// `example.com`. Nothing loads until it is set. The script tracks
// client-side navigations itself, so no SvelteKit wiring is needed.
// Self-hosting? Point `src` at your instance instead of plausible.io.
const domain = env.PUBLIC_PLAUSIBLE_DOMAIN ?? "";
</script>
<svelte:head>
{#if domain}
<script
defer
data-domain={domain}
src="https://plausible.io/js/script.js"
></script>
{/if}
</svelte:head>
<script lang="ts">
import "../app.css";
import favicon from "$lib/assets/favicon.svg";
import { site } from "$lib/site";
import { ModeWatcher } from "mode-watcher";
import { getFlash } from "sveltekit-flash-message";
import { toast } from "svelte-sonner";
import { page } from "$app/state";
import { Toaster } from "$lib/components/ui/sonner";
import { MetaTags, deepMerge } from "svelte-meta-tags";
import Analytics from "$lib/components/analytics/analytics.svelte";
let { data, children } = $props();
const flash = getFlash(page);
$effect(() => {
if (!$flash || $flash.type !== "toast") {
return;
}
toast.message($flash.message);
$flash = undefined;
});
let metaTags = $derived(deepMerge(data.baseMetaTags, page.data.pageMetaTags));
</script>
<svelte:head>
<title>{site.name}</title>
<link rel="icon" href={favicon} />
</svelte:head>
<MetaTags {...metaTags} />
<ModeWatcher />
<Toaster />
<Analytics />
{@render children?.()}
# Plausible analytics
PUBLIC_PLAUSIBLE_DOMAIN=