Visitor analytics
An analytics identifier connects a website visitor to a Senler lead. It helps find the lead in a funnel source report without manually writing ClientID into a variable. Calls require a compatible Public API version.
Pass an identifier
Wait for widget readiness and authentication. Obtain the identifier from the tag installed on your site, then pass it as a string:
await SenlerWidget.setAnalytics({
provider: "yandex_metrica",
sourceId: "12345678",
identifiers: { client_id: "000123456789" },
visit: { yclid: "CLICK_ID_FROM_CURRENT_VISIT" },
});
The example values are illustrative. provider names the system, sourceId identifies the counter, stream, or pixel, and identifiers contains visitor identifiers. Do not convert IDs to numbers: leading zeroes can matter. Optional visit contains data for this specific visit, such as a session or advertising-click ID.
For GA4, use provider: "google_analytics", sourceId: "G-ABC123", identifiers: { client_id: "123.456" }, and visit: { session_id: "1780000000" }. A custom system can use provider: "my_analytics" and visitor_id. For self-hosted systems, include the installation address in sourceId, such as analytics.example:42, to separate identical numbers from different installations.
setAnalytics does not load a tag, create a dialog, or send an agent message. Await its Promise before sending a request that needs these data. Ordinary composer messages also capture the current analytics snapshot.
Update visit data
Another call replaces data only for provider + sourceId in the current instance. Both identifiers and visit are replaced in full; omitting visit clears this source's previous visit data. Other counters are unaffected.
To stop attaching a source to future messages:
await SenlerWidget.setAnalytics({
provider: "yandex_metrica",
sourceId: "12345678",
identifiers: {},
});
This does not delete information from saved events or the lead profile. Supply current data again after a page reload, visitor change, or instance creation. A failed call retains the previous snapshot. If analytics is blocked or unavailable, ordinary chat continues without it.
What is stored
The lead accumulates unique identifiers qualified by site, provider, counter, and type. Repeating the same ID creates no duplicate. The lead API exposes them in analytics_identifiers, which can be empty. They are not proof of identity or grounds for automatically merging leads.
Visit data stays in the originating event snapshot: source_context.analytics for a message and payload.analytics for a subscription. For a conversion, use the relevant event snapshot rather than an arbitrary ClientID from the profile. Queuing and retries preserve the message's original snapshot.
These data are not included in the agent instruction or context chips. In the funnel source, specify the same provider, counter, and identifier type. An ambiguous match to multiple leads creates no link.
Goals and conversions
setAnalytics stores the association but does not send external goals or conversions. For opening or accepted-message events, subscribe to instance events. Your site configures when a goal is reached and sends it.
messageSent does not mean contact details were collected or a payment completed. Send those conversions only after your site has successfully saved the data or confirmed the operation.
Example: three Yandex Metrica goals
Install the counter on your site and create widget_opened, chat_started, and contact_left goals to send through reachGoal. After loading a compatible SDK v3 script, use this initialization instead of the previous one; substitute your counter number and widget's channel_id:
const counterId = 12345678;
const goal = (name) => window.ym?.(counterId, "reachGoal", name);
const widget = SenlerWidget.create({ channel_id: "CHANNEL_ID" });
widget.on("open", () => goal("widget_opened"));
widget.on("messageSent", ({ source }) => {
if (source === "widget") goal("chat_started");
});
widget.registerAction("saveContact", {
description: "Save the phone number or email the visitor provided for contact.",
returnsResult: true,
payloadSchema: {
type: "object",
properties: { phone: { type: "string" }, email: { type: "string" } },
additionalProperties: false,
},
async handler({ payload }) {
await widget.updateLead({
phone: typeof payload.phone === "string" ? payload.phone : undefined,
email: typeof payload.email === "string" ? payload.email : undefined,
});
goal("contact_left");
return { saved: true };
},
});
open counts opening through the standard launcher and programmatic opening; an initially visible embedded widget does not emit this event. messageSent counts a server-accepted message, including queued messages; the source filter excludes programmatic ask requests. To count people who started a conversation, use “Converted users”: “Conversions” counts messages in this example.
saveContact is an agent action declared by the site, not a built-in event. Add this instruction to the agent: “When the visitor provides their phone number or email for contact, call saveContact with those details; confirm saving only after a successful result.” updateLead saves the contact in the current lead; a failure does not send the goal. For a site form, call updateLead and the goal from its handler after validating the data, without an agent action.
These browser goals do not require passing ClientID to the widget. To link it to the lead, use setAnalytics as described above. The site handler works while the page is open; for a conversion after it closes, configure server-side delivery using the originating event's analytics snapshot. Do not send the same conversion through both methods.
Limits
An instance allows up to 8 sources; each identifiers and visit map allows up to 8 string values of at most 256 characters. provider and map keys begin with a lowercase Latin letter, followed by lowercase letters, digits, or _, up to 64 characters total. sourceId accepts Latin letters, digits, ., _, :, and -, up to 128 characters. Do not supply secrets or access tokens.