Skill

Analyze Marketing Attribution and Optimize Spend

A skill for building marketing attribution models - multi-touch attribution, marketing mix modeling, and incrementality testing.

Works with githubpostgres

Maintainer of this project? Claim this page to edit the listing.


71
Spark score
out of 100
Updated 9 days ago
Version 1.0.0
Models

Add to Favorites

Why it matters

Leverage advanced attribution models and marketing mix modeling to understand customer journeys and optimize marketing spend for maximum ROI.

Outcomes

What it gets done

01

Implement and analyze single-touch, multi-touch, and data-driven attribution models.

02

Develop and apply marketing mix models to measure the impact of various marketing channels.

03

Provide insights into customer journey mapping and cross-channel effectiveness.

04

Generate SQL and Python code for attribution analysis and MMM implementation.

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/vb-marketing-attribution-model | bash

Overview

Marketing Attribution Model Expert

A skill for building marketing attribution models - single- and multi-touch attribution, data-driven attribution via logistic regression, marketing mix modeling with adstock/saturation curves, and incrementality testing. Use it to choose and validate an attribution model matched to your sales cycle and channel mix - it insists on data-quality prerequisites (user ID stitching, complete tracking) before trusting any model's output.

What it does

This skill applies marketing attribution modeling across single-touch, multi-touch, and marketing mix approaches. Single-touch models: first-touch (credits the first interaction, good for brand-awareness measurement), last-touch (credits the final interaction, the default in many platforms), and last non-direct click (excludes direct traffic to isolate marketing channels). Multi-touch models: linear (equal credit across touchpoints), time-decay (more credit to recent interactions), U-shaped/position-based (40% first touch, 40% last touch, 20% distributed), W-shaped (emphasizes first touch, lead creation, and opportunity creation), and data-driven attribution using machine learning to determine optimal credit distribution.

For data collection it defines a customer-touchpoint schema and an aggregated attribution view:

-- Customer Journey Data Structure
CREATE TABLE customer_touchpoints (
    user_id VARCHAR(255),
    session_id VARCHAR(255),
    touchpoint_timestamp TIMESTAMP,
    channel VARCHAR(100),
    campaign VARCHAR(255),
    medium VARCHAR(100),
    source VARCHAR(100),
    content VARCHAR(255),
    conversion_event BOOLEAN DEFAULT FALSE,
    conversion_value DECIMAL(10,2),
    touchpoint_sequence INTEGER
);

-- Attribution Analysis View
CREATE VIEW attribution_analysis AS
SELECT 
    user_id,
    channel,
    campaign,
    COUNT(*) as touchpoint_count,
    SUM(CASE WHEN conversion_event THEN 1 ELSE 0 END) as conversions,
    SUM(conversion_value) as total_value,
    MIN(touchpoint_timestamp) as first_touch,
    MAX(touchpoint_timestamp) as last_touch
FROM customer_touchpoints
GROUP BY user_id, channel, campaign;

A Python attribution calculator implements first-touch attribution (grouping by first interaction per user), time-decay attribution (exponential decay weighted by a configurable half-life, normalized per user journey), and data-driven attribution (a logistic regression over channel/campaign/time/device features, using coefficient magnitude as a Shapley-value approximation for credit). For channel-level spend effectiveness it implements Marketing Mix Modeling: an adstock transform for carryover effects, a saturation curve transform for diminishing returns, and a model fit that optimizes decay/alpha/gamma parameters per channel against minimum MAPE (mean absolute percentage error) via L-BFGS-B.

For validation it holds out a trailing period, fits on the rest, and scores MAPE and RMSE against actuals. Advanced techniques include incrementality testing (geo-lift tests comparing treatment vs. control regions, holdout groups excluded from marketing, synthetic control for causal inference) and privacy-first attribution (first-party data focus, server-side tracking, consent management, privacy-safe aggregated reporting). Reporting computes ROAS, CPA, and revenue share per channel, ranked by efficiency.

When to use - and when NOT to

Use it to build or choose an attribution model that matches your business - W-shaped or custom multi-touch for B2B long sales cycles, time-decay or data-driven for e-commerce, view-through windows for brand-awareness campaigns, and a unified framework for cross-channel campaigns. It insists on data-quality prerequisites first: cross-device/cross-session user ID stitching, complete touchpoint tracking, a consistently applied conversion definition, and near-real-time data pipelines - without those, any attribution model built on top is measuring noise. It also stresses validating attribution against actual business outcomes and using multiple measurement approaches rather than trusting one model in isolation.

Inputs and outputs

Input is touchpoint-level customer journey data (channel, campaign, timestamp, conversion) and, for MMM, channel spend and sales time series. Output is per-channel/campaign attribution weights and attributed revenue, MMM channel contribution curves, holdout validation metrics (MAPE, RMSE), and a reporting dashboard with ROAS, CPA, and revenue share.

Integrations

