Skip to content
  • There are no suggestions because the search field is empty.

What Is User Analytics?

User Analytics counts the visits that AI assistants such as ChatGPT, Perplexity or Google AI send to your website, page by page, next to the citations OtterlyAI already tracks. It needs one snippet on your site and nothing else.

Available on: Standard, Premium and Custom Enterprise plans.


How it works

You add one snippet to your site. Each page view sends one small request to OtterlyAI. 

The AI assistant that sent the visitor is counted once, on the first page view. Later page views count as visits from your own site. On a site with a consent banner, the first page view after the visitor accepts is credited to that assistant as well, so the visitor counts as its referral user.

Follow the installation instructions below:


Install the snippet

In OtterlyAI, open Data sources, choose Add data source, pick User Analytics, select the domain and copy the snippet.

You can copy it again later from the row's View tracking code action. It looks like this, with your own id in the init line:

<script async src="https://t.otterly.ai/seti.js"></script>
<script>
  window.seti = window.seti || function () { (window.seti.q = window.seti.q || []).push(arguments); };
  seti('init', 'YOUR_TRACKING_ID');
  seti('pageview');
</script>

Paste it inside <head> on every page, and keep init before pageview. A tag manager works too: add the snippet as a custom HTML tag that fires on every page. OtterlyAI checks installations by watching what the page sends, not by reading its HTML, so a tag-manager install verifies like any other.

Each page view sends one small request to OtterlyAI: the page URL, the site the visitor came from, the utm parameters of the address and, where your consent banner allows it, a random visitor id. See Consent and Privacy and consent below.


Single-page apps

  • Paste the snippet once, in the HTML <head>. It sends the first page view.
  • On each route change, call seti('pageview') once the new route has rendered. A repeat of the view just counted is ignored, so calling it on the first render too is fine.
  • If the app keeps one <link rel="canonical"> for every route, or updates it late, pass the page: seti('pageview', { url: '/pricing' }).
  • If the app passes url, replace the snippet's seti('pageview') with the app's own first seti('pageview', { url }), or the landing page counts twice.
  • Hash routers (/#/pricing): the part after # is never sent. Pass the route's path only: seti('pageview', { url: location.hash.slice(1).split('?')[0] }). Never pass tokens or query values you don't want stored.
  • Page views after the first count as visits from your own site. The AI assistant that sent the visitor is counted once, on the first page view. On a site with a consent banner, the first page view after the visitor accepts is credited to that assistant as well, so the visitor counts as its referral user.

Content Security Policy

If your site sets a Content Security Policy, allow the inline part with a nonce or a hash, as for Google Analytics, or move the two seti lines into your app's own bundle. Allow https://t.otterly.ai in script-src and img-src.

Verifying the installation: the test visit

Once the snippet is on your site, the Data sources row shows Waiting for your test visit with a link, Open the test address, and a copy button. The address is your homepage with ?useranalytics=firstvisit added:

https://www.example.com/?useranalytics=firstvisit

Open it in your browser. The snippet notices the parameter and sends one verification request instead of a page view. Within a few seconds the row changes to Verified. The test visit is never counted, so you can open the address as often as you like.

One limit: some sites remove unknown parameters from the address before the page runs. On such a site the test address sends an ordinary page view, which counts as one visit from your own browser and verifies nothing. Use Check installation there instead.


Check installation

Check installation is available in the setup window before you save, and later as an action on the Data sources row. OtterlyAI opens your homepage in its own browser as a test visit, waits up to 30 seconds for the snippet's request, and tells you what it saw. The check is never counted as a visit, and it can run once every 30 seconds per site.

  • Script is present on the page. The snippet fires. The row shows Verified.
  • The page sends the id of another of your sites. The snippet of another site in your workspace was pasted here. Copy this site's snippet from its row and replace it.
  • No pixel from this page. The page loaded, but nothing was sent. The snippet is missing, sits outside <head>, or pageview never runs. On a single-page app, see the section above.
  • We could not load your page. Your site did not answer, or blocked our visit. The message names the cause, for example a certificate problem or a firewall. A site with bot protection may always block the check; open the test address yourself instead, it verifies the site from your own browser.

The check never blocks saving. A site behind a tag manager or bot protection can be saved without a verdict and verified by the test visit.


Privacy and consent

Consent

The snippet shows no banner of its own. It follows the one your site shows.

If your consent banner uses Google Consent Mode v2, which Cookiebot, OneTrust, Usercentrics, Didomi and most others do, there is nothing to configure. While the banner is unanswered, page views are counted without a visitor id and nothing is stored in the browser, so they count as views but not as unique visitors. Once the visitor accepts, page views carry the visitor id, and the first of them is credited to the source that brought the visitor, so a visitor who arrived from ChatGPT and then accepted still counts as a ChatGPT referral user. If the visitor declines, nothing is sent and the visitor id is removed from the browser.

If your banner does not use Consent Mode, or runs inside Google Tag Manager's own consent templates, page views are counted without a visitor id until you tell the snippet yourself:

seti('consent', 'granted');  // once the visitor accepts
seti('consent', 'denied');   // when the visitor declines

Or load the snippet through a Tag Manager trigger that fires after consent. A site without a consent banner sends page views as before.

The test visit and Check installation work whatever the consent state. They send the site id and the page address only, never a visitor id.

Privacy and consent

The snippet keeps a random visitor id in the browser's local storage for your site, so OtterlyAI can count unique visitors over a period. On a site with a consent banner it does so only once the visitor has accepted, see Consent above; after that it also keeps, in the browser's session storage, the site and campaign the visitor arrived from, until the next page view. It sets no cookie and derives nothing from the person. The visitor id is still a persistent identifier on the visitor's device: your privacy policy must disclose OtterlyAI tracking, and where the law requires consent, your consent banner must cover the snippet, the same way it covers other analytics tags. You confirm this when you save the data source.