Add UTM registration tracking

pull/7500/head
Kamran Ahmed 2 days ago
parent 87ed33b330
commit c481e8aa38
  1. 3
      src/components/AuthenticationFlow/GitHubButton.tsx
  2. 17
      src/components/AuthenticationFlow/GoogleButton.tsx
  3. 12
      src/components/AuthenticationFlow/LinkedInButton.tsx
  4. 3
      src/components/AuthenticationFlow/TriggerVerifyAccount.tsx
  5. 11
      src/components/PageSponsor.tsx
  6. 62
      src/lib/browser.ts

@ -4,6 +4,7 @@ import Cookies from 'js-cookie';
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt'; import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
import { httpGet } from '../../lib/http'; import { httpGet } from '../../lib/http';
import { Spinner } from '../ReactIcons/Spinner.tsx'; import { Spinner } from '../ReactIcons/Spinner.tsx';
import { triggerUtmRegistration } from '../../lib/browser.ts';
type GitHubButtonProps = { type GitHubButtonProps = {
isDisabled?: boolean; isDisabled?: boolean;
@ -46,6 +47,8 @@ export function GitHubButton(props: GitHubButtonProps) {
return; return;
} }
triggerUtmRegistration();
let redirectUrl = '/'; let redirectUrl = '/';
const gitHubRedirectAt = localStorage.getItem(GITHUB_REDIRECT_AT); const gitHubRedirectAt = localStorage.getItem(GITHUB_REDIRECT_AT);
const lastPageBeforeGithub = localStorage.getItem(GITHUB_LAST_PAGE); const lastPageBeforeGithub = localStorage.getItem(GITHUB_LAST_PAGE);

@ -4,6 +4,10 @@ import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
import { httpGet } from '../../lib/http'; import { httpGet } from '../../lib/http';
import { Spinner } from '../ReactIcons/Spinner.tsx'; import { Spinner } from '../ReactIcons/Spinner.tsx';
import { GoogleIcon } from '../ReactIcons/GoogleIcon.tsx'; import { GoogleIcon } from '../ReactIcons/GoogleIcon.tsx';
import {
getStoredUtmParams,
triggerUtmRegistration,
} from '../../lib/browser.ts';
type GoogleButtonProps = { type GoogleButtonProps = {
isDisabled?: boolean; isDisabled?: boolean;
@ -37,6 +41,8 @@ export function GoogleButton(props: GoogleButtonProps) {
}`, }`,
) )
.then(({ response, error }) => { .then(({ response, error }) => {
const utmParams = getStoredUtmParams();
if (!response?.token) { if (!response?.token) {
setError(error?.message || 'Something went wrong.'); setError(error?.message || 'Something went wrong.');
setIsLoading(false); setIsLoading(false);
@ -45,6 +51,8 @@ export function GoogleButton(props: GoogleButtonProps) {
return; return;
} }
triggerUtmRegistration();
let redirectUrl = '/'; let redirectUrl = '/';
const googleRedirectAt = localStorage.getItem(GOOGLE_REDIRECT_AT); const googleRedirectAt = localStorage.getItem(GOOGLE_REDIRECT_AT);
const lastPageBeforeGoogle = localStorage.getItem(GOOGLE_LAST_PAGE); const lastPageBeforeGoogle = localStorage.getItem(GOOGLE_LAST_PAGE);
@ -97,9 +105,12 @@ export function GoogleButton(props: GoogleButtonProps) {
// For non authentication pages, we want to redirect back to the page // For non authentication pages, we want to redirect back to the page
// the user was on before they clicked the social login button // the user was on before they clicked the social login button
if (!['/login', '/signup'].includes(window.location.pathname)) { if (!['/login', '/signup'].includes(window.location.pathname)) {
const pagePath = ['/respond-invite', '/befriend', '/r', '/ai'].includes( const pagePath = [
window.location.pathname, '/respond-invite',
) '/befriend',
'/r',
'/ai',
].includes(window.location.pathname)
? window.location.pathname + window.location.search ? window.location.pathname + window.location.search
: window.location.pathname; : window.location.pathname;

@ -4,6 +4,7 @@ import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
import { httpGet } from '../../lib/http'; import { httpGet } from '../../lib/http';
import { Spinner } from '../ReactIcons/Spinner.tsx'; import { Spinner } from '../ReactIcons/Spinner.tsx';
import { LinkedInIcon } from '../ReactIcons/LinkedInIcon.tsx'; import { LinkedInIcon } from '../ReactIcons/LinkedInIcon.tsx';
import { triggerUtmRegistration } from '../../lib/browser.ts';
type LinkedInButtonProps = { type LinkedInButtonProps = {
isDisabled?: boolean; isDisabled?: boolean;
@ -45,6 +46,8 @@ export function LinkedInButton(props: LinkedInButtonProps) {
return; return;
} }
triggerUtmRegistration();
let redirectUrl = '/'; let redirectUrl = '/';
const linkedInRedirectAt = localStorage.getItem(LINKEDIN_REDIRECT_AT); const linkedInRedirectAt = localStorage.getItem(LINKEDIN_REDIRECT_AT);
const lastPageBeforeLinkedIn = localStorage.getItem(LINKEDIN_LAST_PAGE); const lastPageBeforeLinkedIn = localStorage.getItem(LINKEDIN_LAST_PAGE);
@ -97,9 +100,12 @@ export function LinkedInButton(props: LinkedInButtonProps) {
// For non authentication pages, we want to redirect back to the page // For non authentication pages, we want to redirect back to the page
// the user was on before they clicked the social login button // the user was on before they clicked the social login button
if (!['/login', '/signup'].includes(window.location.pathname)) { if (!['/login', '/signup'].includes(window.location.pathname)) {
const pagePath = ['/respond-invite', '/befriend', '/r', '/ai'].includes( const pagePath = [
window.location.pathname, '/respond-invite',
) '/befriend',
'/r',
'/ai',
].includes(window.location.pathname)
? window.location.pathname + window.location.search ? window.location.pathname + window.location.search
: window.location.pathname; : window.location.pathname;

@ -4,6 +4,7 @@ import { httpPost } from '../../lib/http';
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt'; import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
import { Spinner } from '../ReactIcons/Spinner'; import { Spinner } from '../ReactIcons/Spinner';
import { ErrorIcon2 } from '../ReactIcons/ErrorIcon2'; import { ErrorIcon2 } from '../ReactIcons/ErrorIcon2';
import { triggerUtmRegistration } from '../../lib/browser.ts';
export function TriggerVerifyAccount() { export function TriggerVerifyAccount() {
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
@ -26,6 +27,8 @@ export function TriggerVerifyAccount() {
return; return;
} }
triggerUtmRegistration();
setAuthToken(response.token); setAuthToken(response.token);
window.location.href = '/'; window.location.href = '/';
}) })

@ -6,6 +6,7 @@ import { X } from 'lucide-react';
import { setViewSponsorCookie } from '../lib/jwt'; import { setViewSponsorCookie } from '../lib/jwt';
import { isMobile } from '../lib/is-mobile'; import { isMobile } from '../lib/is-mobile';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { getUrlUtmParams } from '../lib/browser.ts';
export type PageSponsorType = { export type PageSponsorType = {
company: string; company: string;
@ -50,6 +51,16 @@ export function PageSponsor(props: PageSponsorProps) {
const [sponsorId, setSponsorId] = useState<string | null>(null); const [sponsorId, setSponsorId] = useState<string | null>(null);
const [sponsor, setSponsor] = useState<PageSponsorType>(); const [sponsor, setSponsor] = useState<PageSponsorType>();
useEffect(() => {
const foundUtmParams = getUrlUtmParams();
if (!foundUtmParams.utmSource) {
return;
}
localStorage.setItem('utm_params', JSON.stringify(foundUtmParams));
}, []);
const loadSponsor = async () => { const loadSponsor = async () => {
const currentPath = window.location.pathname; const currentPath = window.location.pathname;
if ( if (

@ -1,3 +1,65 @@
type UtmParams = Partial<{
utmSource: string;
utmMedium: string;
utmCampaign: string;
utmContent: string;
utmTerm: string;
}>;
export function getUrlUtmParams(): UtmParams {
if (typeof window === 'undefined') {
return {};
}
const utmParams = new URLSearchParams(window.location.search);
const utmSource = utmParams.get('utm_source') ?? undefined;
const utmMedium = utmParams.get('utm_medium') ?? undefined;
const utmCampaign = utmParams.get('utm_campaign') ?? undefined;
const utmContent = utmParams.get('utm_content') ?? undefined;
const utmTerm = utmParams.get('utm_term') ?? undefined;
if (!utmSource || !utmCampaign) {
return {};
}
return {
utmSource: utmCampaign ? utmSource.toLowerCase() : undefined,
utmMedium: utmMedium ? utmMedium.toLowerCase() : undefined,
utmCampaign: utmCampaign ? utmCampaign.toLowerCase() : undefined,
utmContent: utmContent ? utmContent.toLowerCase() : undefined,
utmTerm: utmTerm ? utmTerm.toLowerCase() : undefined,
};
}
export function triggerUtmRegistration() {
const utmParams = getStoredUtmParams();
console.log(utmParams);
if (!utmParams.utmSource) {
return;
}
localStorage.removeItem('utm_params');
window.fireEvent({
category: 'UserRegistration',
action: `Registration: ${utmParams.utmSource || 'unknown'}-${utmParams.utmCampaign || 'unknown'}`,
label: `Registration: ${utmParams.utmSource || 'unknown'}-${utmParams.utmCampaign || 'unknown'}`,
});
}
export function getStoredUtmParams(): UtmParams {
if (typeof window === 'undefined') {
return {};
}
const utmParams = localStorage.getItem('utm_params');
if (!utmParams) {
return {};
}
return JSON.parse(utmParams);
}
export function getUrlParams() { export function getUrlParams() {
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
return {}; return {};

Loading…
Cancel
Save