diff --git a/app/javascript/packs/baseTracking.js b/app/javascript/packs/baseTracking.js
index caa54454d..2adeef299 100644
--- a/app/javascript/packs/baseTracking.js
+++ b/app/javascript/packs/baseTracking.js
@@ -1,4 +1,5 @@
/*eslint-disable prefer-rest-params*/
+/* global isTouchDevice */
function initializeBaseTracking() {
showCookieConsentBanner();
@@ -7,11 +8,12 @@ function initializeBaseTracking() {
trackCustomImpressions();
}
+// Google Anlytics 3 is deprecated, and mostly not supported, but some sites may still be using it for now.
function trackGoogleAnalytics3() {
let wait = 0;
let addedGA = false;
const gaTrackingCode = document.body.dataset.gaTracking;
- if (gaTrackingCode) {
+ if (gaTrackingCode && localStorage.getItem('cookie_status') === 'allowed') {
const waitingOnGA = setInterval(() => {
if (!addedGA) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
@@ -33,6 +35,8 @@ function trackGoogleAnalytics3() {
}
}, 25);
eventListening();
+ } else if (gaTrackingCode) {
+ fallbackActivityRecording();
}
}
@@ -60,9 +64,13 @@ function trackGoogleAnalytics4() {
window['gtag'] = window['gtag'] || function () {
window.dataLayer.push(arguments)
}
-
+ const consent = localStorage.getItem('cookie_status') === 'allowed' ? 'granted' : 'denied';
gtag('js', new Date());
gtag('config', ga4MeasurementCode, { 'anonymize_ip': true });
+ gtag('consent', 'default', {
+ 'ad_storage': consent,
+ 'analytics_storage': consent
+ });
clearInterval(waitingOnGA4);
}
if (wait > 85) {
@@ -181,7 +189,7 @@ function trackCustomImpressions() {
function showCookieConsentBanner() {
// if current url includes ?cookietest=true
- if (window.location.href.includes('cookietest=true')) {
+ if (shouldShowCookieBanner()) {
// show modal with cookie consent
const cookieDiv = document.getElementById('cookie-consent');
@@ -190,7 +198,7 @@ function showCookieConsentBanner() {
- Some content on our site requires cookies for personalization and analytics.
+ Some content on our site requires cookies for personalization.
Read our full privacy policy to learn more.
@@ -210,6 +218,12 @@ function showCookieConsentBanner() {
document.getElementById('cookie-accept').onclick = (() => {
localStorage.setItem('cookie_status', 'allowed');
cookieDiv.style.display = 'none';
+ if (window.gtag) {
+ gtag('consent', 'update', {
+ 'ad_storage': 'granted',
+ 'analytics_storage': 'granted'
+ });
+ }
});
document.getElementById('cookie-dismiss').onclick = (() => {
@@ -220,6 +234,38 @@ function showCookieConsentBanner() {
}
}
+function shouldShowCookieBanner() {
+ const { userStatus, cookieBannerUserContext, cookieBannerPlatformContext } = document.body.dataset;
+ function determineActualPlatformContext() {
+ if (navigator.userAgent.includes('DEV-Native')) {
+ return 'mobile_app'
+ } else if (isTouchDevice()) {
+ return 'mobile_web'
+ }
+ return 'desktop_web'
+ }
+
+ // Determine the actual platform context
+ const actualPlatformContext = determineActualPlatformContext();
+
+ // Check if either user or platform context is set to 'off'
+ if (cookieBannerUserContext === 'off' || cookieBannerPlatformContext === 'off') {
+ return false;
+ }
+
+ // Check based on user status
+ const showForUserContext = (userStatus === 'logged-in' && cookieBannerUserContext === 'all') ||
+ (userStatus !== 'logged-in' && cookieBannerUserContext !== 'off');
+
+ // Check based on platform context
+ const showForPlatformContext = (cookieBannerPlatformContext === 'all') ||
+ (cookieBannerPlatformContext === 'all_web' && ['desktop_web', 'mobile_web'].includes(actualPlatformContext)) ||
+ (cookieBannerPlatformContext === actualPlatformContext);
+
+ // Return true if both user context and platform context conditions are met
+ return showForUserContext && showForPlatformContext;
+}
+
function trackPageView(dataBody, csrfToken) {
window.fetch('/page_views', {
method: 'POST',
diff --git a/app/lib/constants/settings/general.rb b/app/lib/constants/settings/general.rb
index da186ab4e..658fb51c9 100644
--- a/app/lib/constants/settings/general.rb
+++ b/app/lib/constants/settings/general.rb
@@ -45,6 +45,14 @@ module Constants
description: I18n.t("lib.constants.settings.general.ga_analytics_4.description"),
placeholder: ""
},
+ cookie_banner_user_context: {
+ description: I18n.t("lib.constants.settings.general.cookie_banner_user_context.description"),
+ placeholder: "off"
+ },
+ coolie_banner_platform_context: {
+ description: I18n.t("lib.constants.settings.general.coolie_banner_platform_context.description"),
+ placeholder: "off"
+ },
health_check_token: {
description: I18n.t("lib.constants.settings.general.health.description"),
placeholder: I18n.t("lib.constants.settings.general.health.placeholder")
diff --git a/app/models/settings/general.rb b/app/models/settings/general.rb
index 923760aa4..f47ebd699 100644
--- a/app/models/settings/general.rb
+++ b/app/models/settings/general.rb
@@ -1,5 +1,8 @@
module Settings
class General < Base
+ BANNER_USER_CONFIGS = %w[off logged_out_only all].freeze
+ BANNER_PLATFORM_CONFIGS = %w[off all all_web desktop_web mobile_web mobile_app].freeze
+
self.table_name = "site_configs"
SOCIAL_MEDIA_SERVICES = %w[
twitter facebook github instagram twitch mastodon
@@ -24,9 +27,15 @@ module Settings
setting :contact_email, type: :string, default: ApplicationConfig["DEFAULT_EMAIL"]
setting :periodic_email_digest, type: :integer, default: 2
- # Google Analytics Tracking ID, e.g. UA-71991000-1
+ # Analytics and tracking
setting :ga_tracking_id, type: :string, default: ApplicationConfig["GA_TRACKING_ID"]
setting :ga_analytics_4_id, type: :string, default: ApplicationConfig["GA_ANALYTICS_4_ID"]
+ setting :cookie_banner_user_context, type: :string, default: "off", validates: {
+ inclusion: { in: BANNER_USER_CONFIGS }
+ }
+ setting :coolie_banner_platform_context, type: :string, default: "off", validates: {
+ inclusion: { in: BANNER_PLATFORM_CONFIGS }
+ }
# Ahoy Tracking
setting :ahoy_tracking, type: :boolean, default: false
diff --git a/app/views/admin/settings/forms/_google_analytics.html.erb b/app/views/admin/settings/forms/_google_analytics.html.erb
index 5b81f7c07..85851522f 100644
--- a/app/views/admin/settings/forms/_google_analytics.html.erb
+++ b/app/views/admin/settings/forms/_google_analytics.html.erb
@@ -2,16 +2,9 @@
url: admin_settings_general_settings_path,
html: { data: { action: "submit->config#updateConfigurationSettings" } }) do |f| %>
- Google Analytics
+ Google Analytics and Cookies
<%= render "update_setting_button", f: f %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 8f6fd9efd..e0b72bca9 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -55,6 +55,8 @@
data-deployed-at="<%= j(ForemInstance.deployed_at) %>"
data-latest-commit-id="<%= j(ForemInstance.latest_commit_id) %>"
data-ga-tracking="<%= j(Settings::General.ga_tracking_id) %>"
+ data-cookie-banner-user-context="<%= j(Settings::General.cookie_banner_user_context) %>"
+ data-cookie-banner-platform-context="<%= j(Settings::General.coolie_banner_platform_context) %>"
data-ga4-tracking-id="<%= j(Settings::General.ga_analytics_4_id) %>">
<%# Repeat of stylesheets in to fix rendering glitch: https://github.com/forem/forem/issues/12377 %>
<%= render "layouts/styles", qualifier: "secondary" %>
diff --git a/config/locales/lib/en.yml b/config/locales/lib/en.yml
index c157c5c49..298c607fe 100644
--- a/config/locales/lib/en.yml
+++ b/config/locales/lib/en.yml
@@ -118,6 +118,10 @@ en:
description: Google Universal Analytics Tracking ID, e.g. UA-XXXXXXXX-1
ga_analytics_4:
description: Google Analytics 4 Measurement ID, e.g. G-XXXXXXXXX
+ cookie_banner_user_context:
+ description: Used to determine whether the cookie banner should be shown based on user context (i.e. logged in or not)
+ coolie_banner_platform_context:
+ description: Used to determine whether the cookie banner should be shown based on platform (i.e. web/mobile)
hashtag:
description: Used as the twitter hashtag of the community
placeholder: '#DEVCommunity'
diff --git a/config/locales/lib/fr.yml b/config/locales/lib/fr.yml
index 67ab72066..4e00556cc 100644
--- a/config/locales/lib/fr.yml
+++ b/config/locales/lib/fr.yml
@@ -118,6 +118,10 @@ fr:
description: Google Universal Analytics Tracking ID, e.g. UA-XXXXXXXX-1
ga_analytics_4:
description: Google Analytics 4 Measurement ID, e.g. G-XXXXXXXXX
+ cookie_banner_user_context:
+ description: Used to determine whether the cookie banner should be shown based on user context (i.e. logged in or not)
+ coolie_banner_platform_context:
+ description: Used to determine whether the cookie banner should be shown based on platform (i.e. web/mobile)
hashtag:
description: Used as the twitter hashtag of the community
placeholder: '#DEVCommunity'