replace analytics double-count prevention with buffer supersede
All checks were successful
deploy / deploy (push) Successful in 1m13s
All checks were successful
deploy / deploy (push) Successful in 1m13s
The Plug records a pageview with a known ID (plug_ref) into the ETS buffer. When JS connects, the LiveView hook supersedes that event by ID and records its own with full data (screen_size from connect params). If JS never connects, the Plug's event flushes normally after 10s. Also fixes: admin browsing no longer leaks product_view events — the Plug now sets no analytics session data for admins, so all downstream visitor_hash guards naturally filter them out. Replaces the previous time-based skip logic which was brittle and race-prone. The supersede approach is deterministic and handles both the ETS buffer and already-flushed DB cases. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
defmodule BerrypodWeb.Plugs.Analytics do
|
||||
@moduledoc """
|
||||
Plug that records a pageview event on every shop HTTP request.
|
||||
Plug that records an initial pageview and prepares analytics session data.
|
||||
|
||||
This is Layer 1 of the progressive analytics pipeline — it fires on every
|
||||
GET request regardless of whether JS is enabled. Computes a privacy-friendly
|
||||
visitor hash, parses the user agent, extracts referrer and UTM params, and
|
||||
buffers the event for batch writing to SQLite.
|
||||
Fires on every GET request regardless of JS — computes a privacy-friendly
|
||||
visitor hash, parses the user agent, extracts referrer and UTM params.
|
||||
Records the pageview immediately (for no-JS support) and stores the data
|
||||
in the session for the LiveView hook to use on SPA navigations.
|
||||
|
||||
Also stores analytics data in the session so the LiveView hook (Layer 2)
|
||||
can read it for subsequent SPA navigations.
|
||||
The event is recorded with a known ID (plug_ref) stored in the session.
|
||||
When JS connects, the LiveView hook supersedes this event by ID and
|
||||
records its own with full data (screen_size). If JS never connects,
|
||||
the Plug's event flushes to the DB normally.
|
||||
"""
|
||||
|
||||
import Plug.Conn
|
||||
@@ -26,9 +28,11 @@ defmodule BerrypodWeb.Plugs.Analytics do
|
||||
if browser == "Bot" do
|
||||
conn
|
||||
else
|
||||
# Skip if the logged-in admin is browsing
|
||||
# Skip recording for logged-in admin — don't set analytics session
|
||||
# data either, so downstream guards (visitor_hash checks in LiveViews)
|
||||
# naturally filter out admin browsing for all event types
|
||||
if admin?(conn) do
|
||||
prepare_session(conn, ua, browser, os)
|
||||
conn
|
||||
else
|
||||
record_and_prepare(conn, ua, browser, os)
|
||||
end
|
||||
@@ -42,9 +46,10 @@ defmodule BerrypodWeb.Plugs.Analytics do
|
||||
{referrer, referrer_source} = extract_referrer(conn)
|
||||
utm = extract_utms(conn)
|
||||
country_code = get_session(conn, "country_code")
|
||||
screen_size = get_session(conn, "analytics_screen_size")
|
||||
plug_ref = Ecto.UUID.generate()
|
||||
|
||||
Analytics.track_pageview(%{
|
||||
id: plug_ref,
|
||||
pathname: conn.request_path,
|
||||
visitor_hash: visitor_hash,
|
||||
referrer: referrer,
|
||||
@@ -53,7 +58,7 @@ defmodule BerrypodWeb.Plugs.Analytics do
|
||||
utm_medium: utm.medium,
|
||||
utm_campaign: utm.campaign,
|
||||
country_code: country_code,
|
||||
screen_size: screen_size,
|
||||
screen_size: nil,
|
||||
browser: browser,
|
||||
os: os
|
||||
})
|
||||
@@ -67,16 +72,7 @@ defmodule BerrypodWeb.Plugs.Analytics do
|
||||
|> put_session("analytics_utm_source", utm.source)
|
||||
|> put_session("analytics_utm_medium", utm.medium)
|
||||
|> put_session("analytics_utm_campaign", utm.campaign)
|
||||
end
|
||||
|
||||
# Store session data for the hook even when we skip recording for admins
|
||||
defp prepare_session(conn, ua, browser, os) do
|
||||
visitor_hash = Salt.hash_visitor(conn.remote_ip, ua)
|
||||
|
||||
conn
|
||||
|> put_session("analytics_visitor_hash", visitor_hash)
|
||||
|> put_session("analytics_browser", browser)
|
||||
|> put_session("analytics_os", os)
|
||||
|> put_session("analytics_plug_ref", plug_ref)
|
||||
end
|
||||
|
||||
defp admin?(conn) do
|
||||
|
||||
Reference in New Issue
Block a user