# Time-Decay Attribution: Credit Recent Touchpoints More

Time-decay attribution gives more credit to touchpoints closer to conversion. Learn how the half-life parameter works, when time-decay is the right model, and how to implement it for your business.

- Canonical: https://mbuzz.co/articles/time-decay-attribution
- Published: 2026-05-01
- Last updated: 2026-07-23
- Author: Holly Mehakovic, mbuzz (https://mbuzz.co)

---

> **TL;DR:** Time-decay attribution gives more credit to touchpoints closer to the conversion moment. Credit decreases exponentially as you go further back in time—controlled by a 'half-life' parameter (commonly 7 days). It's a middle ground between last-touch and linear: acknowledging all touchpoints while recognizing that recent interactions often have more influence on the final decision.


## What Time-Decay Attribution Measures

Time-decay attribution answers: **"How much did each touchpoint contribute, considering that recent touches probably mattered more?"**

It's a compromise between linear (equal credit) and last-touch (all credit to final touch):

*[Chart omitted from the text version: Reusable customer-journey visual for attribution articles.
    Locals:
      title:    String header (uppercase tracking)
      steps:    Array of step hashes with keys:
                  day:     "Day 1" / "Day -30" / "Same day" — small label above
                  label:   "Facebook Ad" — main pill text
                  role:    :inactive | :credited | :conversion (controls colour)
                  percent: optional small label under pill (e.g. "100%", "50%")
                  sublabel: optional italic text under percent
      caption:  String — italic caption under the row]*


The touchpoint on the same day gets the most credit. The touchpoint from 13 days ago gets the least—but it still gets *some* credit, unlike last-touch.

### The Half-Life Concept

Time-decay uses exponential decay with a **half-life** parameter. At one half-life before conversion, a touchpoint receives 50% of the credit it would get if it happened at conversion time.

| Days Before Conversion | Credit (7-Day Half-Life) |
|-----------------------|--------------------------|
| 0 (same day) | 100% base weight |
| 7 days | 50% of base |
| 14 days | 25% of base |
| 21 days | 12.5% of base |
| 28 days | 6.25% of base |

Credit decays quickly. A touchpoint from 28 days ago gets only 6% of the weight of a same-day touchpoint.

## When Time-Decay Is the Right Choice

### 1. E-Commerce and Retail

E-commerce purchases often follow a pattern: browse, consider, return, buy. The recent touches—the retargeting ad, the email reminder, the price drop notification—often tip the decision.

<div class="not-prose my-8 bg-white border border-slate-200 rounded-lg overflow-hidden">
  <div class="px-5 py-3 border-b border-slate-200 bg-slate-50">
    <p class="text-xs font-bold text-slate-500 tracking-[0.15em]">TYPICAL E-COMMERCE JOURNEY</p>
  </div>
  <ol class="divide-y divide-slate-100">
    <li class="flex items-baseline gap-4 px-5 py-3"><span class="text-xs font-mono font-semibold text-slate-500 w-12 shrink-0">Day 1</span><span class="text-sm text-slate-700"><strong>Discovery</strong> &mdash; paid social impression. Low intent.</span></li>
    <li class="flex items-baseline gap-4 px-5 py-3"><span class="text-xs font-mono font-semibold text-slate-500 w-12 shrink-0">Day 3</span><span class="text-sm text-slate-700"><strong>Research</strong> &mdash; organic search visit. Building interest.</span></li>
    <li class="flex items-baseline gap-4 px-5 py-3"><span class="text-xs font-mono font-semibold text-slate-500 w-12 shrink-0">Day 5</span><span class="text-sm text-slate-700"><strong>Product page</strong> &mdash; direct visit. Considering.</span></li>
    <li class="flex items-baseline gap-4 px-5 py-3"><span class="text-xs font-mono font-semibold text-slate-500 w-12 shrink-0">Day 7</span><span class="text-sm text-slate-700"><strong>Cart abandon email</strong> &mdash; re-engagement.</span></li>
    <li class="flex items-baseline gap-4 px-5 py-3 bg-indigo-50/40"><span class="text-xs font-mono font-semibold text-indigo-700 w-12 shrink-0">Day 8</span><span class="text-sm text-slate-900"><strong>Purchase</strong> via retargeting click.</span></li>
  </ol>
</div>

### 2. Short-to-Medium Sales Cycles

For products bought within 2-4 weeks, time-decay captures the intensifying engagement pattern:

| Sales Cycle | Half-Life Recommendation |
|-------------|-------------------------|
| 1-7 days | 3 days |
| 1-2 weeks | 5-7 days |
| 2-4 weeks | 7-10 days |
| 1-2 months | 14-21 days |

Match your half-life to your typical consideration period.

### 3. Urgency and Seasonality

Products with urgency (events, limited offers, seasonal items) see compressed decision windows. Recent touches matter more:

- Concert tickets: Decision made days before purchase
- Black Friday deals: Hours matter, not days
- Tax services: Last week of tax season drives conversion

Time-decay with a short half-life (3-5 days) captures these dynamics.

### 4. When You Want More Nuance Than Last-Touch

Time-decay acknowledges that early touches contributed—they just mattered less than recent ones:

| Model | Facebook (Day 1) | Email (Day 12) | Search (Day 14) |
|-------|-----------------|----------------|-----------------|
| Last-touch | 0% | 0% | 100% |
| Time-decay (7d) | 6% | 32% | 62% |
| Linear | 33% | 33% | 33% |

Time-decay sits between the extremes, providing a reasonable middle ground.

> **Note:**
> **Rule of thumb:** Use time-decay when you believe recency matters but don't want to ignore early-funnel completely. It's the "I don't want to go full last-touch" model.

## When Time-Decay Is the Wrong Choice

### 1. Long B2B Sales Cycles

With 90+ day sales cycles, time-decay aggressively underweights the touchpoints that started the journey:

*[Chart omitted from the text version: Reusable customer-journey visual for attribution articles.
    Locals:
      title:    String header (uppercase tracking)
      steps:    Array of step hashes with keys:
                  day:     "Day 1" / "Day -30" / "Same day" — small label above
                  label:   "Facebook Ad" — main pill text
                  role:    :inactive | :credited | :conversion (controls colour)
                  percent: optional small label under pill (e.g. "100%", "50%")
                  sublabel: optional italic text under percent
      caption:  String — italic caption under the row]*


The LinkedIn ad that sourced the deal gets nearly zero credit—which doesn't reflect its importance.

**Fix:** Either use a much longer half-life (30+ days) or switch to position-based for B2B.

### 2. When First-Touch Really Matters

For businesses where the introduction is critical—breaking into a new audience, first-time brand exposure—time-decay undervalues that moment.

### 3. Content-Heavy Journeys

If your funnel relies on progressive education (SaaS with whitepapers → webinars → demos), each content piece builds on the previous. Time-decay penalizes the foundational content.

> **Warning:**
> **The recency bias trap:** Time-decay, like last-touch, systematically credits closers over introducers. Use it only when you believe recency genuinely correlates with influence—not just because it seems intuitive.

## How Time-Decay Works

### The Math

Time-decay uses exponential decay:

```
Weight = 2^(-t / half_life)
```

Where:
- t = time between touchpoint and conversion (in days)
- half_life = your chosen parameter (commonly 7 days)

Then normalize weights so they sum to 1:

```
Credit = Weight / Sum(all weights)
```

### Example Calculation

Journey: 3 touchpoints at Day 1, Day 7, and Day 14 (conversion)
Half-life: 7 days

| Touchpoint | Days Before | Raw Weight | Normalized Credit |
|------------|-------------|------------|-------------------|
| Day 1 | 13 | 2^(-13/7) = 0.27 | 0.27/1.77 = 15% |
| Day 7 | 7 | 2^(-7/7) = 0.50 | 0.50/1.77 = 28% |
| Day 14 | 0 | 2^(0/7) = 1.00 | 1.00/1.77 = 57% |
| **Total** | | **1.77** | **100%** |

### Implementation

```ruby
class TimeDecayAttribution
  def initialize(half_life_days: 7, lookback_days: 30)
    @half_life_days = half_life_days
    @lookback_days = lookback_days
  end

  def attribute(conversion)
    touchpoints = conversion.user.touchpoints
      .where("occurred_at >= ?", conversion.occurred_at - @lookback_days.days)
      .where("occurred_at <= ?", conversion.occurred_at)
      .order(:occurred_at)

    return [] if touchpoints.empty?

    # Calculate raw weights
    weights = touchpoints.map do |tp|
      days_before = (conversion.occurred_at.to_date - tp.occurred_at.to_date).to_i
      calculate_weight(days_before)
    end

    total_weight = weights.sum

    # Normalize and build results
    touchpoints.zip(weights).map do |touchpoint, weight|
      {
        channel: touchpoint.channel,
        source: touchpoint.source,
        medium: touchpoint.medium,
        campaign: touchpoint.campaign,
        credit: weight / total_weight,
        touchpoint_at: touchpoint.occurred_at
      }
    end
  end

  private

  def calculate_weight(days_before)
    2.0 ** (-days_before.to_f / @half_life_days)
  end
end
```

### Choosing Your Half-Life

| Business Type | Typical Cycle | Recommended Half-Life |
|---------------|---------------|----------------------|
| Impulse e-commerce | < 3 days | 1-2 days |
| Considered e-commerce | 1-2 weeks | 5-7 days |
| Low-cost SaaS | 2-4 weeks | 7-14 days |
| Mid-market SaaS | 1-3 months | 14-21 days |
| Enterprise B2B | 3-12 months | 30+ days (or use position-based) |

**Validate your choice:** Look at your time-to-conversion distribution. Set half-life so touchpoints within your typical buying window still get meaningful credit.

## Comparing Time-Decay to Other Models

### Time-Decay vs Last-Touch

| Aspect | Time-Decay | Last-Touch |
|--------|------------|------------|
| Early touches | Some credit (decayed) | Zero credit |
| Late touches | Most credit | All credit |
| Extremity | Moderate | Extreme |
| Funnel view | Compressed but visible | Only sees the close |

**When to prefer time-decay:** When you want last-touch's recency emphasis without completely ignoring the journey.

### Time-Decay vs Linear

| Aspect | Time-Decay | Linear |
|--------|------------|--------|
| Credit distribution | Weighted by recency | Equal |
| Assumption | Recent = more important | All equal |
| Awareness channels | Under-credited | Fair credit |
| Conversion channels | Boosted | Fair credit |

**When to prefer time-decay:** E-commerce, short cycles, urgency products.
**When to prefer linear:** B2B, long cycles, education-heavy funnels.

### Time-Decay vs Position-Based

| Aspect | Time-Decay | Position-Based |
|--------|------------|----------------|
| First-touch credit | Low (decayed) | High (40%) |
| Last-touch credit | High | High (40%) |
| Middle credit | Varies by recency | Low (20% split) |
| Use case | Recency-driven | First/last emphasis |

**When to prefer time-decay:** Short cycles where introduction is less critical.
**When to prefer position-based:** B2B where both sourcing and closing matter.

## Time-Decay in Practice

### Visualizing the Decay Curve

<div class="not-prose my-8 bg-white border border-slate-200 rounded-lg overflow-hidden">
  <div class="px-5 py-3 border-b border-slate-200 bg-slate-50">
    <p class="text-xs font-bold text-slate-500 tracking-[0.15em]">CREDIT WEIGHT BY DAYS BEFORE CONVERSION (7-DAY HALF-LIFE)</p>
  </div>
  <div class="px-5 py-5">
      <div class="grid grid-cols-[7rem_1fr_3rem] sm:grid-cols-[9rem_1fr_3.5rem] items-center gap-x-3 sm:gap-x-4 py-1.5">
        <div class="text-xs sm:text-sm font-mono text-slate-600 text-right">Same day (0)</div>
        <div class="h-5 sm:h-6 bg-slate-100 rounded-sm overflow-hidden">
          <div class="h-full bg-indigo-500 rounded-sm" style="width: 100%;"></div>
        </div>
        <div class="text-xs sm:text-sm font-mono font-semibold text-indigo-700 text-right">100%</div>
      </div>
      <div class="grid grid-cols-[7rem_1fr_3rem] sm:grid-cols-[9rem_1fr_3.5rem] items-center gap-x-3 sm:gap-x-4 py-1.5">
        <div class="text-xs sm:text-sm font-mono text-slate-600 text-right">7 days before</div>
        <div class="h-5 sm:h-6 bg-slate-100 rounded-sm overflow-hidden">
          <div class="h-full bg-indigo-500 rounded-sm" style="width: 50%;"></div>
        </div>
        <div class="text-xs sm:text-sm font-mono font-semibold text-indigo-700 text-right">50%</div>
      </div>
      <div class="grid grid-cols-[7rem_1fr_3rem] sm:grid-cols-[9rem_1fr_3.5rem] items-center gap-x-3 sm:gap-x-4 py-1.5">
        <div class="text-xs sm:text-sm font-mono text-slate-600 text-right">14 days before</div>
        <div class="h-5 sm:h-6 bg-slate-100 rounded-sm overflow-hidden">
          <div class="h-full bg-indigo-500 rounded-sm" style="width: 25%;"></div>
        </div>
        <div class="text-xs sm:text-sm font-mono font-semibold text-indigo-700 text-right">25%</div>
      </div>
      <div class="grid grid-cols-[7rem_1fr_3rem] sm:grid-cols-[9rem_1fr_3.5rem] items-center gap-x-3 sm:gap-x-4 py-1.5">
        <div class="text-xs sm:text-sm font-mono text-slate-600 text-right">21 days before</div>
        <div class="h-5 sm:h-6 bg-slate-100 rounded-sm overflow-hidden">
          <div class="h-full bg-indigo-500 rounded-sm" style="width: 12.5%;"></div>
        </div>
        <div class="text-xs sm:text-sm font-mono font-semibold text-indigo-700 text-right">12.5%</div>
      </div>
      <div class="grid grid-cols-[7rem_1fr_3rem] sm:grid-cols-[9rem_1fr_3.5rem] items-center gap-x-3 sm:gap-x-4 py-1.5">
        <div class="text-xs sm:text-sm font-mono text-slate-600 text-right">28 days before</div>
        <div class="h-5 sm:h-6 bg-slate-100 rounded-sm overflow-hidden">
          <div class="h-full bg-indigo-500 rounded-sm" style="width: 6.25%;"></div>
        </div>
        <div class="text-xs sm:text-sm font-mono font-semibold text-indigo-700 text-right">6.25%</div>
      </div>
      <div class="grid grid-cols-[7rem_1fr_3rem] sm:grid-cols-[9rem_1fr_3.5rem] items-center gap-x-3 sm:gap-x-4 py-1.5">
        <div class="text-xs sm:text-sm font-mono text-slate-600 text-right">35 days before</div>
        <div class="h-5 sm:h-6 bg-slate-100 rounded-sm overflow-hidden">
          <div class="h-full bg-indigo-500 rounded-sm" style="width: 3.1%;"></div>
        </div>
        <div class="text-xs sm:text-sm font-mono font-semibold text-indigo-700 text-right">3.1%</div>
      </div>
  </div>
</div>

### Impact on Channel Credit

Here's how a typical e-commerce business sees credit shift between models:

| Channel | Last-Touch | Time-Decay (7d) | Linear |
|---------|------------|-----------------|--------|
| Paid Social | 8% | 18% | 30% |
| Email | 40% | 32% | 20% |
| Retargeting | 25% | 22% | 15% |
| Organic | 12% | 15% | 20% |
| Paid Search | 15% | 13% | 15% |

Time-decay rebalances from pure last-touch but still favors conversion channels.

### Setting Up Multiple Half-Lives

Some teams run time-decay with different half-lives for different analyses:

| Analysis | Half-Life | Purpose |
|----------|-----------|---------|
| Performance marketing | 3 days | Optimize conversion |
| Standard reporting | 7 days | Balanced view |
| Brand marketing | 21 days | Value awareness |

Compare results to understand how half-life assumptions affect credit.

## Common Time-Decay Mistakes

### Mistake 1: Using Default Half-Life Without Analysis

The 7-day default may not match your business. If your sales cycle is 30 days, 7-day half-life crushes early-touch credit.

**Fix:** Analyze your time-to-conversion distribution. Set half-life to match your business reality.

### Mistake 2: Forgetting About Lookback Window

Time-decay still needs a lookback window. Too short = missing early touches. Too long = including irrelevant ancient touches.

**Fix:** Set lookback to 2-3x your typical sales cycle. A 14-day cycle should use 30-45 day lookback.

### Mistake 3: Assuming Recency = Causation

Just because email was recent doesn't mean it caused the purchase. The user might have already decided; email just reminded them.

**Fix:** Validate time-decay with incrementality tests. Does email's attributed credit match its actual incremental impact?

### Mistake 4: Using Same Half-Life for All Segments

New customers vs returning customers have different journey patterns. Applying one half-life to both distorts credit.

**Fix:** Consider segment-specific half-lives or analyze segments separately.

## Time-Decay and GA4

Google Analytics 4 removed time-decay attribution in 2023. Your options:

### 1. Third-Party Attribution Tools

Use mbuzz or similar tools that support time-decay with configurable half-life.

### 2. Build in Your Data Warehouse

Export data to BigQuery/Snowflake and implement time-decay:

```sql
WITH touchpoints_weighted AS (
  SELECT
    user_id,
    conversion_id,
    channel,
    conversion_value,
    touchpoint_time,
    conversion_time,
    -- Calculate weight using 7-day half-life
    POWER(2, -DATE_DIFF(conversion_time, touchpoint_time, DAY) / 7.0) as weight
  FROM touchpoint_data
),
normalized AS (
  SELECT
    *,
    weight / SUM(weight) OVER (PARTITION BY conversion_id) as credit
  FROM touchpoints_weighted
)
SELECT
  channel,
  SUM(credit * conversion_value) as attributed_revenue
FROM normalized
GROUP BY channel
ORDER BY attributed_revenue DESC;
```

## Implementing Time-Decay in mbuzz


mbuzz uses **AML (Attribution Modeling Language)** — a small Ruby DSL — to define how credit is distributed. The `time_decay` helper takes a `half_life` argument and normalizes credits to sum to 1.0 across all touchpoints in the window.

### Basic time-decay

```ruby
within_window 30.days
  time_decay half_life: 7.days
end
```

A 30-day lookback with credit halving every 7 days. The most recent touchpoint gets the highest weight; a touchpoint 7 days older gets half; 14 days older, a quarter; and so on.

### Tuning the half-life

Change the half-life to match your sales cycle:

```ruby
# E-commerce: fast decay
within_window 14.days
  time_decay half_life: 3.days
end

# B2B SaaS: slow decay, don't crush early touches
within_window 90.days
  time_decay half_life: 21.days
end
```

The full AML reference — including segment weights, conditional logic, and channel filtering — is at [docs/attribution-models](/docs/attribution-models).

## Tuning Time-Decay for Your Business

Time-decay has more levers than linear. Here's how to tune them.

### Half-Life by Business Type

| Business Type | Half-Life | Lookback | Why |
|---------------|-----------|----------|-----|
| **Flash sales / Urgency** | 1-2 days | 7 days | Decisions made fast |
| **Impulse e-commerce** | 3 days | 14 days | Short consideration |
| **Standard e-commerce** | 5-7 days | 30 days | Normal shopping cycle |
| **High-AOV retail** | 7-10 days | 45 days | More research time |
| **Low-cost SaaS** | 7 days | 30 days | Quick trial-to-buy |
| **Mid-market SaaS** | 14 days | 60 days | Sales involvement |
| **Enterprise B2B** | 21-30 days | 90+ days | Long cycles, don't crush early |

In AML, both levers are arguments: `within_window` for the lookback and `half_life:` on `time_decay`.

### Seasonal adjustments

Buying behavior compresses during high-intent periods. For BFCM week, run a parallel model with a 2-day half-life and a 7-day window — credit lands on the immediate pre-purchase touches. For the post-holiday gift card window, stretch the lookback to 45 days and the half-life to 10–14 days so original holiday campaigns still get credit when redemptions land in January.

### Campaign launch adjustments

For a launch attribution view, narrow the lookback and accelerate the decay so credit lands on the immediate pre-conversion touches:

```ruby
within_window 14.days
  time_decay half_life: 3.days
end
```

To restrict the model to a single launch campaign, or to vary half-life by conversion value, see the channel-filtering and conditional-logic patterns at [docs/attribution-models](/docs/attribution-models).

### Parameter Tuning Cheatsheet

| Scenario | Parameter Change | Why |
|----------|------------------|-----|
| **Faster conversions observed** | Shorter half-life (3-5d) | Match actual behavior |
| **Longer consideration observed** | Longer half-life (14-21d) | Don't crush early touches |
| **High urgency / sale period** | Very short half-life (1-2d) | Decisions made fast |
| **Post-holiday period** | Longer half-life (10-14d) | Gift cards, returns, delayed decisions |
| **New customer acquisition focus** | Longer half-life | Value awareness more |
| **Retention / repeat focus** | Shorter half-life | Recent re-engagement matters |
| **Early touches getting crushed** | Add min_credit_floor | Preserve some awareness credit |
| **Too much credit to old touches** | Shorter lookback window | Exclude irrelevant history |

## Summary

Time-decay attribution credits touchpoints based on recency—recent touches get more credit, older touches get less. It's a middle ground between last-touch (all credit to final touch) and linear (equal credit).

**Use time-decay when:**
- Short to medium sales cycles (< 30 days)
- E-commerce and retail where recency matters
- You want last-touch's emphasis without ignoring the journey
- Products with urgency or seasonality

**Don't use time-decay when:**
- Long B2B sales cycles (it crushes early-touch credit)
- First-touch genuinely matters for sourcing
- Content-heavy journeys where early education matters

**Best practice:** Start with a 7-day half-life, then adjust based on your conversion cycle. Validate with incrementality tests to confirm recency actually correlates with influence.

## Further Reading

**On Attribution Models:**
- [Linear Attribution](/articles/linear-attribution) — The neutral baseline
- [Position-Based Attribution](/articles/position-based-attribution) — Emphasize first and last
- [How to Choose the Right Attribution Model](/articles/how-to-choose-attribution-model) — Decision framework

**On Validation:**
- [MTA vs MMM](/articles/mta-vs-mmm) — Where attribution fits in the measurement stack
- [Triangulating Measurement Methods](/articles/mta-mmm-incrementality-triangulation) — Validating with multiple approaches

## Key takeaways

- Time-decay credits all touchpoints, but weights recent touches more heavily
- The half-life parameter controls how quickly credit decays (7 days is common)
- Best for e-commerce and short-to-medium sales cycles where recency matters
- Less extreme than last-touch, but still under-credits early awareness


## FAQ

**What is time-decay attribution?**

Time-decay attribution is a multi-touch model that distributes credit based on how close each touchpoint was to the conversion. Recent touchpoints get more credit; older touchpoints get less. The decay follows an exponential curve controlled by a half-life parameter.

**What is a good half-life for time-decay?**

7 days is the most common default. For e-commerce with fast purchase cycles, 3-5 days may work better. For B2B or considered purchases, 14-30 days gives more credit to the full journey. Match your half-life to your typical time-to-conversion.

**Is time-decay better than linear?**

It depends on your business. Time-decay is better when recent touches genuinely influence purchase decisions more (e-commerce, urgency products). Linear is better when early-funnel touches are equally important (B2B, long cycles). Neither is universally 'better.'

**Does GA4 support time-decay attribution?**

No. GA4 removed time-decay attribution in 2023 along with linear and position-based. Only last-click and data-driven remain. Use a third-party tool or build your own model to use time-decay.

**How does time-decay differ from last-touch?**

Last-touch gives 100% to the final touchpoint; time-decay distributes across all touchpoints but weights recent ones more. Time-decay is less extreme—early touches still get some credit, just less than recent ones.


