Store UTM cookies

This commit is contained in:
Seth Call 2026-01-16 22:15:36 -06:00
parent 71d8571eb9
commit 624853c868
6 changed files with 68 additions and 21 deletions

View File

@ -12,6 +12,7 @@ const MetaTracking = {
const location = window.location; const location = window.location;
this.handleFbc(location.search); this.handleFbc(location.search);
this.handleFbp(); this.handleFbp();
this.handleUtm(location.search);
}, },
// 1. Parsing and storing _fbc (Click ID) // 1. Parsing and storing _fbc (Click ID)
@ -30,6 +31,16 @@ const MetaTracking = {
} }
}, },
handleUtm: function (searchParams) {
const utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];
utmParams.forEach(param => {
const value = this.getQueryParam(param, searchParams);
if (value) {
this.setCookie(param, value, 90);
}
});
},
// 2. Handling _fbp (Browser ID) // 2. Handling _fbp (Browser ID)
handleFbp: function () { handleFbp: function () {
if (!this.getCookie('_fbp')) { if (!this.getCookie('_fbp')) {

View File

@ -7,49 +7,63 @@
* - Checks for `_fbp` cookie; if missing, generates and sets it. * - Checks for `_fbp` cookie; if missing, generates and sets it.
*/ */
(function(window, document) { (function (window, document) {
'use strict'; 'use strict';
var MetaTracking = { var MetaTracking = {
init: function() { init: function () {
var location = window.location; var location = window.location;
this.handleFbc(location.search); this.handleFbc(location.search);
this.handleFbp(); this.handleFbp();
this.handleUtm(location.search);
}, },
// 1. Parsing and storing _fbc (Click ID) // 1. Parsing and storing _fbc (Click ID)
handleFbc: function(searchParams) { handleFbc: function (searchParams) {
var fbclid = this.getQueryParam('fbclid', searchParams); var fbclid = this.getQueryParam('fbclid', searchParams);
if (fbclid) { if (fbclid) {
var version = 'fb'; var version = 'fb';
var subdomainIndex = 1; // 1 = example.com var subdomainIndex = 1; // 1 = example.com
var creationTime = new Date().getTime(); // Unix timestamp in ms var creationTime = new Date().getTime(); // Unix timestamp in ms
// Format: fb.1.timestamp.id // Format: fb.1.timestamp.id
var fbcValue = version + '.' + subdomainIndex + '.' + creationTime + '.' + fbclid; var fbcValue = version + '.' + subdomainIndex + '.' + creationTime + '.' + fbclid;
this.setCookie('_fbc', fbcValue, 90); this.setCookie('_fbc', fbcValue, 90);
} }
}, },
handleUtm: function (searchParams) {
var utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];
var self = this;
// forEach not supported in IE8, but this is modern enough or we can use for loop
for (var i = 0; i < utmParams.length; i++) {
var param = utmParams[i];
var value = self.getQueryParam(param, searchParams);
if (value) {
self.setCookie(param, value, 90);
}
}
},
// 2. Handling _fbp (Browser ID) // 2. Handling _fbp (Browser ID)
handleFbp: function() { handleFbp: function () {
if (!this.getCookie('_fbp')) { if (!this.getCookie('_fbp')) {
var version = 'fb'; var version = 'fb';
var subdomainIndex = 1; var subdomainIndex = 1;
var creationTime = new Date().getTime(); var creationTime = new Date().getTime();
var randomInt = Math.floor(Math.random() * 10000000000); // 10-digit random number var randomInt = Math.floor(Math.random() * 10000000000); // 10-digit random number
// Format: fb.1.timestamp.randomDigits // Format: fb.1.timestamp.randomDigits
var fbpValue = version + '.' + subdomainIndex + '.' + creationTime + '.' + randomInt; var fbpValue = version + '.' + subdomainIndex + '.' + creationTime + '.' + randomInt;
this.setCookie('_fbp', fbpValue, 90); this.setCookie('_fbp', fbpValue, 90);
} }
}, },
// Helper: Get query param by name // Helper: Get query param by name
getQueryParam: function(name, search) { getQueryParam: function (name, search) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(search); var results = regex.exec(search);
@ -57,7 +71,7 @@
}, },
// Helper: Set cookie // Helper: Set cookie
setCookie: function(name, value, days) { setCookie: function (name, value, days) {
var expires = ""; var expires = "";
if (days) { if (days) {
var date = new Date(); var date = new Date();
@ -69,13 +83,13 @@
}, },
// Helper: Get cookie // Helper: Get cookie
getCookie: function(name) { getCookie: function (name) {
var nameEQ = name + "="; var nameEQ = name + "=";
var ca = document.cookie.split(';'); var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) { for (var i = 0; i < ca.length; i++) {
var c = ca[i]; var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1,c.length); while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
} }
return null; return null;
} }
@ -86,7 +100,7 @@
MetaTracking.init(); MetaTracking.init();
} else { } else {
// IE9+ support for DOMContentLoaded // IE9+ support for DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function () {
MetaTracking.init(); MetaTracking.init();
}); });
} }

View File

@ -41,7 +41,9 @@ class ApiRecurlyController < ApiController
reuse_card: reuse_card_next_time, reuse_card: reuse_card_next_time,
affiliate_referral_id: cookies[:affiliate_visitor], affiliate_referral_id: cookies[:affiliate_visitor],
origin: origin_cookie, origin: origin_cookie,
timezone: current_timezone timezone: current_timezone,
facebook_click_id: cookies[:_fbc],
facebook_browser_id: cookies[:_fbp]
} }
options = User.musician_defaults(request.remote_ip, ApplicationHelper.base_uri(request) + "/confirm", any_user, options) options = User.musician_defaults(request.remote_ip, ApplicationHelper.base_uri(request) + "/confirm", any_user, options)

