diff --git a/_docs/10_general/03_how-to-use-url-params.md b/_docs/10_general/03_how-to-use-url-params.md index baa5b9cf..ddbc1dc4 100644 --- a/_docs/10_general/03_how-to-use-url-params.md +++ b/_docs/10_general/03_how-to-use-url-params.md @@ -4,7 +4,7 @@ menu: How to use URL params category: general permalink: /how-to-use-url-parameters excerpt: "You can add URL parameters to see where your customers are coming from." -last_modified_at: 2026-10-17 +last_modified_at: 2026-10-29 --- There are a few ways we determine where a visitor comes from. We automatically detect the previous page (referrer) from the visitor's browser, but you can also add a URL parameter to override this and set a custom referrer. @@ -43,7 +43,7 @@ The UTM codes will show up on the dashboard in the "Referrals" dropdown menu: [Read the UTM guide](https://buffer.com/library/utm-guide/) at Buffer to learn more about UTM codes. -We drop non-UTM parameters from the URLs. If you want to allow more URL parameters, for example, `project-id`, use our [allow params](/allow-params)-feature. +We drop non-UTM parameters from the URLs. From script version 12, we do collect the names of parameters that have a value, like `gclid`, but not their values, so you can tell paid from organic traffic. You can turn this off with [ignore metrics](/ignore-metrics). If you want to allow more URL parameters, for example, `project-id`, use our [allow params](/allow-params)-feature. ### Forbidden characters diff --git a/_docs/10_general/10_what_we_collect.md b/_docs/10_general/10_what_we_collect.md index 26e7256f..d486c15e 100644 --- a/_docs/10_general/10_what_we_collect.md +++ b/_docs/10_general/10_what_we_collect.md @@ -4,7 +4,7 @@ category: general permalink: /what-we-collect hidden: true excerpt: "Simple Analytics only collects privacy-insensitive data. Here is a list of what we do and don’t collect from your visitors." -last_modified_at: 2026-10-17 +last_modified_at: 2026-10-29 --- Not collecting any information would be silly and unrealistic for an analytics tool. We do collect information that is necessary to show you _simple_ analytics, but unlike other analytics tools, we don't collect more than absolutely necessary. Here is a list of what we **do and don't** collect from your visitors. @@ -131,7 +131,7 @@ None of these IDs are linked to a person or personal data, and none are stored o > We **partially collect** and **partially store** URLs -Too much information in the URL can be confusing and can make your stats messy. We only collect and store the first part of the URL. If an URL looks like this `https://example.com/index.html?search=keyword#top` we will only store `https://example.com/index.html`, also known as the protocol (`https`), hostname (`example.com`), and pathname (`/index.html`). +Too much information in the URL can be confusing and can make your stats messy. We only collect and store the first part of the URL. If an URL looks like this `https://example.com/index.html?search=keyword#top` we will only store `https://example.com/index.html`, also known as the protocol (`https`), hostname (`example.com`), and pathname (`/index.html`). From script version 12, we also collect the names of URL parameters that have a value, like `search`. We don't collect their values, except for [UTM codes](#utm-parameters) and [allowed parameters](/allow-params). Read more on [using URL parameters](/how-to-use-url-parameters). ### Referrers @@ -195,7 +195,7 @@ When a visitor scrolls on a page we record how far they scrolled. We do store th ### Script settings -We send some script settings along with the page view. To identify the embed script and check if the page view comes from a robot. The script settings include things like `version: script_version_2`, `robot: true`. +We send some script settings along with the page view. To identify the embed script and check if the page view comes from a robot. The script settings include things like `version: script_version_2`, `robot: true`. From script version 12, we also send the URL of the embed script without its query string. ### Do Not Track diff --git a/_docs/10_general/15_metrics.md b/_docs/10_general/15_metrics.md index 36b41af7..4d2a0bad 100644 --- a/_docs/10_general/15_metrics.md +++ b/_docs/10_general/15_metrics.md @@ -3,7 +3,7 @@ title: Metrics category: general permalink: /metrics excerpt: "We never track visitors so the data below is never linked to one specific visitor. Here is a list of metrics we collect." -last_modified_at: 2026-10-17 +last_modified_at: 2026-10-29 hidden: true redirect_from: - /data-points @@ -39,7 +39,7 @@ To know where customers come from, we store the page's referrer. This means that For example `https://simpleanalytics.com/?utm_source=newsletter` -The part after the `?` is called [URL parameters](/how-to-use-url-parameters). We only keep the UTM codes (`utm_source`/`ref`, `utm_medium`, `utm_content`, `utm_campaign`, `utm_term`) and drop all other URL parameters, unless you [allow them](/allow-params). The UTM codes are something that the customer adds to the URLs. They are usually generic terms like "newsletter_may" or "twitter_campaign_2". Don't put personal data in UTM codes. [See below][5]. +The part after the `?` is called [URL parameters](/how-to-use-url-parameters). We only keep the UTM codes (`utm_source`/`ref`, `utm_medium`, `utm_content`, `utm_campaign`, `utm_term`) and drop all other URL parameters, unless you [allow them](/allow-params). From script version 12, we also collect the names of the other parameters that have a value, but not their values, unless you [ignore `querykeys`](/ignore-metrics). The UTM codes are something that the customer adds to the URLs. They are usually generic terms like "newsletter_may" or "twitter_campaign_2". Don't put personal data in UTM codes. [See below][5]. ### Unique @@ -89,7 +89,7 @@ To know which type of device the visitor used, we store the user agent. This is
-We send some script settings along with the page view. To identify the embed script and check if the page view comes from a robot. The script settings include things like `version: script_version_2`, `robot: true`. +We send some script settings along with the page view. To identify the embed script and check if the page view comes from a robot. The script settings include things like `version: script_version_2`, `robot: true`. From script version 12, we also send the URL of the embed script without its query string. ### Dimensions diff --git a/_docs/20_install-script/00_v12.md b/_docs/20_install-script/00_v12.md new file mode 100644 index 00000000..e2ba5ec7 --- /dev/null +++ b/_docs/20_install-script/00_v12.md @@ -0,0 +1,34 @@ +--- +title: Embed script v12 +category: install-script +hidden: true +permalink: /script/v12 +last_modified_at: 2026-10-29 +created_at: 2026-10-29 +--- + +Our public script is now at v12. You get it automatically with `latest.js`. If you use [SRI](/sri), update to the v12 script and hash. + +## New features + +- [Inline events](/events/inline) are part of the main script: add `data-simple-event` to clicks and form submits, with `data-simple-event-*` attributes as metadata. +- Optional [404 detection](/events/inline#404-pages): `data-detect-404="true"` sends a `page_404` event. +- We collect the names of query parameters that have a value. For example, `gclid` tells paid from organic traffic. We still only collect values of UTM codes, `ref`, and [allowed parameters](/allow-params). Opt out with [`data-ignore-metrics="querykeys"`](/ignore-metrics). +- [Overwrite the referrer](/overwrite-referrer) with `data-referrer` or `sa_settings.referrer`. +- Optional [time on page pings](/pings): `data-pings="5,60"` sends the visible time at those seconds. +- [Automated events](/automated-events) collect clicks on phone (`tel:`) links. +- Inline and automated events use `fetch` with `keepalive` when the browser supports it, with an image request as fallback, so they are more likely to arrive when the visitor navigates away. + +## Improvements and fixes + +- [Time on page](/explained/time-on-page) is reliable on mobile and only counts visible time. +- Automated events no longer block or delay links: Cmd, Ctrl, and middle clicks work, and there's no 5 second delay. +- Automated events work with a [custom namespace](/events#the-variable-sa_event-is-already-used) and skip links with `data-simple-event`. +- Visitors arriving through a Cloudflare challenge are counted as [unique](/uniques). +- Ignoring `scrolled` no longer drops the screen size. +- Manual page views with a different query string are no longer merged. +- [`data-allow-params`](/allow-params) is case-insensitive. +- Fixed false bot detection with the Phantom wallet extension. +- Removed the retired Cloudflare app build. + +If you are a developer you might want to see [what changed](https://github.com/simpleanalytics/scripts/compare/v11...v12) in our open-source repository. diff --git a/_docs/20_install-script/01_script.md b/_docs/20_install-script/01_script.md index fcdccd14..c6e7b7a5 100644 --- a/_docs/20_install-script/01_script.md +++ b/_docs/20_install-script/01_script.md @@ -2,7 +2,7 @@ title: How to add our script category: install-script permalink: /script -last_modified_at: 2026-10-17 +last_modified_at: 2026-10-29 --- Include these two lines on every page at the end of your `` (or anywhere else): @@ -86,6 +86,9 @@ These settings are available: | `namespace` | [`data-namespace`][10] | `"ba"` | | `pathOverwriter` | [`data-path-overwriter`][11] | `"myPathOverwriter"` | | `metadataCollector` | [`data-metadata-collector`][12] | `"myAddMetadataFunction"` | +| `pings` | [`data-pings`][13] | `[5, 30, 60]` | +| `detect404` | [`data-detect-404`][14] | `true` | +| `referrer` | [`data-referrer`][15] | `"https://example.com/"` | For `pathOverwriter` and `metadataCollector`, use the name of a function on `window`, not the function itself. The script logs the settings it received in the browser console. @@ -101,6 +104,9 @@ For `pathOverwriter` and `metadataCollector`, use the name of a function on `win [10]: /events#the-variable-sa_event-is-already-used [11]: /overwrite-path [12]: /metadata +[13]: /pings +[14]: /events/inline#404-pages +[15]: /overwrite-referrer ## Browser support diff --git a/_docs/20_install-script/02_custom.md b/_docs/20_install-script/02_custom.md index a32881f2..7d9cb942 100644 --- a/_docs/20_install-script/02_custom.md +++ b/_docs/20_install-script/02_custom.md @@ -2,7 +2,7 @@ title: Trigger custom page views category: install-script permalink: /trigger-custom-page-views -last_modified_at: 2026-10-17 +last_modified_at: 2026-10-29 --- Normally you want to trigger a custom page view for _Single Page Apps_ (SPAs) like React, Vue, and Angular. Because pages are not completely reloaded on navigation we need a way to track those navigations as page views. @@ -49,7 +49,7 @@ You can read our source code [on GitHub](https://github.com/simpleanalytics/scri ## Use custom collection anyway -There might be situation where you don't want to auto collect page views. When you add the `data-auto-collect="false"` attribute you can expose a function called `sa_pageview`. When you call this function, the script will send a page view with the path you give as a parameter. If you don't give a path it will use `window.location.pathname` as a default. This only works with `latest.js`, not with our [light script](/light). +There might be a situation where you don't want to auto collect page views. When you add the `data-auto-collect="false"` attribute, the script doesn't send page views by itself and you send them with the `sa_pageview` function. When you call this function, the script will send a page view with the path you give as a parameter. If you don't give a path it will use `window.location.pathname` as a default. This only works with `latest.js`, not with our [light script](/light). ```html +``` + +We clean this referrer the same way as [the referrer from the browser](/how-to-use-url-parameters#using-the-referrer-url). Later page views in a single page app still use the previous page as their referrer. If you [ignore the `referrer` metric](/ignore-metrics), we don't send it. + +You can also set it with `referrer` in [`sa_settings`](/script#settings-via-javascript). diff --git a/_docs/20_script-settings/04_ignore-metrics.md b/_docs/20_script-settings/04_ignore-metrics.md index 1712dae5..19722364 100644 --- a/_docs/20_script-settings/04_ignore-metrics.md +++ b/_docs/20_script-settings/04_ignore-metrics.md @@ -3,23 +3,24 @@ title: Ignore metrics category: script-settings permalink: /ignore-metrics created_at: 2022-07-26 -last_modified_at: 2026-10-17 +last_modified_at: 2026-10-25 --- Our script only collects non-personal data. Some customers might want to limit our metrics even more. That's why we created the ignore metrics feature. -| Metric | Slug | Inferrered metric | -| ------------------- | -------------- | ---------------------- | -| Referrer | `referrer` | UTM codes, `ref` param | -| UTM codes | `utm` | [`ref` param][0] | -| Country / time zone | `country` | | -| Page-load IDs | `session` | | -| Time on page | `timeonpage` | Data point ID, Page ID | -| Scrolled | `scrolled` | Data point ID, Page ID | -| User Agent | `useragent` | | -| Screen size | `screensize` | | -| Viewport size | `viewportsize` | | -| Language | `language` | | +| Metric | Slug | Inferrered metric | +| --------------------- | -------------- | ---------------------- | +| Referrer | `referrer` | UTM codes, `ref` param | +| UTM codes | `utm` | [`ref` param][0] | +| Country / time zone | `country` | | +| Page-load IDs | `session` | | +| Time on page | `timeonpage` | Data point ID, Page ID | +| Scrolled | `scrolled` | Data point ID, Page ID | +| User Agent | `useragent` | | +| Screen size | `screensize` | | +| Viewport size | `viewportsize` | | +| Language | `language` | | +| Query parameter names | `querykeys` | | [0]: /how-to-use-url-parameters#using-a-url-parameter @@ -40,7 +41,9 @@ Our script only collects non-personal data. Some customers might want to limit o [See page](/metrics) where we explain those metrics. -When you ignore `referrer`, we also drop UTM codes and the `ref` param from page views, because they describe where a visitor came from. Parameters from [allow params](/allow-params) are still collected. When a visitor navigates within your own website, we still send that internal referrer so we can tell [unique visits](/uniques) apart. +From script version 12, we collect the **names** of query parameters in the page URL, for example `gclid,ref` for `?gclid=123&ref=newsletter`. We skip them for single-page app navigations, reloads and back/forward navigation. This only adds names: values are still only collected for UTM codes, `ref` and [allowed parameters](/allow-params). Ignore `querykeys` to turn this off. + +When you ignore `referrer`, we also drop UTM codes, query parameter names and the `ref` param from page views, because they describe where a visitor came from. Parameters from [allow params](/allow-params) are still collected. When a visitor navigates within your own website, we still send that internal referrer so we can tell [unique visits](/uniques) apart. ## Script setting `data-ignore-metrics` @@ -72,7 +75,7 @@ To ignore all metrics that you can ignore, you can use this embed script: ```html ``` diff --git a/_docs/20_script-settings/05_allow-url-parameters.md b/_docs/20_script-settings/05_allow-url-parameters.md index a40248d6..c5885770 100644 --- a/_docs/20_script-settings/05_allow-url-parameters.md +++ b/_docs/20_script-settings/05_allow-url-parameters.md @@ -3,7 +3,7 @@ title: Allow URL parameters category: script-settings permalink: /allow-params created_at: 2022-07-26 -last_modified_at: 2026-10-17 +last_modified_at: 2026-10-29 --- By default, we collect all UTM parameters (with and without the `utm_` prefix) and the `ref` (which is short for `utm_source`) parameter: @@ -27,6 +27,6 @@ If you want to capture `product-id` and `article-slug` from your website's URLs, > ``` -> **Warning:** Defined parameters in `data-allow-params` are case-sensitive. +From script version 12, parameter names in `data-allow-params` are case-insensitive, so `product-id` also allows `Product-ID`. In older versions they are case-sensitive. Read more on [how to use URL parameters](/how-to-use-url-parameters) on your website. diff --git a/_docs/20_script-settings/06_pings.md b/_docs/20_script-settings/06_pings.md new file mode 100644 index 00000000..1606f03d --- /dev/null +++ b/_docs/20_script-settings/06_pings.md @@ -0,0 +1,29 @@ +--- +title: Pings +category: script-settings +permalink: /pings +created_at: 2026-10-25 +last_modified_at: 2026-10-25 +--- + +We send the [time on page](/explained/time-on-page) when a page gets hidden. If a browser discards a page before that, for example on mobile, we don't get any time for that page view. + +With pings, the script also sends the time on page when the visible time passes the thresholds you set, in seconds. Each ping replaces the time sent earlier for that page view, so seconds are never counted twice. Pings require script version 12. + +```html + +``` + +Or with the [settings object](/script#settings-via-javascript): + +```html + +``` + +There are no pings by default. Every threshold adds a request per page view, so only add the ones you need. When you ignore `timeonpage` with [ignore metrics](/ignore-metrics), pings only send how far visitors scrolled. diff --git a/_docs/33_explained/02_time-on-page.md b/_docs/33_explained/02_time-on-page.md index 6e98c67b..b6ac8bab 100644 --- a/_docs/33_explained/02_time-on-page.md +++ b/_docs/33_explained/02_time-on-page.md @@ -3,7 +3,7 @@ title: Time on page explained menu: Time on page category: explained permalink: /explained/time-on-page -last_modified_at: 2022-04-14 +last_modified_at: 2026-10-25 --- _Time on page_ is an important metric to measure how engaged your visitors are with your content. But in most analytics tools, there is something very wrong with that metric. You might think when using Simple Analytics: "These numbers are lower than I'm used to", well, that's probably right. @@ -36,6 +36,8 @@ Simple Analytics detects when a user navigates to a different website (in a new In the above example, we get the expected result: a visitor was 15 seconds on `page1` and 5 seconds on `page2`. Nothing more, nothing less. That's what you can expect from Simple Analytics. We make sure your data is as close to real-world scenarios as possible. +From script version 12, only the time a page is visible counts. The timer pauses when a visitor switches to another tab or app, and continues when they come back. We send the time every time the page gets hidden, so we also keep it when a mobile browser closes the page in the background. Times are rounded down to whole seconds. To also send the time while the page is still open, use [pings](/pings). + {% include video.html slug="time-on-page" diff --git a/_docs/33_explained/05_uniques.md b/_docs/33_explained/05_uniques.md index ec6c9376..e89b0051 100644 --- a/_docs/33_explained/05_uniques.md +++ b/_docs/33_explained/05_uniques.md @@ -5,7 +5,7 @@ category: explained permalink: /explained/unique-visits redirect_from: - /uniques -last_modified_at: 2026-10-17 +last_modified_at: 2026-10-25 --- At Simple Analytics, we approach things differently. Our priority is protecting your visitors' privacy while staying compliant with strict privacy laws. This means some of our statistics work differently than traditional analytics tools. @@ -33,7 +33,7 @@ We use the [referrer](https://en.wikipedia.org/wiki/HTTP_referer) to determine w **A pageview is NOT counted as unique when:** -- The referrer's hostname matches your website's hostname (internal navigation) +- The referrer's hostname matches your website's hostname (internal navigation), except right after a Cloudflare challenge (see below) - The user navigates using browser history (back/forward buttons) - The user reloads the page - The referrer's hostname is in your [non-unique hostnames](/non-unique-hostnames) list, for example a payment provider @@ -50,6 +50,8 @@ If they then navigate to `yourwebsite.com/page`, the referrer is now `yourwebsit  +If your website uses a Cloudflare challenge (such as "I'm Under Attack" mode), visitors arrive from the challenge page on your own domain. From script version 12, we count that first pageview as unique and send it without a referrer, because the challenge replaced the original one. + ## Why some pages have pageviews but (almost) no visitors This happens naturally with internal navigation. Once someone enters your site (counted as a visitor on their entry page), any subsequent pages they visit during that session only add to pageviews, not visitors. Only pages that users land on directly (with no referrer or a referrer from an external site) can be counted as visitors. diff --git a/_docs/55_events/00_inline-events.md b/_docs/55_events/00_inline-events.md index e09b4233..a7c34730 100644 --- a/_docs/55_events/00_inline-events.md +++ b/_docs/55_events/00_inline-events.md @@ -1,69 +1,55 @@ --- -title: Inline events helper +title: Inline events category: events permalink: /events/inline -hidden: true -last_modified_at: 2025-04-22 +last_modified_at: 2026-10-29 --- -This small script watches your page for any element with a `data-simple-event`-attribute and automatically sends events to Simple Analytics when the user interacts. You don’t need to write any extra JavaScript calls—just add the right attributes to your HTML. - --- -### Installation - -Include the tracker snippet somewhere on your page, just before the closing `` tag. +From script version 12, our main script sends an event when a visitor interacts with an element that has a `data-simple-event` attribute. You don't need to write JavaScript or load an extra script. ```html - ``` -### Tracking button clicks +### Clicks -To track a click, add `data-simple-event="event_name"` to any clickable element. The script prevents the default action, sends your event, then continues with the click (including opening links). +Add `data-simple-event="event_name"` to any clickable element: ```html See pricing ``` -Tracking form submissions +The script never delays or cancels the click, so links, downloads and new tabs work as before. + +### Form submissions -Simply put `data-simple-event="form_name"` on your form tag. When the user submits, the script sends an event with the name of the form and the text of the submit button, then submits the form. +Put `data-simple-event="form_name"` on your `form` tag. The event is sent when the form is submitted and includes the text of the submit button as `button_text`. We never collect what visitors type into your form. ```html ``` -### Adding custom metadata +### Metadata -Any attribute starting with `data-simple-event-` will be included as event metadata. Dashes convert to underscores. +Every inline event includes the element's tag name as `tag`. Attributes starting with `data-simple-event-` are added as [metadata](/metadata), with dashes converted to underscores: ```html -Warning, this script is in beta and can change any time.
-