From e652d36a1927a1c6dda9a672b1d05a73d3b4dd67 Mon Sep 17 00:00:00 2001 From: Anjo Vahldiek Date: Mon, 6 Jul 2026 14:05:24 +0200 Subject: [PATCH] Add GA4 tracking for SPA search interactions --- src/assets/js/reprodb-profile.js | 5 ++++ src/assets/js/reprodb-search.js | 5 ++++ src/assets/js/reprodb-utils.js | 45 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/src/assets/js/reprodb-profile.js b/src/assets/js/reprodb-profile.js index 31853b60..296f4651 100644 --- a/src/assets/js/reprodb-profile.js +++ b/src/assets/js/reprodb-profile.js @@ -154,6 +154,11 @@ var ReproDBProfile = (function() { } history.pushState(null, '', url); showShare(); + ReproDB.trackViewSearchResults({ + searchTerm: (result.displayValue !== undefined ? result.displayValue : searchBox.value), + resultsCount: 1, + context: 'profile' + }); } searchBox.addEventListener('input', function() { diff --git a/src/assets/js/reprodb-search.js b/src/assets/js/reprodb-search.js index d2eab4cf..0eb65beb 100644 --- a/src/assets/js/reprodb-search.js +++ b/src/assets/js/reprodb-search.js @@ -110,6 +110,11 @@ doSort(); updateUrl(); renderResults(); + ReproDB.trackViewSearchResults({ + searchTerm: cleaned, + resultsCount: filtered.length, + context: 'landing' + }); } function doSort() { diff --git a/src/assets/js/reprodb-utils.js b/src/assets/js/reprodb-utils.js index 35e15c3f..0fed779a 100644 --- a/src/assets/js/reprodb-utils.js +++ b/src/assets/js/reprodb-utils.js @@ -218,6 +218,51 @@ return url; }; + /* ─── Analytics helpers (GA4) ───────────────────────────────────── */ + + // Avoid flooding GA when the same search term is emitted repeatedly + // (e.g., URL updates and debounced input landing in close succession). + R._lastSearchEvent = { key: '', ts: 0 }; + + /** + * Emit a GA4 site-search signal for client-side (SPA-like) searches. + * opts.searchTerm (required) - user-entered query string + * opts.resultsCount (optional) - number of matched results + * opts.context (optional) - logical source (landing/profile) + */ + R.trackViewSearchResults = function(opts) { + if (typeof window.gtag !== 'function') return false; + opts = opts || {}; + + var searchTerm = (opts.searchTerm || '').trim(); + if (!searchTerm) return false; + + var context = (opts.context || 'search').trim(); + var key = context + '|' + searchTerm.toLowerCase(); + var now = Date.now(); + if (R._lastSearchEvent.key === key && now - R._lastSearchEvent.ts < 1500) return false; + R._lastSearchEvent = { key: key, ts: now }; + + var eventParams = { search_term: searchTerm }; + if (opts.resultsCount != null) { + var n = Number(opts.resultsCount); + if (!isNaN(n)) eventParams.results_count = n; + } + if (context) eventParams.search_context = context; + + window.gtag('event', 'view_search_results', eventParams); + + // In SPA flows, URL changes via history API do not automatically create + // page_view events; send one so GA4 reports align with the current URL. + window.gtag('event', 'page_view', { + page_title: document.title, + page_location: window.location.href, + page_path: window.location.pathname + window.location.search + }); + + return true; + }; + /* ─── Country / continent geo maps (shared across pages) ──────────── */ R.CODE_TO_NAME = {