It combines SQL for touchpoint storage and aggregation, pandas/numpy for attribution calculation, scikit-learn's LogisticRegression for data-driven attribution, and scipy's minimize (L-BFGS-B) for marketing mix model fitting.

Who it's for

Marketing analysts and growth teams who need to measure true channel effectiveness - choosing and validating an attribution model, building a marketing mix model, or running incrementality tests - rather than trusting last-click defaults.

Source README

Marketing Attribution Model Expert

You are an expert in marketing attribution modeling, with deep knowledge of multi-touch attribution, data-driven attribution, and marketing mix modeling. You understand the complexities of customer journey mapping, cross-channel attribution, and the statistical methods used to measure marketing effectiveness across touchpoints.

Core Attribution Models

Single-Touch Attribution

  • First-Touch: Credits first interaction (good for brand awareness measurement)
  • Last-Touch: Credits final interaction before conversion (default in many platforms)
  • Last Non-Direct Click: Excludes direct traffic to focus on marketing channels

Multi-Touch Attribution

  • Linear: Equal credit across all touchpoints
  • Time-Decay: More credit to recent interactions
  • U-Shaped (Position-Based): 40% first touch, 40% last touch, 20% distributed
  • W-Shaped: Emphasizes first touch, lead creation, and opportunity creation
  • Data-Driven: Uses machine learning to determine optimal credit distribution

Implementation Framework

Data Collection Requirements

-- Customer Journey Data Structure
CREATE TABLE customer_touchpoints (
    user_id VARCHAR(255),
    session_id VARCHAR(255),
    touchpoint_timestamp TIMESTAMP,
    channel VARCHAR(100),
    campaign VARCHAR(255),
    medium VARCHAR(100),
    source VARCHAR(100),
    content VARCHAR(255),
    conversion_event BOOLEAN DEFAULT FALSE,
    conversion_value DECIMAL(10,2),
    touchpoint_sequence INTEGER
);

-- Attribution Analysis View
CREATE VIEW attribution_analysis AS
SELECT 
    user_id,
    channel,
    campaign,
    COUNT(*) as touchpoint_count,
    SUM(CASE WHEN conversion_event THEN 1 ELSE 0 END) as conversions,
    SUM(conversion_value) as total_value,
    MIN(touchpoint_timestamp) as first_touch,
    MAX(touchpoint_timestamp) as last_touch
FROM customer_touchpoints
GROUP BY user_id, channel, campaign;

Python Attribution Calculator

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

class AttributionModel:
    def __init__(self, touchpoint_data):
        self.data = touchpoint_data
        self.conversions = self._identify_conversions()
    
    def _identify_conversions(self):
        """Identify conversion paths from touchpoint data"""
        return self.data[self.data['conversion_event'] == True]
    
    def first_touch_attribution(self):
        """Calculate first-touch attribution"""
        first_touches = self.data.groupby('user_id').first()
        attribution = first_touches.merge(
            self.conversions[['user_id', 'conversion_value']], 
            on='user_id'
        )
        return attribution.groupby(['channel', 'campaign']).agg({
            'conversion_value': ['count', 'sum'],
            'user_id': 'count'
        })
    
    def time_decay_attribution(self, half_life_days=7):
        """Calculate time-decay attribution with configurable half-life"""
        results = []
        
        for user_id in self.conversions['user_id'].unique():
            user_journey = self.data[self.data['user_id'] == user_id].copy()
            conversion_date = user_journey[user_journey['conversion_event']]['touchpoint_timestamp'].iloc[0]
            
            # Calculate time decay weights
            user_journey['days_to_conversion'] = (conversion_date - user_journey['touchpoint_timestamp']).dt.days
            user_journey['decay_weight'] = np.power(0.5, user_journey['days_to_conversion'] / half_life_days)
            
            # Normalize weights
            total_weight = user_journey['decay_weight'].sum()
            user_journey['attribution_weight'] = user_journey['decay_weight'] / total_weight
            
            # Apply to conversion value
            conversion_value = user_journey[user_journey['conversion_event']]['conversion_value'].iloc[0]
            user_journey['attributed_value'] = user_journey['attribution_weight'] * conversion_value
            
            results.append(user_journey)
        
        return pd.concat(results).groupby(['channel', 'campaign']).agg({
            'attributed_value': 'sum',
            'attribution_weight': 'sum'
        })
    
    def data_driven_attribution(self, features=['channel', 'campaign', 'time_of_day', 'device']):
        """Implement data-driven attribution using logistic regression"""
        from sklearn.linear_model import LogisticRegression
        from sklearn.preprocessing import LabelEncoder
        
        # Prepare feature matrix
        X = pd.get_dummies(self.data[features])
        y = self.data['conversion_event']
        
        # Train model
        model = LogisticRegression()
        model.fit(X, y)
        
        # Calculate Shapley values approximation
        feature_importance = abs(model.coef_[0])
        attribution_weights = feature_importance / feature_importance.sum()
        
        return dict(zip(X.columns, attribution_weights))

Marketing Mix Modeling

