Show total and unique view/click analytics when individual tracking is on#3085
Show total and unique view/click analytics when individual tracking is on#3085sysrow wants to merge 2 commits into
Conversation
When individual subscriber tracking is enabled, the analytics page used to silently replace the total view/click counts with unique counts. It now prepares both the total and unique-subscriber count queries and shows them as separate "Views"/"Unique views" and "Clicks"/"Unique clicks" graphs, so totals are no longer lost. Behaviour is unchanged when individual tracking is off.
|
@sysrow since you're working on this area, do you think you could fix the circles & percentages too? #1728 (comment) Or maybe give me some feedback on the AI answers I got, so I can try to do it? |
|
@MaximilianKohler sure, Ill give it a try tomorrow |
There was a problem hiding this comment.
Issues Found
Critical (P0/P1)
- [P1] Block or ignore
unique=truewhen individual tracking is disabled (cmd/campaigns.go:616-637)- The new
unique=truequery param is honored unconditionally, so callers can request unique view/click counts even whenprivacy.individual_trackingis off (UI hides it, but the API still serves it). Depending on how non-individual tracking data is stored (eg:subscriber_idalwaysNULL/0), this can either expose distinct-subscriber analytics contrary to the privacy setting or return misleading counts; the handler should reject or forceunique=falseunless individual tracking is enabled.
- The new
Important (P2)
- [P2] Avoid unconditional dependency on unique-count SQL when preparing queries (
cmd/init.go:402-416)prepareQueries()now always builds the*-uniquestatements by dereferencingqMap["get-campaign-analytics-unique-counts"]. If an operator supplies a custom queries directory (or older query set) that omits this query, listmonk will fail to start even if unique analytics are never used; consider gating this onprivacy.individual_tracking(or at least checking presence and failing with a clearer error).
Summary
Total issues: 1 critical, 1 important, 0 minor.
Overall Verdict
Status: Patch has blocking issues
Explanation: The core feature works, but the API now exposes (or computes) unique analytics counts via ?unique=true without enforcing the privacy.individual_tracking setting, and query preparation now unconditionally depends on the unique-count SQL template being present.
Review generated by Hodor (model: gpt-5.2)
Review Metrics — 19 turns, 23 tool calls, 3m 24s
- Tokens: in
24.1K| cached302.2K| out11.6K(total337.9K) - Cost:
$0.2575
|
Ill fix the findings later tonight. Thanks. |
- Force unique=false unless individual_tracking is on, so the API never serves distinct-subscriber counts against the privacy setting. - Build the *-unique statements from the unique-count query only when tracking is on; a missing source query now fails with a clear error instead of a nil panic.
|
Thanks for the review. Addressed both:
Verified end to end against the HTTP API in both states: with tracking on, |
There was a problem hiding this comment.
Issues Found
No issues found.
Summary
Total issues: 0 critical, 0 important, 0 minor.
Overall Verdict
Status: Patch is correct
Explanation: Reviewing only the PR diff, the backend query preparation and routing logic correctly separates total vs. unique counts, and the frontend only requests/renders unique charts when individual tracking is enabled. I did not find any production-breaking bugs introduced by these changes.
Review generated by Hodor (model: gpt-5.2)
Review Metrics — 20 turns, 24 tool calls, 2m 44s
- Tokens: in
17.7K| cached271.4K| out9.0K(total298.0K) - Cost:
$0.2041

Closes #3083.
When
privacy.individual_trackingis on, the analytics page now shows both total and unique view/click graphs, instead of silently replacing the totals with unique counts.Changes
prepareQueries()(cmd/init.go): always prepares both the total and unique count statements for views and clicks, reusing the existingget-campaign-analytics-counts/get-campaign-analytics-unique-countsqueries.GetCampaignViewAnalyticsreads a?unique=truequery param;GetCampaignAnalyticsCountsroutes to the unique statement.CampaignAnalytics.vue: renders "Unique views" / "Unique clicks" charts only whenserverConfig.privacy.individual_trackingis true.en.jsonkeys (campaigns.uniqueViews,campaigns.uniqueClicks).When individual tracking is off, behavior is unchanged.
Tested:
go build/go vet/ eslint clean; verified against a running instance (total vs. unique counts render correctly per campaign).