Skip to content

Marketing

A digital-marketing performance warehouse spanning paid, organic, and email channels. Campaigns run across channels and target audience segments. Spend gets a CDC audit (attribution restated as conversion windows close). A subset of awareness campaigns is on an A/B treatment targeted at conversion rate specifically (per-metric lift). Seasonality follows the Q4 holiday window.

What it produces

Table Type Grain Rows (default) Notes
dim_date dim per_period 24 24 monthly periods, Jan 2023 – Dec 2024
dim_campaign dim per_entity (+ SCD2) 95–285 95 campaigns, expanded by SCD2 campaign-phase moves
dim_audience dim per_reference 6 lookalike, prospecting, retargeting, ...
dim_creative_format dim per_reference 6 video, static_image, carousel, story, native, collection
fct_campaign_performance fact per_entity_per_period (CDC) 2,280 spend, impressions, CTR, creative quality
fct_funnel fact per_entity_per_period 2,280 conversion, bounce, leads + funnel-stage bucket
fct_revenue fact per_entity_per_period 2,280 revenue, ROI
evt_click event variable (proportional) ~18,000 scaled 8× click_through_rate
evt_campaign_pause event variable (threshold) 10–40 conversion_rate below 0.1 for 3 consecutive periods

95 entities across seven segments: awareness_builder (15, half in a per-metric treatment cohort), paid_burst (18), seasonal_promo (20), delayed_breakthrough (12), viral_compound (10), end_of_life (10), retarget_revival (10).

Features exercised

  • Per-metric treatmentawareness_builder segment 50/50 split. Treatment arm runs a new audience-targeting model at period 8 with target_metric: conversion_rate. Only conversion_rate shifts; every other metric stays byte-identical to control draws.
  • Seasonality — Q4 holiday lift Nov–Dec (+0.45), summer slowdown Jun–Aug (-0.10), post-holiday January dip (-0.25). Larger holiday lift than other templates — marketing is the most seasonally amplified domain.
  • Causal lagleads_generated follows impressions with delay 1.
  • Correlationsclick_through_rate driven_by impressions, conversion_rate driven_by click_through_rate, bounce_rate opposes conversion_rate, plus explicit revenue 0.62 conversion_rate, roi 0.48 revenue, leads_generated related click_through_rate. This produces a coherent funnel — impressions move CTR moves conversions moves revenue.
  • SCD2campaign_phase on dim_campaign tracking revenue with thresholds [0.30, 0.70] (seed / scale / mature).
  • CDCfct_campaign_performance carries audit columns for attribution-window-close spend restatements.
  • Bucket columnfunnel_stage on fct_funnel with four bands: cold / warming / engaged / converted.
  • Pool-driven event reasonevt_campaign_pause.reason is a pool.pause_reason column, so each campaign's pause reasons stay consistent with its segment's pool.
  • Multi-phase archetypesgrowth > spike_then_crash @ 12, flat > growth @ 10, decline > flat > growth @ 6 @ 16.
  • Lifecycle stageslaunch / ramping / performing / winning on conversion_rate.
  • Quality injection — null injection on ad_spend (4%), late arrivals on clicks (3%), duplicate rows on funnel (1%).
  • Events — one proportional (evt_click) and one threshold (evt_campaign_pause, with below rather than above).

Use it

from plotsim import load_template, generate_tables, write_tables

config = load_template("marketing")
tables = generate_tables(config)
write_tables(tables, config, output_dir="./output")
plotsim template marketing -o marketing.yaml
plotsim run marketing.yaml -o ./output

Common customizations

Strengthen the Q4 seasonal lift

Default Q4 strength is +0.45. To model a Black-Friday-heavy retailer:

config = create(
    # ... other fields ...
    seasonality=[
        {"months": [11, 12], "strength":  0.80},  # bigger Q4 lift
        {"months": [6, 7, 8], "strength": -0.10},
        {"months": [1],       "strength": -0.25},
    ],
)
seasonality:
  - { months: [11, 12], strength:  0.80 }
  - { months: [6, 7, 8], strength: -0.10 }
  - { months: [1],       strength: -0.25 }

Use time-varying correlations instead of a static funnel

Default has constant connections across the window. To model a funnel that decouples after a tracking change at period 12:

config = create(
    # ... metrics, segments, etc. unchanged ...
    connections=[
        "conversion_rate driven_by click_through_rate",
        "revenue 0.62 conversion_rate",
    ],
    connection_phases=[
        {
            "start_period": 0,
            "end_period":   11,
            "connections":  ["conversion_rate driven_by click_through_rate"],
        },
        {
            "start_period": 12,
            "end_period":   23,
            "connections":  ["conversion_rate hints_at click_through_rate"],
        },
    ],
)
connections:
  - conversion_rate driven_by click_through_rate
  - "revenue 0.62 conversion_rate"

connection_phases:
  - start_period: 0
    end_period:   11
    connections:
      - conversion_rate driven_by click_through_rate
  - start_period: 12
    end_period:   23
    connections:
      - conversion_rate hints_at click_through_rate

Add a holdout for an ROI prediction model

Holdout combines cleanly with the template's quality issues — corrupted rows are sliced by date_key so both train and holdout carry their share of injections. You don't need to drop the quality block first:

config = create(
    # ... metrics, segments, etc. unchanged ...
    holdout={
        "target":  "roi",
        "periods": 3,        # last 3 months held out
    },
    # quality block from the template is preserved.
)
holdout:
  target:  roi
  periods: 3

# remove the quality: block

Where it shines

  • ATE recovery exercises — the per-metric treatment on awareness_builder is the cleanest teaching surface for "did your inference correctly identify which metric was treated?" The manifest's treatment_cohorts records the answer.
  • Funnel-decay decomposition — the seasonal_decomposition and regression_pairs_global manifest sections let students recover per-pair OLS coefficients against the engine's ground truth.
  • Marketing-mix modeling teaching — causal_lag plus decay_window on leads_generated reproduces adstock-style dynamics; the capability ships out of the box (see Connecting metrics to extend the template).