=== Snorklee Analytics – Cookieless GDPR Web Analytics ===
Contributors: moovswell
Tags: analytics, gdpr, cookieless, privacy, google analytics alternative
Requires at least: 5.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 3.0.1
License: MIT
License URI: https://opensource.org/licenses/MIT

Cookieless web analytics hosted in Paris, no consent banner. Also sees, server-side, the AI crawlers that JavaScript never sees.

== Description ==

Snorklee is simple web analytics: visitors, pages, sources, places, devices and goals on one page. It sets no cookie, so it needs no consent banner, and it is hosted in Paris. One more page shows which AI robots read your site and how many visitors AI assistants send you, and only what is actually captured.

This plugin connects your WordPress site to Snorklee. It does three things:

* **It installs the tracker** on every public page, and keeps it there through theme updates.
* **It counts AI robots server-side.** GPTBot, ClaudeBot, PerplexityBot and their peers fetch your HTML without running JavaScript, so no JavaScript analytics can see them, Snorklee's own snippet included. The plugin recognises them on the server, from the user agent of the page request, and reports the visit.
* **It lets you choose how the tracker is installed**, with three modes, and says what each one costs.

A Snorklee account is required. 14-day free trial, no credit card; then €4 a month ex. VAT up to 100,000 pageviews, €9 up to 500,000, €19 up to 2 million. 10 sites and every feature in every plan.

= What you see about AI =

On the AI page in Snorklee: which AI robots read your pages, how often and which pages, named as each robot declares itself in its user agent. A declaration is not proof of identity. A hit claiming to be OpenAI, Anthropic or Perplexity from outside the address ranges they publish is left out of the counts. You also see how many visitors arrive from an AI assistant: this is a minimum, because many AI apps do not say where a visitor comes from. The page includes a robots.txt generator if you want to let some robots in and keep others out.

= Three install modes, and what each one costs =

1. **Standard.** Script and measurements both come from snorklee.com. Full measurement, but blockers that filter on the domain cut everything: those visits are not counted.
2. **Script served by WordPress (recommended).** WordPress serves the tracker from your own domain (`/js/flow.js`); the measurements are sent by the visitor's browser. The script escapes blockers that filter on the filename, and you keep country, unique visitors and traffic sources. Blockers that filter on the domain still block the measurements.
3. **Full relay (self-host).** WordPress also passes the measurements through, so no blocker sees anything. The cost: Snorklee then only ever sees your server. No country, no region, and unique visitors and traffic sources stop being reliable. Snorklee shows no location and says why, rather than a false one.

Why the relay loses location: the plugin forwards the visitor's address, but on a public endpoint anyone can declare any address, so Snorklee does not turn a declared address into a location.

No DNS, Nginx or cPanel change is needed: the two WordPress-served modes use WordPress rewrite rules.

= Privacy =

* No cookie, nothing stored on or read from the visitor's device
* No persistent identifier: the visitor key changes every day
* No cross-site tracking
* No advertising data: campaign (UTM) parameters are not read
* Honours `Do Not Track`, Global Privacy Control and a visitor opt-out (`snorklee.optOut()`)
* The visitor's raw IP address is never stored
* The plugin creates no database table and stores no personal data on your WordPress server (in full-relay mode, measurements pass through without being logged)

== Installation ==

1. In wp-admin, go to Plugins › Add New, search for "Snorklee Analytics", then Install and Activate.
2. If you do not have one yet, create a Snorklee account at https://snorklee.com and add your site.
3. Open the Snorklee menu in wp-admin and enter your site domain (e.g. `yoursite.com`, without `www.`). The plugin suggests it from your site address.
4. Choose an install mode. Read what each one costs before choosing; "Script served by WordPress" is recommended.
5. Save, then click "Test installation": the plugin loads your home page and checks that the tracker is there with the right domain.

Your first visits appear in Snorklee's Statistics. AI robots appear on the AI page the next time one fetches a page: that can take hours or days, depending on how often they come.

== Frequently Asked Questions ==

= Which domain do I enter? =

The domain your site is published under, without `www.` and without `https://`. It is the `data-site` value of the snippet shown in Snorklee, under Settings › Installation.

= Do I need a cookie banner? =

Not for Snorklee. It sets no cookie and stores nothing on the visitor's device, so the ePrivacy consent requirement (article 5(3)) is not triggered. The documentation is in Snorklee, under Settings › Privacy. Your other tools (ads, embedded videos, chat) remain yours to check.

= Does the plugin track admin pages? =

No. The tracker is only added to public pages. wp-admin is excluded.

= How does full-relay mode work? =

The plugin adds WordPress rewrite rules that map `/js/flow.js`, `/api/event` and `/api/ping` to its own handlers. They fetch the tracker from snorklee.com, cache it for one hour (Transients API), and forward the measurements. For the visitor's browser, every request goes to your own domain.

The visitor's address is forwarded in `X-Forwarded-For`, but Snorklee does not use it to place the visitor: on a public endpoint without authentication, an address in a header is a claim, not an observation. So there is no country or region in this mode, and unique visitors and traffic sources become unreliable, since the visit key is derived from that same address. Choose "Script served by WordPress" if that matters more to you than the visits blocked by domain.

= Will full-relay mode slow down my site? =

Barely. The tracker file is cached for one hour. Each forwarded measurement adds an outbound request from your server to snorklee.com, but the browser sends it in the background (`sendBeacon()` or a `keepalive` request), without blocking the page.

= What happens if snorklee.com is down? =

When WordPress serves the tracker and cannot fetch it from snorklee.com, it serves an empty script so your page does not break. Measurements sent during the outage are lost: there is no offline queue.

= Can I change mode later? =

