Skip to main content
This widget is being rolled out. Interfaces on this page may change before general availability. The engineering documentation site, which tracks the current build, is at webchat.connectly.ai/docs.
Two paths, decided by a single question: does your site have an npm install step?
  • No build step β€” a CMS, a page builder, a static site, a tag manager, anywhere you can paste HTML β€” use the script tag.
  • Bundling your own frontend β€” React, Vue, Svelte, Solid, Angular β€” use the npm package. It ships ES modules and a typed React wrapper.

The script tag

Paste this before the closing </body> tag. <head> also works β€” the script defers itself until the page is ready either way.
That is the whole integration. The launcher appears in the corner once the widget loads. Place the element; do not call a function. <connectly-webchat> is a custom element, and the browser upgrades whatever elements are already on the page the moment the definition lands. Your markup may therefore sit before or after the script tag with the same result, and this form works where a CMS, a theme or a tag manager lets you add markup but not run a script. If you do need the JS API, keep the call in a second tag carrying defer or type="module", after the first. Both attributes hold execution until the document has parsed and then run in document order, so window.ConnectlyWebchat exists by the time the second tag runs; a plain inline <script> with neither attribute runs first, against a global that is not there yet. The sturdier form β€” and the one to use when you cannot control tag order β€” is the ready event, which you may subscribe to before the widget exists because it bubbles to document:
open() is deliberately not what this example calls: it would pop the panel up for every visitor on every page. Use the event to hook up analytics, and leave opening to the reader. The event fires when the launcher renders, and is not replayed β€” register the listener before the widget loads rather than after. It fires again if the widget is torn down and re-initialized (a changed client-key, or an SPA remount), so it is once per launcher rather than once per page.

The npm package

A git URL rather than a registry name: the package is distributed from its own GitHub repository, which npm, pnpm and yarn all install from natively. Always pin a tag. A git specifier resolves to a commit, so omit the fragment after # and you get whatever is on the default branch at install time, which moves under you. #semver:^1.1.0 also works, resolving against the repository’s tags. If the install asks for credentials, see β€œnpm cannot install the git URL” under Troubleshooting. ESM only, browser only. There is no CommonJS build, so reach it through import or a bundler, never require().

React

The component renders null. The widget is created imperatively and lives in <body>, outside your tree; unmounting the component ends the session. react and react-dom are optional peer dependencies, needed only for this entry point.

Any other framework, or none

That import is the integration: it defines the <connectly-webchat> custom element and configures the origin. Then put the element on the page.
Svelte, Vue, Solid and Angular all render custom elements natively, so the import plus the tag is everything β€” with two exceptions that break the build otherwise. Vue needs isCustomElement, or the compiler treats the tag as a component it cannot resolve, warns on every render, and emits nothing:
Angular needs schemas: [CUSTOM_ELEMENTS_SCHEMA] on the component, or the template fails with NG0304. Where you put the element in the DOM does not matter β€” it is a 0Γ—0, pointer-events: none mount point, and the launcher is fixed to the viewport corner. One exception: an ancestor with a transform, filter or contain becomes the containing block for position: fixed, so the element relocates itself to <body> β€” which breaks any framework that thinks it still owns that node. Append to <body> yourself, or use the React wrapper.

Server rendering

Never import the package on the server. It defines a custom element extending HTMLElement, which does not exist in a server runtime, so the import itself throws ReferenceError: HTMLElement is not defined. That includes @connectly/webchat/react, which imports the main entry. Next.js, both routers β€” load it through next/dynamic with ssr: false, because even a client component is prerendered during next build:
Everywhere else β€” Remix, Nuxt, Astro, SvelteKit β€” the rule is the same: reach it from a browser-only path (a dynamic import() in a mount or effect hook, a <ClientOnly> wrapper, client:only, a plain module <script>), never a static import at the top of a shared module.

One integration per page

Do not load the script tag and the npm package on the same page. You get two launchers, two sessions and two sockets for one visitor, and the transcript splits unpredictably between them. Nothing errors and nothing warns β€” multiple widgets on one page is deliberately supported for other cases β€” so this is a bug you will only find by looking at it.