View File

@ -49,11 +49,22 @@ class ApplicationController < ActionController::Base
def origin_cookie def origin_cookie
begin begin
JSON.parse(cookies[:origin]) if cookies[:origin] data = JSON.parse(cookies[:origin]) if cookies[:origin]
rescue rescue
nil data = nil
end end
# Backfill with individual UTM cookies if present
# This supports cases where the frontend (jam-ui/web) set specific cookies
# or if the JSON cookie is missing/incomplete.
%w(utm_source utm_medium utm_campaign utm_term utm_content).each do |key|
if cookies[key].present?
data ||= {}
data[key] = cookies[key]
end
end
data
end end
def track_origin def track_origin

View File

@ -635,6 +635,10 @@ class LandingsController < ApplicationController
musician: true, musician: true,
timezone: current_timezone, timezone: current_timezone,
first_name: @first, first_name: @first,
origin: origin_cookie,
affiliate_referral_id: cookies[:affiliate_visitor],
facebook_click_id: cookies[:_fbc],
facebook_browser_id: cookies[:_fbp],
instruments: [{:instrument_id => @instrument, :proficiency_level => 1, :priority => 1}]) instruments: [{:instrument_id => @instrument, :proficiency_level => 1, :priority => 1}])
if @user.errors.any? if @user.errors.any?
first = @user.errors.first first = @user.errors.first

View File

@ -120,7 +120,10 @@ class SessionsController < ApplicationController
last_name: auth_hash[:info][:last_name], last_name: auth_hash[:info][:last_name],
email: auth_hash[:info][:email], email: auth_hash[:info][:email],
timezone: current_timezone, timezone: current_timezone,
affiliate_referral_id: cookies[:affiliate_visitor]) affiliate_referral_id: cookies[:affiliate_visitor],
origin: origin_cookie,
facebook_click_id: cookies[:_fbc],
facebook_browser_id: cookies[:_fbp])
# Users who sign up using oauth are presumed to have valid email adddresses. # Users who sign up using oauth are presumed to have valid email adddresses.
user.confirm_email! user.confirm_email!
@ -196,7 +199,9 @@ class SessionsController < ApplicationController
location: {:country => nil, :state => nil, :city => nil}, location: {:country => nil, :state => nil, :city => nil},
affiliate_referral_id: cookies[:affiliate_visitor], affiliate_referral_id: cookies[:affiliate_visitor],
origin: origin_cookie, origin: origin_cookie,
timezone: current_timezone timezone: current_timezone,
facebook_click_id: cookies[:_fbc],
facebook_browser_id: cookies[:_fbp]
} }
options = User.musician_defaults(request.remote_ip, ApplicationHelper.base_uri(request) + "/confirm", any_user, options) options = User.musician_defaults(request.remote_ip, ApplicationHelper.base_uri(request) + "/confirm", any_user, options)