Install guide
Installing a chat assistant in a SvelteKit project
SvelteKit gives you one template for the whole application, src/app.html, and it is deliberately plain HTML. Knowing that it is plain HTML is most of what you need here, because it explains both where the tag goes and why the obvious alternative inside a component cannot work.
The tag
<script src="https://cdn.askably.xyz/w.js" data-key="pk_live_YOUR_KEY" defer></script>Your own key replaces the placeholder. You will find it on the install tab of the assistant.
The origin the page is served from has to be on the allowlist for that assistant, or nothing renders and the browser console says which origin was refused. An apex domain and its www are two different origins to a browser, so list both, along with any staging or preview host you want it to work on.
Where it goes on SvelteKit
src/app.html, after the SvelteKit body placeholder and immediately before the closing body tag.
Every SvelteKit project has src/app.html and it is yours to edit, whichever adapter you build with. There is nothing to enable and no build configuration to change.
Step by step
- 1Open src/app.html. It sits beside src/routes rather than inside it.
- 2Find the body, which contains the SvelteKit body placeholder that the framework replaces with your rendered application.
- 3Paste the tag on its own line after that placeholder and immediately before the closing body tag.
- 4Do not reach for Svelte syntax in this file. app.html is a static shell and only the percent delimited SvelteKit placeholders are substituted, so anything else is passed through verbatim.
- 5Restart the development server so the shell is read again, then load any route.
- 6Allowlist the development origin and the origin your adapter deploys to, since a widget that works in one and not the other is almost always this.
What goes wrong on SvelteKit
A script tag in a component is not markup
Put a script element at the top level of a component file and the compiler treats it as that component's instance script, which is where your own logic lives. It is compiled, not emitted, so no tag ever reaches the page and nothing tells you why.
app.html is the one place in a SvelteKit project where a raw script tag is passed straight through to the document.
Do not paste it inside the hydrated region
Many app.html templates wrap the body placeholder in a div. Anything inside that wrapper sits in the subtree SvelteKit hydrates, and hydration reconciles that subtree against what the server rendered.
Keep the tag outside the wrapper, immediately before the closing body tag, and hydration never has an opinion about it.
Navigation keeps the document, so the install persists
The SvelteKit client side router replaces page components without leaving the document. The loader installed on the first load is still installed on the tenth route, which is why nothing in your routes needs to know it exists.
If it does disappear mid-session, look for a full page reload in your own code, or a call to the destroy method on the global, rather than for a router setting.
Origins to allowlist
These are the origins a SvelteKit site is typically served from. List every one you want the assistant to answer on, including the ones only you visit.
- http://localhost:5173
- https://yourdomain.com
- https://www.yourdomain.com
How the tag behaves, wherever you put it
The rest of this is the same on every platform, so it is worth reading once rather than on each guide.
| One tag, nothing else | There is no second file, no stylesheet and no package to install. The tag is the whole install. |
|---|---|
| Where it goes | Immediately before the closing body tag. It works in the head too, because it defers, but the body keeps it out of the way of anything that measures render order. |
| data-key is required | Without it the loader stops and writes a warning to the browser console rather than rendering anything. |
| It finds itself | The loader reads the tag it was loaded from, and falls back to the first tag on the page carrying a data-key. Platforms that move or re-inject the tag do not break it. |
| It installs once | A second copy of the tag on the same page is ignored, so a template that renders twice does not produce two launchers. |
| Assets follow the tag | Everything else it needs is fetched from the same origin the tag was served from, so a proxy or a private domain needs no extra configuration. |
| The panel loads late | Only the small launcher is on the page at first. The conversation panel is fetched the first time a visitor opens it, in its own frame. |
| Styles cannot collide | The launcher renders inside a closed shadow root and the panel inside a frame, so nothing on the host page can restyle either, and neither can restyle the host page. |
Taking it off again
Delete the line from src/app.html and redeploy. There is nothing in your routes or your configuration to clean up.
Before you remove it
- Removing the tag stops the widget on that site. It does not delete the assistant, its material, or the enquiries it has already collected.
- If you are moving the widget to a different host rather than retiring it, add the new origin to the allowlist before you remove the old tag, or there is a window where neither works.
Questions
- Do I need to add it to every route or layout?
- No. app.html wraps every route in the application, so one line covers all of them, including routes you add later.
- Does the adapter I use matter?
- No. Every adapter builds from the same app.html, so the tag ends up in the delivered document whether you output a static site or run a server.
- Can I put it in the root layout instead?
- There are ways to make that work, and none of them are simpler than one line in app.html. All of them tie a tag that should exist for the whole session to a component's lifecycle.
- Why is there no launcher on the development server?
- The local port is its own origin and has to be allowlisted separately. The console on that page names the origin that was refused, which is the fastest confirmation you will get.
Keep reading
- Install on Next.jsapp/layout.tsx in the App Router, or pages/_document.tsx in the Pages Router. Not a client component that can unmount.
- Install on Reactindex.html at the project root for a Vite app, or public/index.html for Create React App. Immediately before the closing body tag.
- Install on Vueindex.html at the project root, after the div the app mounts into and immediately before the closing body tag.
- Every install guideThe same one line of HTML, and where it goes on each platform.
Try it on your own material
Upload a document or point it at your site, paste one line of HTML, then ask it something only your business could answer.