Analytika: landing event zachytava prvu navstevu aj s referrerom

Navsteva zacinajuca na / (preklik z FB/Messengeru, natukanie domeny)
doteraz nezanechala v page_views ziadny zaznam: / je v skip liste
beaconu a gate redirect na /auth je REPLACE navigacia, takze sa skipli
oba hopy a referrer sa stratil. trackLanding() v main.tsx posle raz za
kazdy plny load stranky pomenovany event landing s document.referrer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
tim
2026-07-04 15:39:11 +02:00
co-authored by Claude Fable 5
parent 652a5aa66e
commit 42f8dfdcf0
4 changed files with 31 additions and 0 deletions
+2
View File
@@ -76,6 +76,8 @@ function AppInner() {
// too -- that's the dashboard viewing its own traffic, not player usage.
// Skip /, /lobby, /game -- high-frequency in-game navigation with no
// analytical value; the backend drops these anyway (api/stats.py _SKIPPED_PATHS).
// The visitor's first touch (incl. landings on "/", which both skips would
// otherwise swallow) is captured by trackLanding() in main.tsx instead.
useEffect(() => {
if (navigationType === 'REPLACE') return;
if (location.pathname.startsWith('/admin')) return;
+11
View File
@@ -10,3 +10,14 @@ export function trackEvent(path: string, referrer = '') {
keepalive: true,
}).catch(() => {});
}
/** One "landing" event per full page load — the visitor's first touch,
* carrying document.referrer (e.g. facebook.com). Without it a visit that
* starts on "/" leaves no trace at all: "/" is in the beacon's skip list and
* the auth-gate redirect to /auth is a REPLACE navigation (see App.tsx), so
* both hops are skipped. Not sent on /admin — the dashboard doesn't track
* itself. */
export function trackLanding() {
if (window.location.pathname.startsWith('/admin')) return;
trackEvent('landing', document.referrer);
}
+4
View File
@@ -3,11 +3,15 @@ import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
import { setupSocketListeners, socket, setAuthToken } from './lib/socket';
import { trackLanding } from './lib/track';
setupSocketListeners();
// Carry the stored session token into the handshake so the server auto-logs us in.
setAuthToken(localStorage.getItem('bridzik_token'));
socket.connect();
// Here (not in a component effect): runs exactly once per full page load,
// unaffected by StrictMode double-mounting.
trackLanding();
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>