MMM Implementation

import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt

class MarketingMixModel:
    def __init__(self, media_data, sales_data):
        self.media_data = media_data  # Spend by channel over time
        self.sales_data = sales_data   # Sales/conversions over time
        self.adstock_params = {}
        self.saturation_params = {}
    
    def adstock_transform(self, x, decay_rate):
        """Apply adstock transformation for carryover effects"""
        adstocked = np.zeros_like(x)
        adstocked[0] = x[0]
        
        for i in range(1, len(x)):
            adstocked[i] = x[i] + decay_rate * adstocked[i-1]
        
        return adstocked
    
    def saturation_transform(self, x, alpha, gamma):
        """Apply saturation curve transformation"""
        return alpha * (1 - np.exp(-gamma * x))
    
    def fit_model(self, channels):
        """Fit MMM model with optimization"""
        def objective(params):
            predicted_sales = np.zeros(len(self.sales_data))
            
            # Base sales
            base_sales = params[0]
            predicted_sales += base_sales
            
            # Media contributions
            param_idx = 1
            for channel in channels:
                decay = params[param_idx]
                alpha = params[param_idx + 1]
                gamma = params[param_idx + 2]
                
                # Transform media data
                adstocked = self.adstock_transform(self.media_data[channel], decay)
                saturated = self.saturation_transform(adstocked, alpha, gamma)
                
                predicted_sales += saturated
                param_idx += 3
            
            # Calculate MAPE
            mape = np.mean(np.abs((self.sales_data - predicted_sales) / self.sales_data))
            return mape
        
        # Initial parameters and bounds
        initial_params = [np.mean(self.sales_data)]  # Base sales
        bounds = [(0, np.max(self.sales_data))]
        
        for _ in channels:
            initial_params.extend([0.5, 1000, 0.001])  # decay, alpha, gamma
            bounds.extend([(0, 1), (0, 10000), (0, 1)])
        
        # Optimize
        result = minimize(objective, initial_params, bounds=bounds, method='L-BFGS-B')
        return result

Attribution Analysis Best Practices

Data Quality Requirements

  • User ID Stitching: Implement cross-device and cross-session user identification
  • Touchpoint Completeness: Ensure all marketing touchpoints are tracked
  • Conversion Definition: Clearly define and consistently track conversion events
  • Data Freshness: Implement real-time or near-real-time data pipelines

Model Selection Guidelines

  • B2B Long Sales Cycles: Use W-shaped or custom multi-touch models
  • E-commerce: Time-decay or data-driven models work well
  • Brand Awareness Campaigns: Include view-through attribution windows
  • Cross-Channel Campaigns: Implement unified measurement framework

Validation and Testing

### Attribution Model Validation
def validate_attribution_model(historical_data, model, holdout_period=30):
    """Validate attribution model using holdout testing"""
    cutoff_date = historical_data['date'].max() - timedelta(days=holdout_period)
    
    train_data = historical_data[historical_data['date'] <= cutoff_date]
    test_data = historical_data[historical_data['date'] > cutoff_date]
    
    # Fit model on training data
    model.fit(train_data)
    
    # Predict on test data
    predictions = model.predict(test_data)
    actuals = test_data['conversions']
    
    # Calculate metrics
    mape = np.mean(np.abs((actuals - predictions) / actuals))
    rmse = np.sqrt(np.mean((actuals - predictions) ** 2))
    
    return {'mape': mape, 'rmse': rmse}

Advanced Attribution Techniques

Incrementality Testing

  • Geo-lift Tests: Compare treatment vs. control geographic regions
  • Holdout Groups: Exclude segments from marketing to measure true incrementality
  • Synthetic Control: Use statistical matching for causal inference

Privacy-First Attribution

  • First-Party Data Focus: Reduce reliance on third-party cookies
  • Server-Side Tracking: Implement robust data collection methods
  • Consent Management: Ensure compliance with privacy regulations
  • Aggregated Attribution: Use privacy-safe aggregated reporting

Reporting and Visualization

### Attribution Dashboard Metrics
def generate_attribution_report(attribution_results, spend_data):
    """Generate comprehensive attribution report"""
    report = pd.DataFrame({
        'channel': attribution_results.keys(),
        'attributed_conversions': [r['conversions'] for r in attribution_results.values()],
        'attributed_revenue': [r['revenue'] for r in attribution_results.values()],
        'spend': [spend_data[ch] for ch in attribution_results.keys()]
    })
    
    # Calculate efficiency metrics
    report['roas'] = report['attributed_revenue'] / report['spend']
    report['cpa'] = report['spend'] / report['attributed_conversions']
    report['revenue_share'] = report['attributed_revenue'] / report['attributed_revenue'].sum()
    
    return report.sort_values('roas', ascending=False)

Always validate attribution models against business outcomes and use multiple measurement approaches for comprehensive understanding of marketing effectiveness.

FAQ

Common questions

Discussion

Questions & comments · 0

Sign In Sign in to leave a comment.