Install guide
Installing a chat assistant in a Phoenix project
Phoenix has two layouts and only one of them is the document. The root layout supplies the html and body elements and is shared by controllers and live views alike, which makes it the correct and the only sensible place for this. The other question people bring to this task, whether the live socket interferes, has a short answer: it does not.
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 Phoenix
lib/your_app_web/components/layouts/root.html.heex, immediately before the closing body tag.
Any Phoenix application generated by the framework's own project generator. The root layout is part of that skeleton, so the file is already in your project.
Step by step
- 1Open lib/your_app_web/components/layouts/root.html.heex, substituting your own application name in the path.
- 2Confirm you have the right file: this is the one containing the html and body elements, and near the end of the body it places the inner content assign, which is where everything else on the page is put.
- 3Paste the tag on its own line immediately before the closing body tag, after the inner content assign.
- 4Leave the app layout alone. Whether your version keeps it as its own template file or as a function component, it sits inside the root layout and is replaced during live navigation, so a tag there would be re-added on every navigation instead of installed once.
- 5Start the server and load a page. The code reloader picks up a template change without a restart, so a browser reload is enough to see it.
- 6Confirm the launcher appears on a plain controller page and on a live view, since both use this same root layout.
What goes wrong on Phoenix
The app layout is inside the root layout, and it is replaced
The root layout is drawn once, on the full page load that starts a session. Everything else, the app layout included, sits inside it and is swapped out as the visitor moves around. Putting the tag in the app layout means asking the browser to install the widget again on every navigation.
It does not produce two widgets, because the loader checks for its own global and returns immediately when it finds one. It produces a page that keeps asking for the same file for no reason, and a launcher whose position in the document keeps changing under it. The root layout avoids both.
Which file the app layout is depends on your Phoenix version
Older generated projects keep the app layout as a template beside the root layout. Newer ones express it as a function component that each template invokes. Instructions written for one shape send you looking for a file the other shape does not have, and people then assume the layout system has changed more than it has.
The root layout is stable across both. If you can see the html and body elements in the file, you are in the right place, whatever the rest of your project looks like.
The live socket is not the widget's connection
A live view holds a websocket to your own server for the lifetime of the page, and that connection is checked against the origin settings in your endpoint configuration. None of that has anything to do with this widget, which makes its own request to the address the tag was served from.
The confusion is worth naming because the two failures look alike in a console full of red. A refusal that names your own application address is your endpoint's socket configuration. A refusal that names your site as an origin the assistant does not accept is the widget's allowlist. They are fixed in different places.
Origins to allowlist
These are the origins a Phoenix site is typically served from. List every one you want the assistant to answer on, including the ones only you visit.
- http://localhost:4000
- 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 root.html.heex and deploy. The template is compiled into your release, so a running server keeps the old page until the new build is out.
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 work on a live view page?
- Yes, and it works the same way as on any other page. The root layout is shared by controllers and live views, so a single install covers both. Live updates change content inside the document and never replace the document itself.
- Will it interfere with live view events?
- No. The launcher lives in a closed shadow root of its own and the conversation panel is a separate frame, so nothing it does is visible to your event handlers and nothing your handlers do can reach into it.
- Do I need to change the content policy in the endpoint?
- Only if your project sets one. Phoenix does not impose a script policy on you by default, so unless somebody added a plug that writes that header, there is nothing to change. If one was added, the console tells you by naming the directive rather than the origin.
- How do I keep it off an admin area?
- If the admin section uses a different root layout, simply do not add the tag there. If it shares this one, add a condition on the current path around the tag in the layout.
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.