Yes, at any time. Pick another mode and save: the plugin refreshes its rewrite rules and the next page view uses the new mode. Nothing is migrated and nothing is lost.

= Does it work with caching plugins (WP Rocket, W3 Total Cache…)? =

Yes. The tracker is added through the standard WordPress script API (`wp_enqueue_script`) in the `<head>`, so caching plugins keep it like any other script. The tracker served by WordPress uses `Cache-Control: public, max-age=3600`.

= How do I uninstall? =

Deactivate and delete the plugin from Plugins. Deleting it removes the site domain, dashboard URL and AI-robot settings and the cached tracker. The plugin creates no database table.

== Screenshots ==

1. The Statistics screen in Snorklee: four numbers, one chart, then sources, pages, places, devices and goals. Click any row to filter the whole page (demo data).
2. The AI page: AI robots reading your pages, as they declare themselves, and visitors sent by AI assistants — at least (demo data).
3. The plugin settings: three ways to install the tracker, each stating what it costs.

== External services ==

This plugin connects to the Snorklee analytics service (https://snorklee.com), operated by Snorklee (France) and hosted in Paris. That is what the plugin is for. Requests go only to the Snorklee address set in the plugin (https://snorklee.com by default):

1. **Tracker, in every mode.** When a visitor views a public page, the browser runs the Snorklee tracker and sends a measurement: page path (without the query string), referrer, scroll depth, time on page, whether the page was actually displayed, the address of an outbound link clicked, the fact that a form was submitted or an e-mail, phone or download link was opened (never its content), and the names and limited properties of events you define. The request also carries the browser's user agent and IP address. The IP address is used briefly to find the country and region and is never stored. In Standard mode the browser loads `https://snorklee.com/w.js` and sends to `https://snorklee.com/api/event` and `/api/ping`.
2. **Tracker file served by WordPress (Script and Full relay modes).** Your server downloads the tracker file from `https://snorklee.com/w.js` and caches it for one hour. No visitor data is sent in that request.
3. **Measurements forwarded by WordPress (Full relay mode only).** Your server forwards each measurement from item 1 to `https://snorklee.com/api/event` or `/api/ping`, with the visitor's IP address, user agent and browser language. Nothing is logged on your server.
4. **AI-robot report (server-side, on by default).** When a known AI robot (GPTBot, ClaudeBot, PerplexityBot…) requests a page, your server sends one request to `https://snorklee.com/api/event` with the robot's user agent, the page path (without the query string), the robot's IP address and the plugin version. This concerns robots only, never your human visitors.

Terms of use: https://snorklee.com/en/legal/conditions
Privacy policy: https://snorklee.com/en/legal/confidentialite
Data collected: https://snorklee.com/docs/en/data-collected

== Changelog ==

= 3.0.1 =
* **Fix: saving the settings no longer switches off the AI-robot report.** The setting has no checkbox on the page, and WordPress hands an absent field to the plugin as empty: until 3.0.0 every "Save changes" turned the report off. It now keeps its value, and an installation where it was switched off this way gets it back once, on update.
* Uninstalling now also removes the install-mode setting.
* The settings page and readme now use the words of today's Snorklee: the snippet and its `data-site` value are under Settings › Installation, and the privacy documentation under Settings › Privacy.
* Removed a promise that no longer exists: in full-relay mode Snorklee shows no location and says why; there is no "repair task".
* "Hosted in Paris" replaces "100% EU-sovereign".
* The installation test now says exactly what it checks (the tracker is on the home page with the right domain) instead of claiming that visitors are being counted or that ad-blocker bypass is active.
* French now uses « vous », like the rest of Snorklee.
* The External services section now lists every request, including the robot's IP address sent by the AI-robot report.

= 3.0.0 =
* Three install modes instead of a toggle, and each states its cost. The new "Script served by WordPress" mode serves the tracker from your domain while the measurements go straight from the visitor's browser: you escape blockers that filter on the filename and keep country, unique visitors and traffic sources. It is now the recommended mode.
* Correction of a false measurement claim. Earlier versions said that forwarding `X-Forwarded-For` let Snorklee see the visitor's real IP for geolocation. It never did: Snorklee refuses to geolocate a declared address on a public endpoint, so sites in full-relay mode had all their traffic placed at their host's location. The settings page and the documentation now say what each mode really costs.
* AI robots: the address sent is the one your server actually observed (the last hop of `X-Forwarded-For`), no longer the first entry, which the caller writes and can forge. A private or unusable address is not sent at all.
* Existing installs are migrated silently: self-host on becomes full relay, self-host off becomes standard.
* Single-page themes and headless front-ends (React, Vue, Next.js, Nuxt) are counted page by page: the tracker follows page changes made through the History API. Only the path is sent, never the query string or fragment.
* The description no longer promises features Snorklee has removed.

= 2.3.7 =
* AI robots: the robot's IP address is now sent in a dedicated header (`X-Snorklee-Crawler-IP`). Behind a reverse proxy, `X-Forwarded-For` could be rewritten in transit and the address lost.

= 2.3.6 =
* Behavioural cards (scroll maps, attention zones, UX friction) were removed from Snorklee. The self-host proxy no longer maps `/api/zone`; the rule is dropped automatically on update.

= 2.3.5 =
* The click heatmap was removed from Snorklee. The self-host proxy no longer maps `/api/click`; the rule is dropped automatically on update.

= 2.3.4 =
* The installation test now recognises the tracker served from your own domain (`/js/flow.js`). Tracking itself was unaffected, only the test verdict.

Older versions: the full history is in the plugin's SVN repository on wordpress.org.

== Upgrade Notice ==

= 3.0.1 =
Fixes the AI-robot report being switched off by every "Save changes" (switched back on once, on update). The settings page and readme now match today's Snorklee.
