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.
Most of the appearance is not configured in code. Colours, the launcher’s side and icon, the panel’s size and the greeting are stored against your client key in the Connectly dashboard and fetched at runtime, so the common case needs no config at all — change it in the dashboard and every page using that key follows, with no redeploy. Everything below is for what the dashboard cannot cover: a per-page override, a value driven by your own state, or a theme that has to match the page it sits on.

The precedence chain

Four layers, lowest to highest:
They merge per group, not wholesale, so { launcher: { side: 'left' } } moves the launcher without resetting its size, icon and offsets to defaults. HTML attributes get the last word. An attribute is in the page’s own markup, authored by whoever owns the page; config is often set by a shared wrapper or component library that the page author cannot edit. So <connectly-webchat side="left"> wins over config={{ launcher: { side: 'right' } }}. One consequence worth knowing: title is a global HTML attribute, so anything that sets it on the element — a CMS, a framework, a tooltip helper — overrides config.panel.title. See the title row under “Attributes” below. If you set the panel heading through config, make sure nothing is also writing a title attribute. init() is the one place the shorthands and config are reconciled for you: the title/width/height options land as attributes, so when a single init() call passes both a shorthand and a config for the same field, the shorthand yields to config and logs a warning rather than beating it from the top tier.
Outside React, assigning config alone repaints nothing — it is a plain field, not an attribute, so call reload() after:
Each distinct config value costs a network round-trip. Values are compared structurally, so an equal object is free — but bind config to a colour picker and you send one request per intermediate value. Memoise it, apply on commit, or for a live preview drive the --cwc-* custom properties instead (see “Theming with CSS” below).

config fields

config is a partial WidgetUi — the same shape the dashboard saves.
  • launcherside, offsetX, offsetY, size, shape (circle | pill), label, ariaLabel, icon ({ kind: 'default' | 'url' | 'none', url })
  • panelwidth, height, radius
  • themeaccent, accentText, surface, surfaceAlt, text, textMuted, border, bubbleVisitor, bubbleVisitorText, bubbleAgent, bubbleAgentText, bubbleRadius, fontFamily, colorScheme (light | dark | auto)
  • zIndex
  • collisionbottomOffsetPx, maxBottomOffsetPx
  • mobilebreakpointPx, launcher (offsetX, offsetY, size), panel (fullscreen, width, height, radius0 means “inherit the desktop value”)
Visible in autocomplete but not yet acted on, so setting them does nothing: behavior.autoOpen*, navigation.linkTarget, paths.*, panel.anchor, launcher.hideOnMobile, collision.bottomOffsetSelectors, collision.hideBehindModalDialog, position, bundleVersion. Only the config stored for your business is range-checked. Values passed through config or an attribute are merged in as given, so panel.width: 5000 is a 5000px panel. Use the dashboard’s ranges as your bounds. Note this cuts both ways with the precedence order above: an out-of-range attribute is not clamped and cannot be corrected by config. And fontFamily names a face, it cannot load one: @font-face is ignored inside a shadow root, so declare the face in your own stylesheet and name it here.

Attributes

Every attribute is optional except client-key.

React props

log-level is not a React prop: set it with setAttribute, or write it directly in JSX.

Theming with CSS

The --cwc-* custom properties are the supported theming API. Every resolved value is written to a custom property on the host element, with no !important anywhere in that path, so yours wins:
--cwc-* is desktop and --cwc-m-* is mobile, switched by a media query. Lengths take units here (56px), unlike config, which takes plain numbers. This is also the layer for anything that changes rapidly — it costs no network round-trip at all. Reaching inside the shadow root is not supported. Class names and structure change without notice; a stylesheet that depends on them will break on an ordinary widget update.