Skip to main content
This page is written for a security or privacy review.
Everything on this page applies equally whether the widget is added through the snippet or through the WordPress plugin. The plugin only loads the same hosted script described below; it does not change what the widget can reach or collect.

How it talks to the backend

The widget is anonymous. There is no login step, no user account, and no session cookie involved. Instead:
  1. Every request the widget makes is sent to a dedicated widget endpoint on api.baseUrl, never directly to the underlying service.
  2. Your tenantId travels with each request as an X-Tenant-Id header, identifying which organization’s catalog and branding to use.
  3. That endpoint checks the requested path and method against a fixed allowlist before forwarding anything. Requests outside the allowlist are rejected.
The allowlist covers only what the widget’s screens actually need:
  • Starting and continuing a chat, reading chat messages, cancelling a request, and resolving a clarifying question
  • Reading material records and datasheets
  • Reading catalog reference data such as families, manufacturers, colors, brands, and property definitions
  • Reading citations
  • Listing countries and states for the quote form
  • Submitting a guest quote
  • Posting widget telemetry
The allowlist is the boundary. It contains only anonymous catalog reads, chat operations, and the guest quote submission, so account, order, project, and administrative endpoints are not reachable through the widget path.

Cross-origin access and the tenant ID

The widget endpoints and the widget script are served with permissive cross-origin headers so the bundle can be loaded and called from your own domain. There is currently no per-origin restriction on the widget endpoints, so a request carrying your tenant ID is accepted from any origin.
Treat api.tenantId as a public identifier, not a credential. It is visible in the page source of any site running your embed, and on its own it does not prove where a request came from. It scopes which catalog and branding a request receives; it is not a secret and does not authenticate the caller.

Streaming responses

Answers stream over Server-Sent Events. When a conversation starts, the widget opens a long-lived connection for that chat and receives a sequence of typed events: Browsers cannot attach custom headers to an SSE connection, so on the streaming connection only, the tenant ID is passed as a query parameter instead of a header. If the stream goes quiet while a response is still in flight, the widget falls back to periodically refetching the conversation, so a dropped connection degrades to slower updates rather than a stuck screen.

Telemetry

What is collected

The widget buffers two kinds of events and periodically sends them to your api.baseUrl: Timings. Named performance milestones with a timestamp, such as when the bundle finished loading, when the interface rendered, when the streaming connection opened, when the first answer token arrived, and when the answer finished rendering. Actions. Named interaction events with a small structured context. The events currently emitted are:
  • A message-sent event, whose context records the chat identifier, whether files were attached, whether a shortcut was used, and which search mode was selected.
  • A diagnostic trace event, whose context records internal trace identifiers for the completed answer, used to correlate a slow or failed response with backend logs.
  • Error events, whose context records the error text and where in the widget it occurred.
Each batch is sent with the following envelope: your tenant ID, a session identifier, the current chat identifier, the timing and action lists, the origin of the page hosting the widget, the browser user agent string, and the flush timestamp.

What is not collected

  • No message content. The text a visitor types and the text the assistant replies with are never included in a telemetry event.
  • No identity. There is no sign-in, so no user account, email, or name is attached to telemetry. The session identifier is a random value generated fresh each time the widget bundle loads on a page; it is not persisted, and it does not link one page view to another.
  • No third-party analytics. The embedded bundle does not include the platform’s product analytics SDK. Telemetry goes only to your configured api.baseUrl.
Personal data does reach the platform when a visitor voluntarily submits a quote request. That is the quote form’s own payload, described in Overview, and it is separate from telemetry.

How it is sent and retained

Batches are debounced and sent in the background, and are also flushed when the visitor navigates away or closes the tab. The widget buffers at most a few hundred events of each kind at a time and discards the oldest beyond that, so a long session cannot grow unbounded. On receipt, the platform records each timing and action as a structured log entry, tagged with tenant ID, session ID, origin, and user agent. Field lengths and list sizes are capped on the server, and payload keys that would collide with reserved log fields are dropped.