Install guide
Installing a chat assistant in an Astro project
Astro treats script elements in your components as source code to process, which is excellent for your own modules and exactly wrong for a hosted loader. One directive fixes it. The other thing worth knowing before you ship is what view transitions do to scripts on navigation.
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 Astro
Your base layout, usually src/layouts/Layout.astro, immediately before the closing body tag.
Any Astro project. You own the layout that renders the html and body elements, so there is nothing to configure beyond one directive on the tag itself.
Step by step
- 1Open the layout that your pages wrap themselves in, commonly src/layouts/Layout.astro.
- 2Find the closing body tag, below the slot where page content is rendered.
- 3Paste the tag immediately before it, and add the is:inline directive to the script element.
- 4Keep src, defer and data-key exactly as given. is:inline is what guarantees they survive the build.
- 5Run the development server and confirm the launcher appears on a page that uses this layout.
- 6If some routes use a different layout, repeat it there or move both layouts onto a shared shell, then allowlist the development and production origins.
What goes wrong on Astro
Without is:inline the attributes are gone
By default Astro picks up script elements in components, processes them as modules, bundles them and emits its own tag in place of yours. A src pointing at another origin is not something it can usefully bundle, and your data-key attribute is not carried over to whatever it emits.
The symptom is a tag in the served page that does not look like the one you wrote, followed by a console warning about a missing key. is:inline tells Astro to leave the element exactly as authored, attributes and all.
View transitions re-run inline scripts
With Astro's client side routing enabled, navigating to a new page re-executes inline scripts in the incoming document. That would ordinarily mean a second install on every navigation.
It does not here. The loader checks for its own global before doing anything and returns immediately when it is already present, so you get one widget for the whole session and an open conversation stays exactly where it was.
Only the pages using that layout get it
Astro sites accumulate layouts. A marketing layout, a documentation layout and a one-off landing page written as a bare page do not share a shell unless somebody made them share one.
The result is a widget that appears on some URLs and not others, which reads like a caching problem and is not. Check which layout each route actually imports before looking anywhere else.
Origins to allowlist
These are the origins a Astro site is typically served from. List every one you want the assistant to answer on, including the ones only you visit.
- http://localhost:4321
- 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 script element from the layout and rebuild. If you added it to several layouts, remove it from each one, since any single remaining copy still installs the widget.
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
- Does it need a client directive?
- No. Client directives are for islands, which are components that need to hydrate. This is a plain script tag rather than a component, and is:inline is the only directive it takes.
- Will it work on a statically built site?
- Yes. The tag is baked into every generated page and runs in the browser like any other script. Nothing about it needs a server at request time.
- Is it safe to have the tag in more than one layout?
- Yes, because the loader installs once per page and ignores a second attempt. It is still a maintenance cost, since a key change then has to be made in several files.
- Does it slow the build down?
- No, and that is part of what is:inline buys you. The element is copied through untouched rather than entering the bundler at all.
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.