Installation
There are three ways to load the widget: the plain script tag, manual init for single-page apps, and inline (embedded) mode.
Standard HTML sites
Drop the script tag anywhere on the page — just before </body> is a good spot:
<script
src="https://cdn.lane.chat/js/widget.js"
data-app-key="YOUR_APP_KEY"
></script>data-app-key is equivalent to setting window.laneChatAppId before the script loads; its value is your application's app_pub. The widget auto-initializes on load.
App key attribute
The canonical attribute is data-app-key. If you see older snippets using data-app-id, prefer data-app-key — that is what the current widget reads.
Single-page apps (manual init)
In a SPA you usually want to control when the widget mounts and unmounts — for example, mount only on authenticated routes, or wait until you have the user's identity. Turn off auto-init and drive the lifecycle yourself:
<script>
// Set BEFORE the widget script loads.
window.laneChatManualInit = true
window.laneChatAppId = 'YOUR_APP_KEY'
</script>
<script src="https://cdn.lane.chat/js/widget.js"></script>Then mount and unmount as routes change:
// On route enter:
window.laneChat.init()
// On route leave:
window.laneChat.destroy()init() is idempotent — calling it again reuses the existing instance rather than mounting a second widget. destroy() fully unmounts and is safe to init() again afterward.
Don't destroy just to push data
To update visitor data, call identify() — do not destroy() + init(). identify() updates in place without remounting or dropping the session.
React example
import { useEffect } from 'react'
export function SupportWidget() {
useEffect(() => {
// Ensure the loader is configured before the script runs. In practice you
// set window.laneChatManualInit / window.laneChatAppId in index.html and
// load the script once; here we just mount/unmount.
window.laneChat?.init()
return () => window.laneChat?.destroy()
}, [])
return null
}Guard against the script not having loaded yet with window.laneChat?..
Inline (embedded) mode
Instead of a floating launcher, you can render the chat inline inside a container element you control. Set the mode and the container selector before the script loads:
<div id="support-panel" style="width: 380px; height: 600px;"></div>
<script>
window.laneChatAppId = 'YOUR_APP_KEY'
window.laneChatMode = 'inline'
window.laneChatContainer = '#support-panel'
</script>
<script src="https://cdn.lane.chat/js/widget.js"></script>You can also set these via script-tag attributes:
<script
src="https://cdn.lane.chat/js/widget.js"
data-app-key="YOUR_APP_KEY"
data-mode="inline"
data-container="#support-panel"
></script>window.laneChatContainer must resolve to a DOM element. If it does not, the widget logs an error and falls back to floating mode.
Embedding the hosted host page directly
For webviews, iframes, or shared links you can point straight at the hosted host page instead of loading the script. Pass a url-encoded JSON object of visitor traits in data:
https://cdn.lane.chat/widget.html?app_id=app_xxx&layout=centered&data=%7B%22plan%22%3A%22pro%22%7Dlayout=centeredgives a responsive centered card (full-screen on phones); omit it for edge-to-edge fill.user_idis folded into the data asexternal_user_id.- The JSON object in
databecomeswindow.from_datainside the page and is shown to agents.
This is exactly how the native SDKs render chat.
Content Security Policy
If you run a CSP, allow the widget origin. The React runtime injects inline styles, so you also need style-src 'unsafe-inline' (or migrate to a nonce):
script-src 'self' 'unsafe-inline' https://cdn.lane.chat;
style-src 'self' 'unsafe-inline' https://cdn.lane.chat;
connect-src 'self' https://api.lane.chat https://cdn.lane.chat wss://dash.lane.chat;
img-src 'self' data: https:;Adjust connect-src to match the API and WebSocket hosts your account uses.
Troubleshooting
- Console warning
Please set window.laneChatAppId or use data-app-key attribute— the widget could not read an app key. Check the<script>tag or your init order. - Widget doesn't appear after a deploy — the entry
widget.jsis served no-cache, but if you see a stale build, verify the responseLast-Modifiedheader and hard-refresh to rule out browser cache.