Files
calendar/packages/lib/tracking/server.ts
T
Amit SharmaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f9d40e083f feat: store utm tags in stripe on signup (#26838)
* feat: store utm params in stripe on signup

* fix: fallback to cookie when query params don't contain valid UTM data

Changed from else-if to separate if statement so that when query
params exist but don't contain valid UTM data, the cookie fallback
is still tried. Previously, any request with non-UTM query params
would skip the stored cookie data entirely.

Co-Authored-By: unknown <>

* fix: e2e

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-22 08:13:47 -03:00

82 lines
2.0 KiB
TypeScript

import type { NextApiRequest } from "next";
import { z } from "zod";
const utmTrackingDataSchema = z.object({
utm_source: z.string().optional(),
utm_medium: z.string().optional(),
utm_campaign: z.string().optional(),
utm_term: z.string().optional(),
utm_content: z.string().optional(),
utm_id: z.string().optional(),
utm_referral: z.string().optional(),
landing_page: z.string().optional(),
});
export type GoogleAdsTrackingData = {
gclid: string;
campaignId?: string;
};
export type LinkedInAdsTrackingData = {
liFatId: string;
campaignId?: string;
};
export type UtmTrackingData = z.infer<typeof utmTrackingDataSchema>;
export type TrackingData = {
googleAds?: GoogleAdsTrackingData;
linkedInAds?: LinkedInAdsTrackingData;
utmData?: UtmTrackingData;
};
export function getTrackingFromCookies(
cookies?: NextApiRequest["cookies"],
query?: NextApiRequest["query"]
): TrackingData {
const tracking: TrackingData = {};
if (process.env.GOOGLE_ADS_ENABLED === "1" && cookies?.gclid) {
tracking.googleAds = {
gclid: cookies.gclid,
...(cookies.gad_campaignId && { campaignId: cookies.gad_campaignId }),
};
}
if (process.env.LINKEDIN_ADS_ENABLED === "1" && cookies?.li_fat_id) {
tracking.linkedInAds = {
liFatId: cookies.li_fat_id,
...(cookies.li_campaignId && { campaignId: cookies.li_campaignId }),
};
}
const parseUtm = (input: unknown): UtmTrackingData | null => {
const parsed = utmTrackingDataSchema.safeParse(input);
if (!parsed.success) return null;
return Object.fromEntries(
Object.entries(parsed.data).filter(([_, value]) => value !== undefined)
) as UtmTrackingData;
};
let utmData: UtmTrackingData | null = null;
if (query && Object.keys(query).length > 0) {
utmData = parseUtm(query);
}
if (!utmData && cookies?.utm_data) {
try {
utmData = parseUtm(JSON.parse(cookies.utm_data));
} catch {
console.debug("Failed to parse utm_data cookie");
}
}
if (utmData) {
tracking.utmData = utmData;
}
return tracking;
}