Skip to content

Count Cloudflare challenge arrivals as unique - #112

Merged
adriaandotcom merged 8 commits into
v12from
fix/v12-cloudflare-query-markers
Oct 15, 2026
Merged

adriaandotcom merged 8 commits into
v12from
fix/v12-cloudflare-query-markers

Conversation

@simple-analytics-ai

@simple-analytics-ai simple-analytics-ai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Targets v12 (#40). Merge into v12 before releasing #40 to main.

Summary

Fixes #107 and implements the Cloudflare arrival behavior in #48.

Use the owner's requested simple marker check on the raw referrer:

!pages && /[?&]__cf_/.test(getReferrer(trueVar))

This replaces the anchored parameter-name expression with a broad marker-presence check. It accepts the marker at the start of the query or appended after existing campaign parameters. The extra same-URL guard was explicitly declined and is omitted. Existing reload/history and later-pageview handling remain in place. Referrer overrides keep working, and outgoing referrers remain stripped of query strings.

Merged current v12 at 58f6679, including the modified-click fix from #78 and the previously merged manual-pageview, namespace, and phone-click fixes. Source, regression tests, and matching generated bundles are included together. Unrelated pinned auto-events artifacts and older versions are preserved.

Security implications

  • No security impact
  • Has security impact - raw referrers are inspected in memory to classify challenge arrivals as unique; referrer query values are not transmitted.

Testing

  • Node 24.18.0 / pnpm 11.17.0: build with ES5 validation and all 53 unit tests pass.
  • 36 payload checks pass across development, minified CDN, and SRI bundles, covering the simple marker check, existing campaign parameters, reloads, token omission, manual-query overrides, browser-query fallback, filtering, events, and duplicate suppression.
  • Changed JavaScript passes Prettier; git diff --check passes.
  • Against the same-build current v12, excluding headers: latest.js +21 minified bytes / +16 gzip bytes at level 9. Light code is unchanged.
  • Latest main was refreshed through the signed broker and is included. Remote CI is tracked separately from local validation.

Merge Danger

Door: two-way.

Blast Radius: analytics. Challenge arrivals can contribute to unique visitor counts as requested; pageview totals and event names are unchanged.

Checklist

  • Linked to an issue
  • Tested
  • Asked for a review

Requested in the compatibility review: avoid path false positives and inspect raw query-only markers. Reuse the referrer helper without sending raw query values or adding bytes to light builds.

Refs #107
@github-actions

Copy link
Copy Markdown

Documentation update

_docs/33_explained/05_uniques.md

Location: ## How we detect unique pageviews, replacing the existing **A pageview is NOT counted as unique when:** list

Copy and paste this into the documentation repository:

**A pageview is NOT counted as unique when:**

- The referrer's hostname matches your website's hostname (internal navigation)
- The user navigates using browser history (back/forward buttons)
- The user reloads the page
- The visitor returns from a Cloudflare security challenge

That last case happens when your site sits behind Cloudflare and a visitor is shown a security challenge (for example a managed challenge or a CAPTCHA). After passing it, Cloudflare sends the visitor back to your page with a challenge parameter such as `__cf_chl_tk` or `__cf_chl_rt_tk` in the URL. We recognise those parameter names in the referrer and count that pageview as non-unique, so a single visitor who passed a challenge is not counted twice. We only look at the parameter names; the referrer we store is still stripped of its query string.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Claude review checkpoint

Reviewed commit 14b75fc883bb3d749a183eaf6d9b8a2aabecaf6e. This is used to keep later automated reviews focused on changes Claude has not checked yet.

@github-actions github-actions Bot added the change: routine Changes to internal tools or low-risk changes (e.g., design updates or content modifications) label Oct 15, 2026
@github-actions

Copy link
Copy Markdown

SDLC label: change: routine because Bug fix to the client-side unique-pageview heuristic; the Cloudflare marker is matched in-memory only and the outgoing payload still strips the referrer query, with no change to data collection, storage, retention, authorization, billing, or infrastructure

@simple-analytics-ai

simple-analytics-ai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Author

In response to #112 (comment) and #112 (comment), superseding #112 (comment):

I corrected the pending docs patch to match 14b75fc and the owner's simplification in #112 (comment). Cloudflare referrers containing ?__cf_ or &__cf_ can make the first arrival unique; reloads and history navigation remain non-unique, and later pageviews do not use that exception. The copy describes the broad marker check without promising strict parameter-name matching or a same-URL guard, and explains that referrer queries are stripped before transmission.

The revised four-page patch applies cleanly to current docs/master and passes formatting checks. It remains local pending the existing request for approval of a supporting docs PR, with publication dependent on this change and the v12 release.

Simple Analytics Codex and others added 4 commits October 15, 2026 17:01
Requested: make issue #107 mergeable while preserving manual-query overrides, browser-query fallback, and existing filtering. Resolve the older Cloudflare branch against current v12 source and regenerate its bundles, preserving inline events and the merged phone-click fix.

All 45 unit tests and 24 additional query payload checks pass.

Refs #107
Requested: make issue #107 mergeable. Preserve all current v12 changes and the reviewed Cloudflare source fix; rebuild and validate the generated bundles with 45 passing unit tests and 24 payload checks.

Refs #107
User requested correcting PR #112 to match issue #48. Challenge query parameter names now allow the first tracked arrival to be unique, including same-site referrers. Reloads, history navigation, and later manual or SPA pageviews remain non-unique. Keep challenge tokens out of payloads, preserve current v12 changes, and regenerate distributions. Validated with 53 offline unit tests and minified payload checks.
@simple-analytics-ai simple-analytics-ai Bot changed the title Recognize Cloudflare challenge markers only in query names Count Cloudflare challenge arrivals as unique Oct 15, 2026
Comment thread src/default.js Outdated
@github-actions

Copy link
Copy Markdown

Documentation update

_docs/33_explained/05_uniques.md

Location: ## How we detect unique pageviews, replacing the existing **A pageview is NOT counted as unique when:** list and the paragraph that follows it

Copy and paste this into the documentation repository:

**A pageview is NOT counted as unique when:**

- The referrer's hostname matches your website's hostname (internal navigation)
- The user navigates using browser history (back/forward buttons)
- The user reloads the page

### Cloudflare security challenges

If your website runs behind Cloudflare and a visitor has to pass a security challenge (for example with "I'm Under Attack" mode enabled), the browser reports the challenge URL as the referrer. That URL is on your own hostname, so without special handling the arrival would look like internal navigation and would not be counted as a visitor.

We recognize these arrivals by looking for a Cloudflare query parameter name such as `__cf_chl_tk` or `__cf_chl_rt_tk` in the referrer, and we count that arrival as unique, just like any other fresh visit. Only the first pageview of the page load can use this exception: reloads, back/forward navigation, and later manual or single-page-application pageviews stay non-unique.

The marker only counts as a query parameter name. A Cloudflare-looking string in the referrer's path, in a query parameter value, or after the `#` is ignored. The challenge token itself never reaches us, because we always strip the query string from the referrer before sending it.

Comment thread src/default.js Outdated
Simple Analytics Codex added 2 commits October 15, 2026 17:21
User asked to replace the parameter-name regex with a literal ?__cf_ check, omit the extra same-URL guard, and merge current v12 into #112. Preserve the latest modified-click, namespace, manual-query, and phone-click fixes. Rebuild matching tracker bundles while retaining unrelated pinned auto-events artifacts.

All 53 unit tests, 33 payload checks, changed JavaScript formatting, and diff checks pass. Manual-query overrides and location.search fallback remain intact.

Refs #107
User requested a literal ?__cf_ check without the extra same-URL guard and asked to merge v12 into #112. Include v12 at 58f6679, retaining its modified-click, namespace, manual-pageview, and phone-click fixes. Use the reviewed, broker-pushed tree with source, tests, and matching distributions.

All 53 unit tests and 33 payload checks pass. Refs #107
Comment thread src/default.js Outdated
Comment thread test/unit/pageview.test.js Outdated
@github-actions

Copy link
Copy Markdown

Documentation update

_docs/33_explained/05_uniques.md

Location: ## How we detect unique pageviews, after the "A pageview is NOT counted as unique when" list and before the randomwebsite.com example

Copy and paste this into the documentation repository:

### Cloudflare challenges

When Cloudflare shows a security challenge (for example a managed challenge or a Turnstile interstitial), your visitor is sent back to your own website after passing it. The referrer of that first pageview is then your own hostname, which would normally make the visit non-unique even though the visitor came from somewhere else.

To avoid losing those visitors, we make one exception: if the referrer of the **first** pageview on a page load contains a Cloudflare challenge parameter (a query parameter starting with `__cf_`, such as `__cf_chl_tk` or `__cf_chl_rt_tk`), we count that pageview as unique.

This exception only applies to the first pageview after a page load. Later pageviews, reloads, back and forward navigation, and single-page application navigation remain non-unique as described above. As always, we only read the referrer in the browser to make this decision; the challenge token itself is never sent to us, because we strip query strings from referrers.

User requested a simple marker check and current v12 merge. Address review by accepting both ?__cf_ and appended &__cf_ with the short /[?&]__cf_/ expression, retaining the requested broad matching and omitting the declined same-URL guard. Update the existing regression and matching bundles.

All 53 unit tests and 36 payload checks pass. Current v12 remains included.

Refs #107
@adriaandotcom
adriaandotcom merged commit 6af229d into v12 Oct 15, 2026
11 of 12 checks passed
@adriaandotcom
adriaandotcom deleted the fix/v12-cloudflare-query-markers branch October 15, 2026 22:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change: routine Changes to internal tools or low-risk changes (e.g., design updates or content modifications)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant