Web Analytics script
Reference for the VitalSentinel Web Analytics script - snippet, data attributes, storage mode, custom events, conversions, ecommerce, authors, consent and troubleshooting.
The Web Analytics script (analytics.js) counts visitors, page views, traffic sources, events and ecommerce on your site. It feeds Web Analytics. It finds ecommerce events on its own on Shopify, WooCommerce, Magento and Squarespace.
For the install flow and the install check, see Tracking Scripts.
The Web Analytics snippet
Add this tag to the <head> of every page:
<script
src="https://analytics.vitalsentinel.com/analytics.js"
data-key="YOUR_TRACKING_ID"
async
></script>The script is small and loads with async, so it does not block your page. Copy the snippet with your real tracking ID from domain Settings > Tracking > Web Analytics > Install snippet. The Web Analytics script and the RUM script use the same tracking ID.
The Install snippet has two forms: HTML ("Paste into your site's <head>.") and Google Tag Manager ("Paste into a Custom HTML tag in GTM.").
Data attributes
The Web Analytics script reads these data-* attributes on its script tag:
| Attribute | Default | What it does |
|---|---|---|
data-key | required | The tracking ID of your domain. |
data-storage | none | The storage level: none, session or persistent. See Storage mode. |
data-spa | false | Page tracking in single-page apps: true, false or auto. See SPA support. |
data-cookie-domain | none | The cookie scope for sites on more than one subdomain, with persistent storage. |
data-debug | false | Writes log messages to the browser console. |
Web Analytics options in Settings > Tracking
The Web Analytics card in domain Settings > Tracking builds the snippet for you. Open Options to change these settings:
| Option | Choices | Snippet attribute |
|---|---|---|
| Storage mode | None (default), Session or Persistent | data-storage for Session or Persistent |
| Single page app (SPA) mode | Disabled (default), Enabled or Auto-detect | data-spa for Enabled or Auto-detect |
| Debug mode > Enable console logging | Off (default) or on | data-debug="true" when on |
VitalSentinel saves Storage mode and Single page app (SPA) mode for everyone on the domain. Debug mode stays in your browser only ("For development only. Kept in this browser.").
A change to these options does not change the snippet that is live on your site. Copy the snippet again and put it on your site after each change.
Page titles, search terms and article authors
The section Page titles, search terms and article authors in Options has two checkboxes. They are not part of the snippet. VitalSentinel applies them when the data arrives, so they save at once and need no change to your site.
- Do not store page titles or site-search terms: VitalSentinel stops storing both within about a minute. New traffic then shows pages by URL only, and you lose what visitors searched for. Use it if your pages or search box can show health, legal or other sensitive details about a visitor.
- Do not store article authors: VitalSentinel stops storing the byline within about a minute. The Authors report then stops filling in.
Text that VitalSentinel collected before stays in your reports until it ages out after three years. Only workspace owners and admins see these checkboxes.
Storage mode
The Storage mode controls what the script saves on the visitor's device. Select the lowest level that gives you the data you need. Lower levels collect less personal data and need less consent.
The script accepts only session and persistent. A missing attribute, or any other value, falls back to none. A typo such as persistant also falls back to none.
| Level | What it saves | Consent |
|---|---|---|
| None (default) | Nothing: no cookies, no local storage, no session storage. No device details are sent. | No consent banner needed for storage. |
| Session | One entry in the browser's session storage, which the browser clears when the visitor closes it. No cookies. | Requires visitor consent before you enable it. |
| Persistent | A few entries in the browser's local storage, so you can recognize returning visitors. Also collects device details such as screen and window size. | Requires visitor consent before you enable it. |
When you select Session or Persistent, the card says "You're the data controller for this snippet."
What the None mode does not collect
In the None mode, VitalSentinel joins the page views of one visit into one session on its servers. It keeps nothing on the device. The result is pseudonymous, not anonymous.
The Not collected in this mode line lists what you do not get:
- Returning visitors: "We cannot tell a first visit from a repeat one, so New visitors reads zero and each day's visitors are counted fresh."
- First campaign: the campaign that first brought a visitor "cannot be remembered between visits."
- Screen size: no screen size, window size, pixel ratio or touch support breakdown.
- Connection speed: no split between visitors on fast and slow connections.
- Shopify cart items: see Ecommerce tracking.
- Exact site-search terms: "Emails and long number runs are replaced before storage, which also affects long product codes."
You still get visitors, sessions, page views, entry and exit pages, traffic sources, campaigns, events and conversions. You also get the country, browser, operating system, device type and language.
Session and Persistent storage details
Session collects the same data as None, and also Shopify cart items. The main difference is where the visit is kept: in None, VitalSentinel joins the page views on its servers. In Session, the script keeps the session ID in the browser tab, with a 30-minute timeout. Thus, Session needs consent. With Persistent, a visitor ID recognizes returning visitors, and first-touch attribution works. VitalSentinel keeps the visitor ID for 180 days.
Persistent is the only level where the script reads device details: screen size, window size, pixel ratio, touch support and connection quality. The snippet from the app writes no cookies. The script writes a first-party cookie only if you add data-cookie-domain. That cookie also expires after 180 days.
Cookie domain for subdomains
If your site uses more than one subdomain, such as www.example.com and app.example.com, and you use persistent storage, add data-cookie-domain="example.com". The script then recognizes the same visitor on both subdomains. Without it, each subdomain tracks visitors separately.
<script
src="https://analytics.vitalsentinel.com/analytics.js"
data-key="YOUR_TRACKING_ID"
data-storage="persistent"
data-cookie-domain="example.com"
async
></script>Consent
session and persistent both store data on the visitor's device. Get the visitor's consent before you turn on either level. none stores nothing, so it needs no consent banner for storage.
Grant and withdraw consent from your banner
Keep None in the snippet and load the snippet first, on every page and for every visitor. The script stores nothing, so it counts the visit from the first page load. Then call the script from your consent banner. The section Using a consent banner? in the options shows these calls:
// Visitor accepted
window.VitalSentinelAnalytics.grantConsent('persistent');
// Visitor rejected, or withdrew a previous acceptance
window.VitalSentinelAnalytics.revokeConsent();Each call changes the script on the page now. You do not need to change the snippet or reload the page.
How grant and revoke work
The script does not remember the consent level between page loads. Your consent tool must call grantConsent() on every page load.
revokeConsent() sends the events that are already in the queue. It then goes back to none, clears the device and network details, and deletes the identifiers that it stored. Events that the script collected before still go out with the level that they had.
To read the current level, call getConsentLevel(). It returns none, session or persistent.
The built-in consent event
The script also listens for the vs-analytics-consent browser event. Your banner can send it in place of a direct call:
window.dispatchEvent(new CustomEvent('vs-analytics-consent', {
detail: { level: 'persistent' }
}));Do Not Track and Global Privacy Control
The script reads the Do Not Track and Global Privacy Control signals of the browser. Any value that is present and is not 0, false or unspecified counts as an opt-out. For these visitors:
- The script reads and writes no storage, whatever
data-storagesays. - VitalSentinel keeps only the country. The region, the city and the time zone stay empty.
- No engagement measurement runs: no scroll depth, active time, engagement score or rage clicks.
- The script still counts the page view, so the traffic stays in your reports.
If the visitor accepts your consent banner, call grantConsent(). The visitor's own choice wins over the browser signal, so the script uses the level from the call. A level that you write in the snippet does not win over the signal. While the grant applies, each batch that the script sends carries cg: 1. Then the VitalSentinel servers also ignore the DNT and Sec-GPC headers for that visitor.
To remember the grant, the script keeps the key vs_cg: in session storage for session, in local storage for persistent. The key lasts 180 days from the latest grantConsent() call. On a later page load, the script reads this key only if data-storage in the snippet is session or persistent. If the snippet keeps none, your banner must call grantConsent() again on each page load. revokeConsent() deletes the key, and the browser signal applies again.
Engagement measurement starts when the grant call comes. If the visitor withdraws consent, revokeConsent() stops it again.
Opt out and opt in
// Stop all tracking on this page load
window.VitalSentinelAnalytics.optOut();
// Start tracking again
window.VitalSentinelAnalytics.optIn();optOut() applies to the current page load only. Call it again on each page load.
What the Web Analytics script collects
Page views and sessions
- URL and page title
- Referrer
- Time on page and scroll depth
- The article author, on pages that publish one (see Authors)
- A session ID (pseudonymous), pages per session and session duration
- A visitor ID, only with
persistentstorage
A page that the browser restores from its back/forward cache counts as a page view. A return to a listing page with the Back button is a real view of that page. The engagement timer starts again for the new view.
Traffic sources
- UTM parameters: source, medium, campaign, term and content
- The referrer domain, and the referrer path without the query string
- The traffic source type, which VitalSentinel finds on its servers: direct, search, social, referral, email, newsletter, paid, paid search, paid social, AI search or internal
- First-touch attribution, only with
persistentstorage
Visitor behavior
- Scroll depth milestones: 25%, 50%, 75%, 90% and 100%
- Time on page, active and total
- Rage clicks: three or more clicks within one second and 100 pixels
- Clicks on outbound links
- File downloads
- Site-search queries
Before VitalSentinel stores a search term, it replaces email addresses, JWTs, phone numbers, card numbers, IBANs, national ID numbers and long runs of digits. It does this in every storage mode. Short product codes such as ABC-12345 stay as they are.
Device information
With session or persistent storage, or after grantConsent(), the script reads the screen resolution, window size, device pixel ratio, touch support and connection type.
In every mode, VitalSentinel finds the language, browser, operating system and device type on its servers. It uses the request headers that every browser sends. From the IP address, it finds the country, the region, the city and the time zone. It also marks traffic from data centers and hosting networks, so that it can remove bots. It does not store the IP address. The region, the city and the time zone do not show in the reports or the API yet.
VitalSentinel also makes a visitor key that changes every day.
Custom events
Track an event with JavaScript
window.VitalSentinelAnalytics.track('signup', {
plan: 'premium',
source: 'homepage'
});The JavaScript API is on window.VitalSentinelAnalytics. The shorter name window.VSAnalytics is the same object.
Track an event with data attributes
You can track clicks without JavaScript. Add data-vs-event with the event name to an element. The script sends every other data-vs-* attribute as a property of the event.
<button
data-vs-event="button_click"
data-vs-button-id="cta-header"
>
Sign Up Now
</button>When a visitor clicks the element, the script sends the event.
Add properties to all events
window.VitalSentinelAnalytics.setGlobalProperties({
environment: 'production',
appVersion: '2.1.0'
});The script adds these properties to all events after the call.
Other API methods
trackPageView({ path, title })sends a page view by hand.flush()sends all queued events now.identify()stays in the API, so old code on your site continues to work. It stores nothing and sends nothing, because VitalSentinel does not identify persons.
Conversions
A conversion goal counts the visits that do one thing at least once. You set up goals in Web Analytics, not in the script. In Web Analytics > Conversions, click Add a goal. In A visit converts when, select one of these:
- A page is viewed: enter the page address. Select Is exactly or Starts with.
- A custom event is sent: enter the Event name. This is "The name your site sends with the tracking script", the first argument of
track()or the value ofdata-vs-event.
You can also enter What one conversion is worth. See Conversions.
Ecommerce tracking
The Web Analytics script finds ecommerce events on its own on these platforms:
- Shopify
- WooCommerce
- Magento
- Squarespace
On Shopify and Squarespace, orders need one more step. On Shopify, add the custom pixel from VitalSentinel. On Squarespace, paste the snippet in the order page fields. See Shopify and Squarespace.
Ecommerce events
| Event | When it is sent |
|---|---|
product_view | A visitor views a product page. |
add_to_cart | A visitor adds an item to the cart. |
view_cart | A visitor views the cart page. |
begin_checkout | A visitor starts the checkout. |
purchase | A visitor completes an order. |
For each event, the script sends the product ID and SKU, the product name and category, the price and quantity, and the cart total. It also sends the currency of your store, and the order ID for a purchase.
Currency
The script reads the currency from your store. It never guesses a currency. It looks for the currency in this order:
- The currency code that your shop platform puts on the page, for example
EUR. - The currency in the price meta tags or the product data of the page.
- A currency symbol in the price that has only one meaning, for example €, £, CHF, R$, A$ or US$.
A symbol with more than one meaning gives no currency. Examples are a plain $, a plain ¥, kr and Rp. If the script finds no currency, it sends the event without one, and the reports use the currency of the domain. Set your currency in domain Settings > Site setup > Currency, so that the revenue figures always have a currency.
Platform notes
- Shopify: the script reads the cart from the visitor's own cart, which is on the visitor's device. Thus, it reads the cart only with
sessionorpersistentstorage. Withnone, it still countsview_cart, but without items, quantities or values.product_viewandadd_to_cartwork in every mode. The custom pixel sendsbegin_checkoutandpurchasewithout items, and it does not use the storage mode. - Magento, WooCommerce and Squarespace: the script reads the cart from the page, so the storage mode does not change what they send.
- Squarespace orders: the script reads orders from the Squarespace order confirmation, when the snippet is in the order page fields. It records an order only when it can read an order ID. Without an ID, VitalSentinel cannot prevent double counts, so it drops the order.
See Ecommerce for the reports.
Article authors
On article pages, the script reads the author from the structured data that the page publishes. It reads a JSON-LD article node, or a <meta name="author"> tag on a page that also says that it is an article.
The script reads nothing from CSS class names. A page that does not say that it is an article sends no author. Examples are a homepage or a category list. Co-authors stay together as one byline.
The author data feeds the Authors report. To stop it, tick Do not store article authors in the Web Analytics options. See Authors.
SPA support
A single-page app (SPA) changes the page in the browser without a full page load. SPA tracking is off by default (data-spa="false"): the script records only the first page load. In the options, this is Disabled ("Traditional multi-page navigation (default)").
To track page changes in an SPA, select Enabled ("Single-page app – track in-app route changes as pageviews"), or set data-spa="true". The script then finds page changes from the History API, the popstate and hashchange events, and the Navigation API in modern browsers. A change of only the # part of an address on the same path does not count as a new page view. If your site uses a hash-based router, call trackPageView() on each route change.
Auto-detect (data-spa="auto") is "Heuristic detection (legacy – not recommended)". It can give wrong results on server-rendered sites.
Track page views by hand
window.VitalSentinelAnalytics.trackPageView({
path: '/new-page',
title: 'New Page Title'
});Tracking IDs and hostnames
A tracking ID belongs to one domain. Web Analytics accepts a hit only from the hostname of that domain. VitalSentinel discards a hit from any other host before it gets to your reports.
This rule uses the exact host. If your workspace tracks example.com, then staging.example.com, docs.example.com and shop.example.com are different sites, and VitalSentinel drops their hits.
| Tracked domain | Hit from | Result |
|---|---|---|
example.com | example.com | Recorded |
example.com | www.example.com | Recorded: www counts as the same site in both directions |
www.example.com | example.com | Recorded |
example.com | staging.example.com | Discarded |
example.com | shop.example.com | Discarded |
example.com | example-com.translate.goog | Discarded |
To measure a subdomain, add it as its own domain in VitalSentinel and install its tracking ID. VitalSentinel keeps a hit when it cannot read the hostname of the page URL. It also keeps a hit when it cannot look up the domain of the tracking ID.
Visitors who read your site through Google Translate arrive on *.translate.goog. Web Analytics does not count these page views, but RUM Monitoring does. A funnel, signup or checkout step can be on its own subdomain with the tracking ID of the main site. Web Analytics then does not show that step.
Bot traffic
VitalSentinel removes bot traffic from your analytics: known bots, headless browsers and automated test tools. The check runs on the VitalSentinel servers, from the User-Agent header that every browser sends, so it works in every storage mode.
In the browser, the script checks for automation in every mode. It reads navigator.userAgent only with session or persistent storage.
Troubleshooting
Some problems affect both scripts: a Content Security Policy, caching plugins, Cloudflare Rocket Loader, consent tools, ad blockers and Google Tag Manager. For these, see Tracking Scripts.
Why does Web Analytics show no page views?
If the browser console shows an error for analytics.js, read it first. Make sure that the data-key value is the tracking ID of this domain. In the browser's Network tab, make sure that the script loads. If an ad blocker runs, turn it off for the test. If the page is on another host than the domain, see Tracking IDs and hostnames.
Why does Web Analytics not load with my Content Security Policy?
If your site has a Content Security Policy, the Web Analytics script needs two hosts. Add https://analytics.vitalsentinel.com to script-src, so that analytics.js can load. Add https://app.vitalsentinel.com to connect-src, so that the script can send its data. If analytics.js loads but no request goes to app.vitalsentinel.com, the connect-src directive is usually the cause.
Why does the console say "Missing data-key attribute"?
The Web Analytics script writes [VitalSentinel Analytics] Missing data-key attribute when its own script tag has no tracking ID. The script then does nothing. Common causes:
- You pasted the HTML form of the snippet into Google Tag Manager. Use the Google Tag Manager form.
- A plugin combined or rewrote the script tag. Exclude
analytics.vitalsentinel.comfrom JavaScript combine, minify and delay settings. - The
data-keyattribute is on another tag, or has a typing error.
Why does the console say "Tracking disabled (bot)"?
With debug mode on, the script writes [VitalSentinel Analytics] Tracking disabled (bot) when it finds an automated browser. Selenium, Puppeteer, Playwright and other headless browsers send no data. VitalSentinel also removes known bots on its servers. To test the script, open your site in a normal browser.
Why does Web Analytics count only one page for each visit?
Your site is probably a single-page app (SPA), and SPA tracking is off. Then the script records only the first page load. Select Enabled in Single page app (SPA) mode, or set data-spa="true". Copy the snippet again and replace it on your site. See SPA support.
Why do I see duplicate page views?
In an SPA, do not call trackPageView() by hand when SPA tracking is on. Use data-spa="false" and track by hand, or use data-spa="true" and let the script find the page changes.
Why does ecommerce tracking not work?
Make sure that your store runs on Shopify, WooCommerce, Magento or Squarespace. Other platforms send no shop events. Make sure that the product pages use the standard structure of the platform. On Shopify, cart contents need session or persistent storage.
Turn on debug mode and open a product page. The console shows Ecommerce platform detected: and the platform name, or No ecommerce platform detected. For a custom store, send your own events. See Custom events.
Why are orders missing in Ecommerce?
The script records an order only on the order page of your store, and only when it can read an order ID. Without an ID, VitalSentinel cannot prevent double counts, so it drops the order.
- On Shopify, add the custom pixel in Customer events. Shopify checkout pages do not use your theme code.
- On Squarespace, paste the snippet in the Order status page and Order confirmation page fields.
- On WooCommerce and Magento, make sure that the snippet runs on the order pages, not only on the shop pages.
See Platform Guides.
Why does New visitors show zero?
In the None storage mode, VitalSentinel cannot tell a first visit from a repeat visit, so New visitors reads zero. To recognize returning visitors, use Persistent storage with the visitor's consent.
Why does my storage setting not work?
The script accepts only session and persistent in data-storage. Any other value, such as the typing error persistant, falls back to none. Copy the snippet again from domain Settings > Tracking, so that the value is correct. Do Not Track and Global Privacy Control also force none for that visitor, until your consent banner calls grantConsent().
Why are visits from a subdomain or Google Translate missing?
Web Analytics accepts hits only from the exact host of the domain and its www form. It discards hits from shop.example.com, staging.example.com and *.translate.goog under the tracking ID of example.com. To measure a subdomain, add it as its own domain. See Tracking IDs and hostnames.
How do I see what the Web Analytics script does?
Add data-debug="true" to the script tag, or tick Enable console logging in the options and copy the snippet again. Then open the browser console and look for messages that start with [VitalSentinel Analytics]. Remove debug mode when you are done.
Related
- Tracking Scripts - install both scripts and check the installation
- Platform Guides - install steps for each CMS and framework
- Web Analytics - what the Web Analytics data shows
- Conversions - goals and conversion reports
- Data Privacy - how VitalSentinel handles visitor data
RUM script
Reference for the VitalSentinel RUM script - snippet, data attributes, consent mode, SPA support, JavaScript API, collected data and troubleshooting.
Google Search Console
Connect a Google account to VitalSentinel, choose the right Google Search Console property, link it to a domain, reconnect, and fix common problems.