geo-measurement
AI Traffic Attribution
Use Cases
AI Channel Performance Measurement
Tracking visits, engagement, and conversions from different AI sources (ChatGPT vs Perplexity vs Bing Copilot) to understand which AI platforms drive the most valuable traffic.
GEO ROI Calculation
Measuring traffic and conversion impact of GEO initiatives by accurately attributing AI-influenced visits, enabling proper return on investment analysis for AI optimization efforts.
Customer Journey Mapping
Understanding how AI touchpoints fit into multi-channel customer journeys, identifying patterns where AI discovery leads to conversion through various paths.
Content Performance Analysis
Identifying which content pieces drive the most AI-attributed traffic, revealing what types of content AI systems prefer to cite and link to.
Competitive Intelligence
Comparing AI traffic share against industry benchmarks and competitors to understand relative AI visibility and market positioning.
Marketing Attribution Modeling
Incorporating AI touchpoints into multi-touch attribution models to properly credit AI's role in conversion paths alongside traditional channels.
Key Metrics
AI Traffic Volume
Total sessions attributed to AI sources within a given period
Sum of all sessions with AI source attributionAI Traffic Share
Percentage of total traffic coming from AI sources
(AI-Attributed Sessions / Total Sessions) × 100AI Conversion Rate
Conversion rate for AI-attributed visitors compared to overall site
(AI-Attributed Conversions / AI-Attributed Sessions) × 100AI Revenue Attribution
Revenue attributed to AI-driven traffic using attribution modeling
Sum of (AI-Attributed Conversions × Conversion Value × Attribution Weight)AI Traffic Quality Index
Composite score of AI traffic engagement metrics vs site average
(AI Engagement Score / Site Average Engagement Score) × 100Platform Distribution
Breakdown of AI traffic by source platform
(Traffic from Platform X / Total AI Traffic) × 100AI-to-Conversion Latency
Average time from AI-attributed first touch to conversion
Average(Conversion Timestamp - First AI Touch Timestamp)Dark AI Traffic Estimate
Estimated AI traffic appearing as direct/unattributed based on behavioral signals
Direct Traffic with AI Behavioral Patterns × Confidence ScoreHow LLMs Interpret This
1// AI Traffic Attribution Implementation2interface AITrafficSource {3 id: string;4 name: string;5 userAgentPatterns: RegExp[];6 referrerPatterns: RegExp[];7 urlPatterns: RegExp[];8 behavioralSignals?: BehavioralSignal[];9}10 11interface BehavioralSignal {12 type: 'landing_page' | 'session_pattern' | 'navigation_flow';13 pattern: any;14 confidence: number;15}16 17interface AttributedSession {18 sessionId: string;19 timestamp: Date;20 source: string;21 attributionMethod: 'referrer' | 'user_agent' | 'url_param' | 'behavioral' | 'correlation';22 confidence: number;23 landingPage: string;24 conversions: Conversion[];25 engagement: EngagementMetrics;26}27 28interface Conversion {29 type: string;30 value: number;31 timestamp: Date;32}33 34interface EngagementMetrics {35 pageViews: number;36 timeOnSite: number;37 bounced: boolean;38 pagesPerSession: number;39}40 41interface AttributionReport {42 period: { start: Date; end: Date };43 totalSessions: number;44 aiAttributedSessions: number;45 aiTrafficShare: number;46 sourceBreakdown: Record<string, {47 sessions: number;48 conversions: number;49 revenue: number;50 avgEngagement: number;51 }>;52 darkAIEstimate: {53 estimatedSessions: number;54 confidence: number;55 };56 conversionMetrics: {57 aiConversionRate: number;58 siteConversionRate: number;59 aiRevenueAttribution: number;60 };61}62 63class AITrafficAttributor {64 private sources: AITrafficSource[] = [65 {66 id: 'chatgpt',67 name: 'ChatGPT',68 userAgentPatterns: [/ChatGPT/i, /OpenAI/i],69 referrerPatterns: [/chat\.openai\.com/i, /chatgpt\.com/i],70 urlPatterns: [/[?&]utm_source=chatgpt/i],71 },72 {73 id: 'perplexity',74 name: 'Perplexity',75 userAgentPatterns: [/Perplexity/i],76 referrerPatterns: [/perplexity\.ai/i],77 urlPatterns: [/[?&]utm_source=perplexity/i],78 },79 {80 id: 'claude',81 name: 'Claude',82 userAgentPatterns: [/Claude/i, /Anthropic/i],83 referrerPatterns: [/claude\.ai/i, /anthropic\.com/i],84 urlPatterns: [/[?&]utm_source=claude/i],85 },86 {87 id: 'bing_copilot',88 name: 'Bing Copilot',89 userAgentPatterns: [/Copilot/i],90 referrerPatterns: [/bing\.com\/chat/i, /copilot\.microsoft/i],91 urlPatterns: [/[?&]utm_source=bing_copilot/i],92 },93 {94 id: 'gemini',95 name: 'Google Gemini',96 userAgentPatterns: [/Gemini/i],97 referrerPatterns: [/gemini\.google/i, /bard\.google/i],98 urlPatterns: [/[?&]utm_source=gemini/i],99 },100 ];101 102 private sessions: AttributedSession[] = [];103 104 // Attribute a session to an AI source105 attributeSession(sessionData: {106 sessionId: string;107 userAgent: string;108 referrer: string;109 landingUrl: string;110 timestamp: Date;111 engagement: EngagementMetrics;112 conversions: Conversion[];113 }): AttributedSession | null {114 // Try each attribution method in order of confidence115 let attribution = this.checkReferrer(sessionData.referrer);116 let method: AttributedSession['attributionMethod'] = 'referrer';117 let confidence = 0.95;118 119 if (!attribution) {120 attribution = this.checkUserAgent(sessionData.userAgent);121 method = 'user_agent';122 confidence = 0.9;123 }124 125 if (!attribution) {126 attribution = this.checkUrlParams(sessionData.landingUrl);127 method = 'url_param';128 confidence = 0.99;129 }130 131 if (!attribution) {132 attribution = this.checkBehavioralSignals(sessionData);133 method = 'behavioral';134 confidence = 0.6;135 }136 137 if (attribution) {138 const attributedSession: AttributedSession = {139 sessionId: sessionData.sessionId,140 timestamp: sessionData.timestamp,141 source: attribution,142 attributionMethod: method,143 confidence,144 landingPage: new URL(sessionData.landingUrl).pathname,145 conversions: sessionData.conversions,146 engagement: sessionData.engagement,147 };148 149 this.sessions.push(attributedSession);150 return attributedSession;151 }152 153 return null;154 }155 156 private checkReferrer(referrer: string): string | null {157 for (const source of this.sources) {158 for (const pattern of source.referrerPatterns) {159 if (pattern.test(referrer)) {160 return source.id;161 }162 }163 }164 return null;165 }166 167 private checkUserAgent(userAgent: string): string | null {168 for (const source of this.sources) {169 for (const pattern of source.userAgentPatterns) {170 if (pattern.test(userAgent)) {171 return source.id;172 }173 }174 }175 return null;176 }177 178 private checkUrlParams(url: string): string | null {179 for (const source of this.sources) {180 for (const pattern of source.urlPatterns) {181 if (pattern.test(url)) {182 return source.id;183 }184 }185 }186 return null;187 }188 189 private checkBehavioralSignals(sessionData: {190 landingUrl: string;191 engagement: EngagementMetrics;192 }): string | null {193 // Check for behavioral patterns typical of AI traffic194 const landingPath = new URL(sessionData.landingUrl).pathname;195 196 // AI traffic often lands on specific content types197 const aiTypicalLandingPatterns = [198 /\/blog\/.+/,199 /\/guides?\/.+/,200 /\/how-to\/.+/,201 /\/what-is\/.+/,202 ];203 204 const isAITypicalLanding = aiTypicalLandingPatterns.some(205 p => p.test(landingPath)206 );207 208 // AI visitors often have distinct engagement patterns209 const hasAIEngagementPattern = 210 sessionData.engagement.timeOnSite > 120 && // > 2 min211 sessionData.engagement.pagesPerSession < 3 && // Focused visit212 !sessionData.engagement.bounced;213 214 if (isAITypicalLanding && hasAIEngagementPattern) {215 return 'unknown_ai'; // Probable AI, unknown source216 }217 218 return null;219 }220 221 // Estimate 'dark' AI traffic in direct visits222 estimateDarkAITraffic(223 directSessions: any[],224 knownAIRatio: number225 ): { estimatedSessions: number; confidence: number } {226 // Analyze direct traffic for AI-like patterns227 let aiLikeDirectSessions = 0;228 229 directSessions.forEach(session => {230 const hasAIPattern = this.checkBehavioralSignals({231 landingUrl: session.landingUrl,232 engagement: session.engagement,233 });234 if (hasAIPattern) {235 aiLikeDirectSessions++;236 }237 });238 239 // Apply known AI ratio calibration240 const estimatedSessions = Math.round(241 aiLikeDirectSessions * knownAIRatio242 );243 244 return {245 estimatedSessions,246 confidence: 0.4 + (knownAIRatio * 0.3), // Higher if ratio is well-established247 };248 }249 250 // Generate comprehensive attribution report251 generateReport(startDate: Date, endDate: Date): AttributionReport {252 const periodSessions = this.sessions.filter(253 s => s.timestamp >= startDate && s.timestamp <= endDate254 );255 256 // Total attributed AI sessions257 const aiAttributedSessions = periodSessions.length;258 259 // Source breakdown260 const sourceBreakdown: AttributionReport['sourceBreakdown'] = {};261 262 for (const source of this.sources) {263 const sourceSessions = periodSessions.filter(264 s => s.source === source.id265 );266 267 const conversions = sourceSessions.reduce(268 (sum, s) => sum + s.conversions.length, 0269 );270 271 const revenue = sourceSessions.reduce(272 (sum, s) => sum + s.conversions.reduce((r, c) => r + c.value, 0), 0273 );274 275 const avgEngagement = sourceSessions.length > 0276 ? sourceSessions.reduce((sum, s) => sum + s.engagement.timeOnSite, 0) / sourceSessions.length277 : 0;278 279 sourceBreakdown[source.id] = {280 sessions: sourceSessions.length,281 conversions,282 revenue,283 avgEngagement,284 };285 }286 287 // Include unknown AI288 const unknownAISessions = periodSessions.filter(289 s => s.source === 'unknown_ai'290 );291 if (unknownAISessions.length > 0) {292 sourceBreakdown['unknown_ai'] = {293 sessions: unknownAISessions.length,294 conversions: unknownAISessions.reduce(295 (sum, s) => sum + s.conversions.length, 0296 ),297 revenue: unknownAISessions.reduce(298 (sum, s) => sum + s.conversions.reduce((r, c) => r + c.value, 0), 0299 ),300 avgEngagement: unknownAISessions.reduce(301 (sum, s) => sum + s.engagement.timeOnSite, 0302 ) / unknownAISessions.length,303 };304 }305 306 // Calculate conversion metrics307 const totalConversions = periodSessions.reduce(308 (sum, s) => sum + s.conversions.length, 0309 );310 const aiConversionRate = aiAttributedSessions > 0311 ? (totalConversions / aiAttributedSessions) * 100312 : 0;313 314 const aiRevenue = periodSessions.reduce(315 (sum, s) => sum + s.conversions.reduce((r, c) => r + c.value, 0), 0316 );317 318 // Placeholder for total site metrics (would come from main analytics)319 const totalSessions = aiAttributedSessions * 15; // Example: AI is ~7% of traffic320 const siteConversionRate = 3.2; // Example site average321 322 return {323 period: { start: startDate, end: endDate },324 totalSessions,325 aiAttributedSessions,326 aiTrafficShare: (aiAttributedSessions / totalSessions) * 100,327 sourceBreakdown,328 darkAIEstimate: {329 estimatedSessions: Math.round(aiAttributedSessions * 0.5), // Estimate 50% more is dark330 confidence: 0.5,331 },332 conversionMetrics: {333 aiConversionRate,334 siteConversionRate,335 aiRevenueAttribution: aiRevenue,336 },337 };338 }339 340 // Analyze AI traffic quality vs site average341 analyzeTrafficQuality(): {342 source: string;343 qualityScore: number;344 engagementVsAvg: number;345 conversionVsAvg: number;346 recommendation: string;347 }[] {348 const report = this.generateReport(349 new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),350 new Date()351 );352 353 const analysis: {354 source: string;355 qualityScore: number;356 engagementVsAvg: number;357 conversionVsAvg: number;358 recommendation: string;359 }[] = [];360 361 // Site averages (would come from main analytics)362 const siteAvgEngagement = 150; // seconds363 const siteConversionRate = report.conversionMetrics.siteConversionRate;364 365 Object.entries(report.sourceBreakdown).forEach(([source, data]) => {366 if (data.sessions === 0) return;367 368 const sourceConversionRate = (data.conversions / data.sessions) * 100;369 const engagementVsAvg = (data.avgEngagement / siteAvgEngagement - 1) * 100;370 const conversionVsAvg = (sourceConversionRate / siteConversionRate - 1) * 100;371 372 // Quality score: weighted combination of engagement and conversion373 const qualityScore = (374 (engagementVsAvg * 0.3 + conversionVsAvg * 0.7 + 100) / 2375 );376 377 let recommendation = '';378 if (conversionVsAvg > 20) {379 recommendation = 'High-value source. Prioritize GEO optimization for this platform.';380 } else if (conversionVsAvg < -20) {381 recommendation = 'Lower conversion rate. Analyze landing experience for this source.';382 } else if (engagementVsAvg < -30) {383 recommendation = 'Low engagement. Review content relevance for queries driving this traffic.';384 } else {385 recommendation = 'Performing at site average. Monitor for changes.';386 }387 388 analysis.push({389 source,390 qualityScore,391 engagementVsAvg,392 conversionVsAvg,393 recommendation,394 });395 });396 397 return analysis.sort((a, b) => b.qualityScore - a.qualityScore);398 }399}400 401// Usage example402const attributor = new AITrafficAttributor();403 404// Attribute incoming sessions405attributor.attributeSession({406 sessionId: 'sess_001',407 userAgent: 'Mozilla/5.0 (compatible; ChatGPT-User)',408 referrer: '',409 landingUrl: 'https://example.com/guides/project-management-best-practices',410 timestamp: new Date(),411 engagement: {412 pageViews: 4,413 timeOnSite: 245,414 bounced: false,415 pagesPerSession: 4,416 },417 conversions: [418 { type: 'signup', value: 50, timestamp: new Date() }419 ],420});421 422// Generate report423const report = attributor.generateReport(424 new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),425 new Date()426);427 428console.log('AI Traffic Attribution Report:', {429 'AI Traffic Share': `${report.aiTrafficShare.toFixed(1)}%`,430 'AI Sessions': report.aiAttributedSessions,431 'AI Conversion Rate': `${report.conversionMetrics.aiConversionRate.toFixed(2)}%`,432 'AI Revenue': `$${report.conversionMetrics.aiRevenueAttribution.toLocaleString()}`,433 'Dark AI Estimate': `~${report.darkAIEstimate.estimatedSessions} sessions`,434});435 436console.log('\nSource Breakdown:');437Object.entries(report.sourceBreakdown).forEach(([source, data]) => {438 console.log(` ${source}: ${data.sessions} sessions, ${data.conversions} conversions, $${data.revenue}`);439});440 441// Analyze traffic quality442const qualityAnalysis = attributor.analyzeTrafficQuality();443console.log('\nTraffic Quality Analysis:');444qualityAnalysis.forEach(item => {445 console.log(` ${item.source}: Quality Score ${item.qualityScore.toFixed(0)}`);446 console.log(` ${item.recommendation}`);447});Examples
SaaS Platform AI Channel Discovery
E-commerce AI Traffic Optimization
Publisher AI Referral Analysis
Export Structured Data
{
"@context": "https://schema.org",
"@type": "DefinedTerm",
"name": "Untitled",
"alternateName": [],
"description": "",
"inDefinedTermSet": {
"@type": "DefinedTermSet",
"name": "AI Optimization Glossary",
"url": "https://geordy.ai/glossary"
},
"url": "https://geordy.ai/glossary/geo-measurement/ai-traffic-attribution"
}Details
- Category
- geo-measurement
- Type
- metric
- Level
- intermediate