In this section
Resources / Installation / Frameworks
Add the embed snippet to app.html in SvelteKit or index.html in a plain Svelte app.
Svelte apps ship an HTML shell, which is the best place for the Hubbo snippet.
Edit src/app.html and add the snippet inside <head>, before %sveltekit.head% or after it:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://api.hubbo.io/embed?key=ACCOUNT_KEY" id="hubbo-embed-script" async type="module" crossorigin="use-credentials"></script>
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>Open index.html in the project root (or public/index.html in older templates) and add the snippet inside <head>.
<script src="https://api.hubbo.io/embed?key=ACCOUNT_KEY" id="hubbo-embed-script" async type="module" crossorigin="use-credentials"></script>You can also load the script from your root layout in the browser only:
<script>
import { onMount } from 'svelte';
let { children } = $props();
onMount(() => {
if (document.getElementById('hubbo-embed-script')) return;
const script = document.createElement('script');
script.src = 'https://api.hubbo.io/embed?key=ACCOUNT_KEY';
script.type = 'module';
script.async = true;
script.crossOrigin = 'use-credentials';
script.id = 'hubbo-embed-script';
document.body.appendChild(script);
});
</script>
{@render children()}Client-side routing
SvelteKit navigates without a full reload. That is fine, the script stays loaded and notification, NPS and survey URL rules follow the browser location (History API + polling).
Svelte 4 layouts
If you are still on Svelte 4 / older SvelteKit, use <slot /> instead of {@render children()} and drop the $props() line.