aboutsummaryrefslogtreecommitdiff
path: root/scripts/seed/distributions/referrers.ts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/seed/distributions/referrers.ts')
-rw-r--r--scripts/seed/distributions/referrers.ts163
1 files changed, 163 insertions, 0 deletions
diff --git a/scripts/seed/distributions/referrers.ts b/scripts/seed/distributions/referrers.ts
new file mode 100644
index 0000000..5b3f2c4
--- /dev/null
+++ b/scripts/seed/distributions/referrers.ts
@@ -0,0 +1,163 @@
+import { weightedRandom, pickRandom, randomInt, type WeightedOption } from '../utils.js';
+
+export type ReferrerType = 'direct' | 'organic' | 'social' | 'paid' | 'referral';
+
+export interface ReferrerInfo {
+ type: ReferrerType;
+ domain: string | null;
+ path: string | null;
+ utmSource: string | null;
+ utmMedium: string | null;
+ utmCampaign: string | null;
+ utmContent: string | null;
+ utmTerm: string | null;
+ gclid: string | null;
+ fbclid: string | null;
+}
+
+const referrerTypeWeights: WeightedOption<ReferrerType>[] = [
+ { value: 'direct', weight: 0.4 },
+ { value: 'organic', weight: 0.25 },
+ { value: 'social', weight: 0.15 },
+ { value: 'paid', weight: 0.1 },
+ { value: 'referral', weight: 0.1 },
+];
+
+const searchEngines = [
+ { domain: 'google.com', path: '/search' },
+ { domain: 'bing.com', path: '/search' },
+ { domain: 'duckduckgo.com', path: '/' },
+ { domain: 'yahoo.com', path: '/search' },
+ { domain: 'baidu.com', path: '/s' },
+];
+
+const socialPlatforms = [
+ { domain: 'twitter.com', path: null },
+ { domain: 'x.com', path: null },
+ { domain: 'linkedin.com', path: '/feed' },
+ { domain: 'facebook.com', path: null },
+ { domain: 'reddit.com', path: '/r/programming' },
+ { domain: 'news.ycombinator.com', path: '/item' },
+ { domain: 'threads.net', path: null },
+ { domain: 'bsky.app', path: null },
+];
+
+const referralSites = [
+ { domain: 'medium.com', path: '/@author/article' },
+ { domain: 'dev.to', path: '/post' },
+ { domain: 'hashnode.com', path: '/blog' },
+ { domain: 'techcrunch.com', path: '/article' },
+ { domain: 'producthunt.com', path: '/posts' },
+ { domain: 'indiehackers.com', path: '/post' },
+];
+
+interface PaidCampaign {
+ source: string;
+ medium: string;
+ campaign: string;
+ useGclid?: boolean;
+ useFbclid?: boolean;
+}
+
+const paidCampaigns: PaidCampaign[] = [
+ { source: 'google', medium: 'cpc', campaign: 'brand_search', useGclid: true },
+ { source: 'google', medium: 'cpc', campaign: 'product_awareness', useGclid: true },
+ { source: 'facebook', medium: 'paid_social', campaign: 'retargeting', useFbclid: true },
+ { source: 'facebook', medium: 'paid_social', campaign: 'lookalike', useFbclid: true },
+ { source: 'linkedin', medium: 'cpc', campaign: 'b2b_targeting' },
+ { source: 'twitter', medium: 'paid_social', campaign: 'launch_promo' },
+];
+
+const organicCampaigns = [
+ { source: 'newsletter', medium: 'email', campaign: 'weekly_digest' },
+ { source: 'newsletter', medium: 'email', campaign: 'product_update' },
+ { source: 'partner', medium: 'referral', campaign: 'integration_launch' },
+];
+
+function generateClickId(): string {
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ let result = '';
+ for (let i = 0; i < 32; i++) {
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
+ }
+ return result;
+}
+
+export function getRandomReferrer(): ReferrerInfo {
+ const type = weightedRandom(referrerTypeWeights);
+
+ const result: ReferrerInfo = {
+ type,
+ domain: null,
+ path: null,
+ utmSource: null,
+ utmMedium: null,
+ utmCampaign: null,
+ utmContent: null,
+ utmTerm: null,
+ gclid: null,
+ fbclid: null,
+ };
+
+ switch (type) {
+ case 'direct':
+ // No referrer data
+ break;
+
+ case 'organic': {
+ const engine = pickRandom(searchEngines);
+ result.domain = engine.domain;
+ result.path = engine.path;
+ break;
+ }
+
+ case 'social': {
+ const platform = pickRandom(socialPlatforms);
+ result.domain = platform.domain;
+ result.path = platform.path;
+
+ // Some social traffic has UTM params
+ if (Math.random() < 0.3) {
+ result.utmSource = platform.domain.replace('.com', '').replace('.net', '');
+ result.utmMedium = 'social';
+ }
+ break;
+ }
+
+ case 'paid': {
+ const campaign = pickRandom(paidCampaigns);
+ result.utmSource = campaign.source;
+ result.utmMedium = campaign.medium;
+ result.utmCampaign = campaign.campaign;
+ result.utmContent = `ad_${randomInt(1, 5)}`;
+
+ if (campaign.useGclid) {
+ result.gclid = generateClickId();
+ result.domain = 'google.com';
+ result.path = '/search';
+ } else if (campaign.useFbclid) {
+ result.fbclid = generateClickId();
+ result.domain = 'facebook.com';
+ result.path = null;
+ }
+ break;
+ }
+
+ case 'referral': {
+ // Mix of pure referrals and organic campaigns
+ if (Math.random() < 0.6) {
+ const site = pickRandom(referralSites);
+ result.domain = site.domain;
+ result.path = site.path;
+ } else {
+ const campaign = pickRandom(organicCampaigns);
+ result.utmSource = campaign.source;
+ result.utmMedium = campaign.medium;
+ result.utmCampaign = campaign.campaign;
+ }
+ break;
+ }
+ }
+
+ return result;
+}