Install guide
Adding a chat assistant to a Laravel application
Laravel renders every page through a Blade layout, so the install is one paste into the layout your views extend. The two things that catch people are Blade escaping, which turns a tag written through an echo into visible text on the page, and the compiled view cache, which happily keeps serving the old layout after a deploy.
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 Laravel
resources/views/layouts/app.blade.php, or whichever layout your pages name in their @extends directive, immediately before the closing body tag.
Any Laravel application that renders Blade views on the server. If your front end is a separate build served on its own, the tag belongs in that application's index template rather than in Blade.
Step by step
- 1Open resources/views/layouts/app.blade.php. If you are not certain that is the layout in use, search resources/views for the closing body tag and see which files come back.
- 2Paste the tag on its own line immediately before the closing body tag, written as plain HTML.
- 3Do not echo it. Blade escapes echoed output, so a tag passed through a variable arrives as words printed on the page rather than as a script the browser runs.
- 4If your layout declares a scripts stack, push the tag onto that stack from a push block instead, so it lands with the rest of your scripts rather than above them.
- 5Deploy as usual, then clear the compiled views on the server. Until you do, Laravel can keep rendering the previously compiled copy of the layout out of storage/framework/views.
- 6Load any page and confirm the launcher appears. Config and route caching have no bearing on this. Only the view cache does.
What goes wrong on Laravel
Blade escapes whatever you echo
The double brace syntax exists to make output safe, which means it also makes a script tag inert. Store the tag in a config value, print it with double braces, and what you get is the tag itself displayed as text at the bottom of every page. It is one of the few install failures you can diagnose without opening the console.
Write the tag as literal markup in the template. There is no reason to route a static line through a variable, and doing so only raises a question about which echo syntax is safe here.
The compiled view cache outlives the deploy
Laravel compiles each Blade template once and reuses the compiled file under storage/framework/views. Normally a newer template timestamp invalidates it, but deploys that copy files into a fresh release directory, or that run from a read only mount, can leave a stale compiled layout in place.
Clearing views is one artisan command and belongs in your deploy script beside the config and route caching you already run. The symptom without it is a page whose source has no tag in it even though the file on disk clearly does.
One layout is rarely all your layouts
Applications acquire a second layout for the admin area, a third for marketing pages, and a stripped one for printable documents. Pasting into app.blade.php covers only the views that extend it, so the launcher vanishes the moment a visitor lands on something rendered from a guest layout.
Search resources/views for the closing body tag, list what comes back, and decide about each one deliberately. Leaving it off the admin layout is usually the right call rather than an oversight.
Origins to allowlist
These are the origins a Laravel site is typically served from. List every one you want the assistant to answer on, including the ones only you visit.
- http://your-app.test
- http://localhost:8000
- https://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. |
Set up on Laravel for a particular trade
The tag is the same everywhere. What is not the same is which of your pages the assistant can read once it is running, and on Laravel that depends on what kind of site this is. These go one level further than this guide.
Taking it off again
Delete the line from the layout, deploy, and clear the compiled views again. Nothing else in the application references it.
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
- Head or before the closing body tag?
- Either. The tag defers, so it never blocks parsing wherever it sits. Before the closing body tag matches the convention in most Blade layouts and keeps the head for meta tags and stylesheets.
- Can it answer from my database?
- No. It answers from the material you index, which is files you upload or a crawl of your own site. Anything that exists only in a table behind an authenticated route is invisible to it, and it says it does not know rather than guessing.
- How do I keep it off the admin panel?
- Put the tag only in the public facing layout, not in the layout your admin views extend. That is cleaner than wrapping it in a condition, and it means no admin route can ever leak a launcher onto an internal screen.
- It works locally but not in production. Why?
- The local site and the production site are different origins, and only allowlisted ones render. Open the console on the production site: if the origin was refused, it is named there, and adding it is the entire fix.
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.