Web analytics: website visitors, the Sensever pixel and data collection
The Sensever widget code on your site is also an analytics pixel. On every page where it is installed, it records the page views and active time of every visitor, not only of those who write to the chat. Your team sees them in the "Web analytics" section of the left panel: people, visits, pages, sources, funnels and each person's history, next to your conversations with them.
This guide is for a site owner and their developer: what is collected and what is not, how consent works, how to send your own events from the page and from your server, how to forward Google Tag Manager events, and how long the data is kept.
In short
Nothing extra to install: the standard widget code from the project settings is the pixel.
Free on every plan, with no limits on visits or events.
No cookies. Personal data (name, email, phone) never goes into analytics; it stays with the conversation.
You don't create goals in Sensever. Any event your site sends appears on its own after the first send.
The "Web analytics" item is in the left panel for everyone who is a member of at least one project.
Turning it on
Open "Projects", select the project and add your site under "Sites and installation", with every HTTPS address the site uses (https://example.com and https://www.example.com are different addresses).
In the "Widget code" block, choose WORLD or RU and copy the code.
Paste it once on every page, before the closing </body> tag. In a single-page application, install it once in the shared shell.
Open the site and click through a few pages, then open "Web analytics", choose the project site and the period "Today".
Pages are recorded only from the addresses added to the site, and only while "Show widget" is on in "Widget settings": a hidden or switched-off widget records nothing. Installation details: Sensever widget: installation and setup.
What is collected
Data | When | Details |
|---|---|---|
Page view | On page load and on every navigation inside a single-page site (pushState, replaceState, popstate) | The page path without the query string, the page title (up to 200 characters), the referrer (only another site: its address without the query string) |
Campaign | With the page view | utm_source, utm_medium, utm_campaign, utm_term, utm_content (up to 200 characters each) |
Ad click | On the landing page | Only the ad network's name: gclid, gbraid, wbraid → Google; msclkid → Microsoft; yclid → Yandex; fbclid → Meta. The click id itself never leaves the browser |
Device | With the page view | Browser and system, screen size, touch screen, window class (phone up to 600 px, tablet up to 1024 px, computer), browser language and up to 5 preferred languages, time zone |
Country and network | Computed from the IP address of the request | Country, the network (provider) name, and network signals: Tor, VPN, proxy, data centre, "Probably VPN" |
Active time | About every 30 seconds of counted time and when the visitor leaves the page | Time while the tab is visible, in focus and the visitor's last action (scroll, click, key, touch, pointer move) is no older than 60 seconds |
Your events | When your page calls SenseverWidget.track() or your server sends an event | The event name and up to 20 simple properties |
A visit ends after 30 minutes without activity. A new campaign (utm_campaign) or a click from another ad network also starts a new visit.
The network signals use only what the visitor's request shows to any site: public lists of Tor exits, VPN and hosting ranges, proxy headers, and a time zone that doesn't match the country of the address. Sensever never tries to find out the real address behind a VPN or proxy. "Data centre" also covers cloud relays and corporate networks: it is a label, not an accusation.
What is not collected
No message texts, attachments or form contents. The pixel doesn't read what visitors type on your pages.
No query strings: only the path of the address. Tokens, search terms and order numbers in the part after "?" are not recorded (except the utm_ values and the ad network's name).
No click ids of ad networks, only the network's name.
No cookies of your site and no third-party cookies. The pixel doesn't read your site's dataLayer either (see "Google Tag Manager" below).
No personal data in analytics. Names, emails, phones and your own visitor fields from SenseverWidget.identify() are stored with the conversation in the chat, not in analytics. "Web analytics" shows them next to a person only to your project's team.
Don't put personal data into event properties. As a precaution, properties of server events whose names look personal (containing email, phone, passport or password, or named name, first_name, last_name, address, zip, birthday, token, ip, id, user_id, customer_id and similar) and values that look like an email address or a phone number are removed before they reach analytics.
Consent
By default every visitor is counted with a visitor number: a random id (a1.…) that the widget keeps in your site's browser storage (localStorage, not a cookie). It lets Sensever recognise a returning visitor and connect their visits to a conversation.
If your site asks for consent first, turn on "Collect visitor statistics only after the visitor's consent" in "Widget settings" of the site. Until the visitor agrees, they are counted without cookies:
The widget creates no visitor number and stores none on the device.
Visits are grouped by a key that changes every day (computed on our server from the site, the IP address and the browser; the daily secret is deleted after two days). Two days of the same person can't be linked, and such a visit is never linked to a person, a device or a conversation.
No IP address is stored for these visits. The country and network signals are computed from the request and the address is dropped.
They appear in "Web analytics" as "Visitor without cookies", with the "Without cookies" tile and filter. "New" counts only visitors with consent.
A visit that crosses midnight UTC is split in two; two people on one network with the same browser may count as one visitor for that day.
How to tell the widget that the visitor agreed:
// Your consent banner, after the visitor clicks "Accept":
SenseverWidget.consent(true);
// The visitor withdrew consent: count without cookies again.
SenseverWidget.consent(false);The choice is remembered in the browser for your site. If your site already uses Google Consent Mode, nothing else is needed: the widget reads the latest analytics_storage signal from gtag('consent', 'default' | 'update', …) in the dataLayer, and "granted" counts as consent. SenseverWidget.consent() takes priority over Consent Mode.
What changes after consent: the current page is recorded again with a visitor number and starts a new visit (the visit without cookies is not merged into it). From then on, the visitor's visits are connected, SenseverWidget.activityId() returns their number, a conversation shows their visits in "About the request", and a signed identify can link their devices into one person.
When the switch is off, consent(true) changes nothing: every visitor is already counted with a number.
Pages you don't want recorded
In the project, open the "Rules" tile, choose the site and add a rule with the action "Site analytics", the trigger "Page opened" and "Don't record analytics" in "Widget events on these pages". Conditions are the same as for other widget rules: pages (all, only, or all except; the address contains, is, or starts with; a value starting with "/" is compared with the path, otherwise with the whole address; the part after "?" is not checked), first or returning visit, team online or not, device, and visitor data.
On a page where analytics is off:
nothing from the page is saved in the visitor's history: no page view, no active time, no track() events, so "Web analytics" and "About the request" don't see the page;
the widget sends nothing to Google Tag Manager or gtag from that page;
the chat itself keeps working, and the sensever-widget event on window still arrives for your own code, with analytics: false.
If several rules match a page, the last one in the list wins, so you can turn analytics off for /account and back on for /account/help with "Record analytics" below it. "Record analytics" can't turn on what is off in the widget settings. Rules are checked on every page load and on every navigation inside a single-page site.
The data-analytics="off" attribute on the script tag only stops widget events going to your Google Tag Manager or GA4. It does not stop the pixel; use a rule for that.
Events from the page: track()
Send what visitors do on your site with one line. The current installation code defines SenseverWidget from its first line, so you can call it anywhere on the page, even before the widget has loaded:
<script>SenseverWidget.track('order_save');</script>SenseverWidget.track('cart_abandoned', {total: 129, items: 3, plan: 'pro'});The event name matches
^[a-z0-9_.-]{1,64}$: lowercase Latin letters, digits, underscore, dot and hyphen, for example order_save, signup.done, form-sent. A name that doesn't match is not sent; the browser console shows a warning.Properties: up to 20; property names match
^[A-Za-z0-9_.-]{1,64}$; values are a string up to 500 characters, a number, or true/false. Nested objects, arrays and empty values are dropped.The event is recorded in the visitor's current visit, with the page path, and is also available to the widget's auto-messages ("Event on the site").
Events are recorded in both modes: with a visitor number and without cookies (then only within that day's anonymous visit).
Nothing to create in Sensever: a new name appears in "Triggers" of the site's widget and in "Web analytics" after the first send. You can use it right away in funnels and in auto-messages.
The installation code and the call queue
Since 15.10.2026, the installation code from the project settings starts with a small stub, the same idea as the Meta pixel's fbq. It defines SenseverWidget with open, close, toggle, identify, track, reset and consent. Calls made before the widget script has loaded are kept in SenseverWidget.q and run, in order, as soon as it loads. The World code looks like this (copy yours from the project: it contains your site's key):
<script>window.SenseverWidget=window.SenseverWidget||{q:[]};['open','close','toggle','identify','track','reset','consent'].forEach(function(m){SenseverWidget[m]=SenseverWidget[m]||function(){(SenseverWidget.q=SenseverWidget.q||[]).push([m,[].slice.call(arguments)])}});</script>
<script src="https://sensever.com/widget/loader.js?v=events-20260922"
data-site="w1.YOUR_PUBLIC_KEY" data-lang="auto" async></script>The RU code carries the same stub inside its single script block.
If your site has the code from before 15.10.2026, copy the code again from "Widget code" and replace the old one. With the old code, SenseverWidget doesn't exist until the script loads, and a track() call placed earlier on the page fails with an error. If you added your own stub with a q queue, as earlier versions of the guide suggested, it keeps working.
SenseverWidget.activityId() isn't part of the stub because it returns a value: call it after the widget has loaded (see "Events from your server" below).
Who the visitor is: identify and reset
SenseverWidget.identify({id: 'u-42', name: 'Ivan Petrov', email: 'ivan@example.com', phone: '+1 555 010 2030', fields: {plan: 'pro'}});
// When the user signs out of your site:
SenseverWidget.reset();identify tells the widget who the visitor is: the id on your site (up to 200 characters), name, email, phone and up to 20 fields of your own. Each call replaces the previous data. The widget keeps it in your site's browser storage until reset(). The data goes to the chat, not to analytics: the chat saves it for the visitor once they have a widget conversation, and your team sees it in "About the request" under "From the site" and next to the person in "Web analytics".
identify from the browser is not a sign-in: any visitor can call it with someone else's email, so the team sees such data marked "Sent by the visitor's browser and not verified". To confirm it, add user_hash, a signature made on your server with the site's server key. How to compute it: Sensever widget: installation and setup.
One person on several devices. When a page calls identify with a valid user_hash, the chat links that device's visitor number to the person. "Web analytics" then shows the person as one row, with the number of devices and all their visits and events. An identify without a signature is never used for linking, and visits without cookies are never linked.
reset() makes the widget forget the identify data on this device. Data the chat already saved for the team stays.
Events from your server
Payments, deliveries and CRM changes happen on your server, not on the page. Send them to the same site events API that the auto-messages use; since 14.10.2026 such an event also appears in the person's history in "Web analytics", marked "from the server" (events from the page are marked "on the site").
POST https://chat.sensever.com/api/sites/events
Authorization: Bearer s1.YOUR_SERVER_KEY
Content-Type: application/json
Idempotency-Key: order-1001-paid
{"user": {"id": "u-42", "activity_id": "a1.Xy3...22 characters"},
"event": "order.paid",
"props": {"order_id": "1001", "total": 129, "currency": "EUR"},
"occurred_at": "2026-10-14T12:00:00Z"}Authorization: the site's server key s1.… as a Bearer token. Issue it in "Events and API" of the site's widget; it is shown once, and issuing a new one switches the old one off at once (also for private comments and identify signatures). Requests from a browser (with an Origin header) are refused with 403: the key must stay on your server.
user: at least one of id (your user id, up to 200 characters), email, phone, activity_id.
activity_id: the visitor number of the device,
a1.followed by 22 characters. Read it on the page with SenseverWidget.activityId() after the widget has loaded and pass it to your server, for example with the order form. It is null when the visitor is counted without cookies.event: the same rule as in the browser,
^[a-z0-9_.-]{1,64}$. props: up to 20 simple values (a string up to 500 characters, a number, true/false). occurred_at: optional, RFC 3339. In "Web analytics", an event older than 24 hours is placed at "24 hours ago".Idempotency-Key (or an event_id field), up to 200 characters: a repeat with the same key doesn't create a second event and answers 200 with the same id.
Answer: 202 with id, status and deliveries, plus an activity field: sent means the event went into the person's history; skipped means there was nobody to attach it to (only an email or phone of a person Sensever doesn't know). An invalid body answers 422 with the field name, a wrong key 401, more than 600 events a minute per site 429.
How Sensever finds the person in "Web analytics": user.id becomes a project-wide person key (the same on all sites of the project; your id itself is not stored in analytics); activity_id points at the device. Without them, the visitor the chat already knows by a signed identify with this id, email or phone is used. The event joins the device's current visit if one is going on, otherwise it goes straight into the person's history.
Shops and form builders that can only post a form can use the incoming webhook address from "Events and API" instead; see "Events from your system" in Sensever widget: installation and setup.
Google Tag Manager
The pixel does not read your site's dataLayer. Events you already push for Google Tag Manager don't reach Sensever until you forward them. There are two ways.
One tag for all your events.
In Google Tag Manager, open Variables → Configure and enable the built-in variable Event.
Create a trigger of the type Custom Event. Event name: a regular expression of your events, for example
^(order_save|signup_done|form_sent)$, with "Use regex matching" turned on.Create a Custom HTML tag with the code below and attach the trigger.
<script>SenseverWidget.track({{Event}});</script>Or one tag per event, with a fixed name and, if you like, properties from Data Layer Variables:
<script>SenseverWidget.track('order_save', {total: {{DLV - order total}}});</script>The names must match the track() rule: lowercase letters, digits, _ . -. GTM's own events (gtm.js, gtm.dom, gtm.click…) and names with capital letters would either clutter your history or be refused, so keep the trigger limited to your own events. The tag works on any page with the current installation code, even if it fires before the widget has loaded. There are no goals to create in Sensever: every new name appears on its own after the first send.
The opposite direction, the widget's own events (window opened, channel chosen, message sent) going into your Google Tag Manager and GA4, is described in Sensever widget in Google Tag Manager and GA4.
The "Web analytics" section
Choose the project site at the top and the period: "Today", "7 days", "30 days" or "90 days". The left column of the section has "People", "Visits", "Pages", "Sources" and "Funnels".
Summary for the period (above the lists): visits, people, new visitors, average active time, pages per visit, visits without cookies, visits from ads by network, the share of VPN / proxy visits, a chart of visits by day, top countries and top sources.
People. One row per person: a known contact by name, otherwise "Visitor" with the last characters of their number, or "Visitor without cookies". Search by name, e-mail, phone or id; the search by personal data goes through your project's conversations.
Visits. Every visit with its start, duration, active time, pages, source, country and device. Search by page, site, country or network.
Pages. Views, visitors and entries for each page. Search by address or title.
Sources. Channels (Direct, Search, Social networks, Other sites, Campaigns, Own site, Ads), sites, campaigns, ad networks, devices and countries.
Filters: country, source, ad network, device, "New only", "VPN / proxy", "Without cookies" and "Include bots" (bots are left out by default). Lists can be sorted by last or first visit, visits, pages, active time and other columns.
Visitor card. First and last visit, number of visits, devices, then "Events" (your track() and server events) and every page. If the person wrote to your project, the card shows their name, contact and photo from the conversation, and the buttons "Open request" and "Write". The name and contacts from the conversation are shown only to project staff who can see that person's latest request.
Visit card. Started, duration, active time, pages, source, came from, first page, UTM, ad click, country, device, browser, system, screen, language, time zone and network, with the list of the visit's pages and events.
In a conversation. In "Requests", the "About the request" panel of a website chat request shows the visitor's visits, pages viewed, device, language, local time, whether they are on the site now, the source of the visit and UTM, and "From the site" with the identify data and recent events. Requests from messengers have no site visits. When a visitor was counted without cookies, the panel says that no site visits are linked to the request.
Funnels
A funnel shows how many people take the steps you choose, in order, for example: pricing page → sign-up → payment. Open "Web analytics" → "Funnels" → "New funnel".
Steps: from 2 to 8. Each step is a "Page visit" (the page address is, starts with, or contains a value; compared with the path without the query string, case-sensitive) or an "Event" (a track() name from the page or a server event, optionally with "property = value").
All steps within: 1, 3, 7, 14, 30, 60 or 90 days, counted from the first step.
Counting: each person is counted once; a person linked across devices counts as one; visitors without cookies only within one day. A step counts when it happens after the previous one and within the time limit.
Report: people at each step, the share of step 1 and of the previous step, drop-off, and the median time between steps. Breakdown by source, ad network, country or device (of the first step's visit), and "Compare with the previous period" of the same length.
Who can change them: the project's owner and admins create, edit and delete funnels (up to 50 per site). Other members of the project see them. Deleting a funnel deletes only its settings; visits and events stay.
If a funnel takes too long to count for a long period, choose a shorter one.
Retention and privacy
Data | How long |
|---|---|
Visits, page views, active time and events of your site's visitors | 13 months |
Full IP address of a visit | 30 days, then only the network part (IPv4 /24, IPv6 /48). The country is computed before that |
Visits without cookies | No IP address and no visitor number are stored at all |
Identify data (name, email, phone, id on your site, your own fields) | In the chat, with the visitor of the conversation; it is removed together with the visitor or the site |
Conversations, messages and files | Not affected by these terms |
Analytics data is stored without names, emails or phones: a person there is a random visitor number or a key derived from your user id that can't be turned back into the id. Deciding whether your visitors must give consent, and telling them about the analytics in your privacy policy, is up to you as the site owner; the consent switch and SenseverWidget.consent() exist so that you can follow your own rules.
Checking that it works
Open your site in a normal browser window (not one with a tracker blocker) and click through a few pages.
In the browser developer tools, Network tab, you should see POST requests to sensever.com/widget/e (or sensever.ru/widget/e when the RU code loaded the widget from .ru) answered with 204.
In the console, run
SenseverWidget.track('test_event', {source: 'console'}), thenSenseverWidget.activityId(): you should get a1.… (or null with consent required and not given).Open "Web analytics" → "Visits", choose the site and "Today": your visit should be there with its pages and the test_event under "Events".
With the consent switch on, check that your visit first appears as "Visitor without cookies" and, after you accept the banner, as a new visit with a visitor number.
Troubleshooting
No visits at all. Check that the page address is among the site's addresses (including www), that "Show widget" is on, that the code is the one for this site, and that your CSP allows the widget (see the setup guide). The very first page of a new visitor is sent once the widget window has loaded.
Some pages are missing. Check the "Site analytics" rules: a "Don't record analytics" rule higher or lower in the list may match them.
Everyone is "Visitor without cookies". The consent switch is on and your banner doesn't call SenseverWidget.consent(true), or Consent Mode keeps analytics_storage denied.
track() says "SenseverWidget is not defined". The page has the old installation code: copy the current one.
An event doesn't appear. Check the name against
^[a-z0-9_.-]{1,64}$(no capital letters or spaces) and the console warning. In GTM, check the trigger in Preview mode.A server event answers activity: skipped. Send user.id or user.activity_id; an email or phone alone works only for a visitor the chat already knows by a signed identify.
Visitors from ad blockers. Browser extensions that block trackers may block the pixel too; such visits are not counted.
FAQ
Do I need to create goals or events in Sensever? No. Send an event with track() or from your server, and it appears in "Web analytics", "Triggers" and the funnel editor after the first send.
Is it paid? Are there limits? No. Web analytics is free on every plan and has no limits on visits or events.
Does it replace Google Analytics or Yandex Metrica? It can run alongside them. The widget doesn't load any third-party counters and doesn't change what they collect.
Does the pixel set cookies? No. With consent (or with the consent switch off), the visitor number is kept in your site's localStorage; without consent nothing identifying is stored on the device.
Can I see who a visitor is? Only if they wrote to your project or your site identified them: then the team sees the name and contacts from the conversation. Analytics itself stores no personal data.
Do I need separate code for a single-page application? No. Navigation with pushState, replaceState and the browser's back button is recorded as page views.
What about visitors who use a VPN? They are counted like anyone else and marked with the network signal, so you can filter them with "VPN / proxy".
Kommentare