Marketing Leadgen

Marketing Leadgen

Agency9 data marts81 fields12 calculated fieldsView on GitHubVlad FlaksRus Obolonsky

Account6 fields2 relationshipsAd Spend8 fields1 relationshipCampaign9 fields4 relationshipsLead11 fields4 relationshipsOpportunities11 fields4 relationshipsStage Transitions6 fields1 relationshipTouchpoints10 fields2 relationshipsWeb Sessions9 fields2 relationships

Campaigns anchor a B2B demand-generation business, tying ad spend, web traffic and attribution to leads that move through pipeline stages to a closed deal, with accounts carrying the firmographics ABM depends on.

Hand this to your AI

Marketing reports leads, sales reports closed deals, and nobody can trace a campaign's spend to the pipeline it created.

Paste this into your AI assistant. It builds the Marketing Leadgen model's Data Marts in your data warehouse from your ad, web and CRM data, and shows which campaigns create pipeline and revenue once spend is counted.

The prompt

build the Marketing Leadgen model with its Campaign, Touchpoints and Opportunities Data Marts, then show me which channels and campaigns create the most pipeline and revenue once ad spend and attribution credit are counted

Overview

A B2B demand-generation and revenue-operations business modeled end to end — from ad spend and marketing campaigns, through web traffic and multi-touch attribution, to leads, sales opportunities and the pipeline stages that carry them to close. Campaigns anchor everything, paid and non-paid alike: every dollar of ad spend, every paid visit and every touch on the path to conversion ties back to a campaign, so channel performance can be traced from a click to a closed-won deal. Deals are won or lost at the account level, so Account carries the firmographics and the ABM target-list flag.

How this business is managed

  • Marketing — turns paid and organic traffic into marketing-qualified leads at a cost the business can sustain.
  • Sales — converts qualified leads into closed-won revenue, focused on the accounts most likely to buy.
  • Finance — makes sure ad spend is matched by the pipeline and revenue the business brings in.

Key metrics

Key Data Marts

  • Lead — every contact, with the dated milestones of its way through the funnel.
  • Opportunities — the deals, their size and their outcome.
  • Ad Spend — what each channel and campaign costs, day by day.
  • Touchpoints — the multi-touch credit behind every lead and deal.

Example Questions

  • Which channels and campaigns generate the most pipeline and revenue once ad spend, attribution credit and win rates are accounted for?
  • Where does the funnel leak most — awareness to lead, lead to MQL/SQL, or opportunity to close — and does that differ by channel?
  • Do target (ABM) accounts convert, close and win at a higher rate than the rest of the book?

Explore on canvas →

Relevant Data Sources

Account Data Mart

Account

One row per target company, the firmographic backbone the rest of the model hangs off. Every account carries an industry, an employee-count band and a region, plus a flag marking whether it sits on the account-based marketing (ABM) target list. Because real B2B deals belong to accounts rather than to whichever individual filled out a form, this mart is the join point that lets leads, opportunities and touchpoints be rolled up to "who is this company, and how big an opportunity is it."

Fields

ColumnTypeAliasDescription
account_idSTRINGAccount IDPK. Unique identifier for the target company.
nameSTRINGNameCompany name.
industrySTRINGIndustryIndustry the company operates in.
employee_bandSTRINGEmployee BandCompany-size bucket — the mid-market segmentation axis. Vocabulary: 1-50 / 51-200 / 201-1000 / 1000+.
regionSTRINGRegionGeographic region of the company.
is_target_accountBOOLEANIs Target AccountWhether the company is on the ABM target list. ~10–20% of accounts, skewed toward larger employee_band; target accounts show higher engagement, pipeline and win rate.

Ad Spend Data Mart

Ad Spend

Daily cost, impressions and clicks for every paid campaign, broken out by ad group. This is the cost side of the funnel — the numbers a demand-gen team reconciles against Google Ads, LinkedIn Ads and other platform reports every week to know what a click, a lead and ultimately a closed deal actually costs.

Fields

ColumnTypeAliasDescription
spend_idSTRINGSpend IDPK. Unique identifier for each spend record.
spend_dateDATESpend DateDay the spend was incurred. Within the campaign's [start_date, end_date] flight.
campaign_idSTRINGCampaign IDCampaign this spend belongs to. FK to Campaign
channelSTRINGChannelMarketing channel where the cost was spent. Denormalized copy of the campaign's channel.
ad_groupSTRINGAd GroupAd group or ad set within the campaign.
impressionsINTEGERImpressionsNumber of times ads were shown.
clicksINTEGERClicksNumber of clicks the ads received. Always ≤ impressions; CTR by channel.
costNUMERICCostMoney spent on this ad group for the day (USD). Derived from clicks × per-channel CPC.
cpcFLOATCPC

Calculated Field. Cost per click, USD: summed cost over summed clicks, right at every cut — channel, campaign, ad group or week. Averaging a per-row CPC would weight a quiet day like a busy one and drop the days with no clicks.

SAFE_DIVIDE(SUM(cost), SUM(clicks))

Relationships

Related data martOnCardinalityMeaning
Campaigncampaign_id = campaign_idN:1The campaign this spend was bought for.

Campaign Data Mart

Campaign

Reference of every marketing initiative run — paid and non-paid alike, from search and social ads to email nurtures, webinars and content syndication — each carrying its channel, its objective and the UTM tags that tie it back to ad-platform and web-analytics data. This is the conformed campaign dimension of the model: every channel value that shows up on ad spend, web sessions, touchpoints or opportunities agrees with what is declared here, so a channel-level report never splits into phantom categories.

Fields

ColumnTypeAliasDescription
campaign_idSTRINGCampaign IDPK. Unique identifier for each campaign.
campaign_nameSTRINGCampaign NameHuman-readable name of the campaign.
channelSTRINGChannelMarketing channel. Controlled vocabulary: paid_search, paid_social, display, organic_search, email, webinar, content_syndication, direct, referral.
objectiveSTRINGObjectivePrimary goal. One of: awareness, lead_generation, conversion, retargeting.
utm_sourceSTRINGUTM SourceUTM source tag identifying where the traffic originates.
utm_mediumSTRINGUTM MediumUTM medium tag describing the type of traffic (e.g. cpc, email).
utm_campaignSTRINGUTM CampaignUTM campaign tag — the key ad-platform ↔ web-analytics join key.
start_dateDATEStart DateDate the campaign went live.
end_dateDATEEnd DateDate the campaign flight ended (nullable for always-on). Spend/touches fall within [start_date, end_date].

Campaign Performance Data Mart

Campaign Performance

One row per campaign per day, putting what the campaign cost next to what it produced: ad spend, impressions and clicks from Ad Spend, leads created from Touchpoints, and opportunities, pipeline and closed-won revenue from Opportunities. A row exists for every day the campaign spent money or produced a lead, an opportunity or a won deal, so leads from organic campaigns and from days with no spend are all here. This is the mart for cost per lead, cost per opportunity and pipeline per dollar of spend — one number at any date grain, campaign or channel. Each result is counted on its own day: spend on the day it was spent, a lead on the day it was created, an opportunity on the day it opened, revenue on the day the deal closed.

Fields

ColumnTypeAliasDescription
campaign_idSTRINGCampaign IDPK. Composite key together with activity_date. Campaign these daily totals belong to. FK to Campaign
activity_dateDATEActivity DatePK. Composite key together with campaign_id. Day the spend, leads, opportunities or won deals on this row happened.
channelSTRINGChannelMarketing channel of the campaign, copied from Campaign.channel. Only paid_search, paid_social and display carry spend.
costNUMERICCostAd spend on the campaign that day (USD), summed over its ad groups; 0 on days with no spend and for campaigns that never buy ads.
impressionsINTEGERImpressionsAd impressions the campaign bought that day; 0 without spend.
clicksINTEGERClicksAd clicks the campaign received that day; 0 without spend.
leads_createdINTEGERLeads CreatedLeads the campaign created that day, counted on the lead's creation date. Each lead counts once, under the campaign of its lead-creating touch.
opportunities_createdINTEGEROpportunities CreatedSales opportunities opened that day with this campaign as their primary campaign source.
pipeline_amountNUMERICPipeline CreatedDeal amount (USD) of the opportunities opened that day, whatever their outcome.
deals_wonINTEGERDeals WonOpportunities from this campaign won that day, counted on their close date.
won_revenueNUMERICClosed-Won RevenueDeal amount (USD) of the opportunities from this campaign won that day, counted on their close date.
cost_per_leadFLOATCost per Lead

Calculated Field. Ad spend per lead created, USD: summed cost over summed leads, right at any date grain, campaign or channel. A lead counts on the day it was created. Only paid search, paid social and display carry spend, so an organic channel reads $0 and display, with no leads, reads empty; across all channels it divides paid spend by every lead — filter to the paid channels for a paid cost per lead.

SAFE_DIVIDE(SUM(cost), SUM(leads_created))
cost_per_opportunityFLOATCost per Opportunity

Calculated Field. Ad spend per opportunity opened, USD: summed cost over summed opportunities, right at any date grain, campaign or channel. An opportunity counts on the day it opened, under its primary campaign source. Organic channels carry no spend and read $0; across all channels it divides paid spend by every opportunity, organic-sourced included.

SAFE_DIVIDE(SUM(cost), SUM(opportunities_created))
pipeline_per_dollarFLOATPipeline per $ of Spend

Calculated Field. Pipeline created per $1 of ad spend: summed deal amount of opportunities opened over summed cost. Pipeline counts on the day the opportunity opened, whatever its outcome. Organic channels have pipeline but no spend and read empty; across all channels it credits organic pipeline to paid spend.

SAFE_DIVIDE(SUM(pipeline_amount), SUM(cost))

Relationships

Related data martOnCardinalityMeaning
Campaigncampaign_id = campaign_idN:1The campaign these daily totals belong to.

Lead Data Mart

Lead

One row per lead or contact captured by marketing, carrying where they came from, their fit-and-engagement score, the dated milestones marking when they became marketing-qualified (MQL) and sales-qualified (SQL), and firmographics that mirror the account they belong to. Because the qualification milestones are dated rather than just a current-state label, leads can be grouped into cohorts — "leads created in March" — and tracked through the funnel over time, not just counted at a single point.

Fields

ColumnTypeAliasDescription
lead_idSTRINGLead IDPK. Unique identifier for each lead or contact.
account_idSTRINGAccount IDCompany the lead belongs to; null for a lead not yet matched to an account. FK to Account
created_atTIMESTAMPCreated AtWhen the lead first entered the system (coincides with the is_lead_create touchpoint).
source_channelSTRINGSource ChannelChannel that first brought in the lead. Equals the channel of the lead's is_lead_create touchpoint. Same controlled vocabulary as Campaign.channel.
lead_scoreINTEGERLead ScoreFit + engagement score for MQL gating.
became_mql_atTIMESTAMPBecame MQL AtWhen the lead reached marketing-qualified status; null if never MQL. created_at ≤ became_mql_at.
became_sql_atTIMESTAMPBecame SQL AtWhen the lead reached sales-qualified status; null if never SQL. became_mql_at ≤ became_sql_at.
employee_bandSTRINGEmployee BandCompany-size bucket. Same vocabulary as Account.employee_band: 1-50 / 51-200 / 201-1000 / 1000+. For matched leads, agrees with the account.
industrySTRINGIndustryIndustry the lead's company operates in. For matched leads, agrees with the account.
countrySTRINGCountryCountry where the lead is located; consistent with the account's region.
lifecycle_stageSTRINGLifecycle Stagesubscriber / lead / MQL / SQL / opportunity / customer. Consistent with the became_*_at timestamps and with the existence of an Opportunities row.
mqlsINTEGERMQLs

Calculated Field. Leads that reached marketing-qualified status, counted once each. Cut by Became MQL At for MQLs per month; by Created At to follow a lead cohort.

COUNTIF(became_mql_at IS NOT NULL)
sqlsINTEGERSQLs

Calculated Field. Leads that reached sales-qualified status, counted once each; every SQL was an MQL first. Cut by Became SQL At for SQLs per month.

COUNTIF(became_sql_at IS NOT NULL)
lead_to_mql_rateFLOATLead-to-MQL Rate

Calculated Field. Share of leads that became MQLs, per lead created. Cut by Created At, never by Became MQL At (that keeps only MQLs and reads 100%). Leads of the last two months are still qualifying.

SAFE_DIVIDE(mqls, COUNT(lead_id))
mql_to_sql_rateFLOATMQL-to-SQL Rate

Calculated Field. Share of MQLs that became SQLs, per MQL. Reads MQLs and SQLs, so the three always agree. Cut by Became MQL At or Created At; MQLs of the last two months are still being worked.

SAFE_DIVIDE(sqls, mqls)
sql_to_opp_rateFLOATSQL-to-Opportunity Rate

Calculated Field. Share of SQLs that became opportunities, per SQL; a lead at opportunity or customer stage counts. Reads SQLs. Cut by Became SQL At or Created At; SQLs of the last month are still converting.

SAFE_DIVIDE(COUNTIF(lifecycle_stage IN ('opportunity', 'customer')), sqls)

Relationships

Related data martOnCardinalityMeaning
Accountaccount_id = account_idN:1The company the lead works for.

Opportunities Data Mart

Opportunities

One row per sales opportunity — the deal object, keyed to the account rather than a single lead, since real B2B buying committees involve multiple people. Each row carries the pipeline stage, the deal size (ACV), the sourcing lead and campaign, and the win/loss outcome with close date and sales-cycle length. Each deal's path through the stages is recorded in Stage Transitions. This is where marketing-sourced pipeline turns into — or fails to turn into — closed revenue.

Fields

ColumnTypeAliasDescription
opportunity_idSTRINGOpportunity IDPK. Unique identifier for each sales opportunity.
account_idSTRINGAccount IDAccount the deal belongs to — the primary spine. FK to Account
lead_idSTRINGLead IDSourcing/converting lead the opportunity originated from; nullable. FK to Lead
primary_campaign_idSTRINGPrimary Campaign IDPrimary Campaign Source (single-touch sourcing); nullable. Equals the campaign of the sourcing lead's is_lead_create touchpoint. FK to Campaign
created_atTIMESTAMPCreated AtWhen the opportunity was created.
stageSTRINGStageCurrent pipeline stage. One of: discovery, demo, proposal, negotiation, closed_won, closed_lost.
amountNUMERICAmountACV / deal size (USD). Correlates with the account's employee_band.
close_dateDATEClose DateDate the opportunity was won or lost; null while open.
is_wonBOOLEANIs WonTrue iff stage = closed_won (then close_date is set); false with a close_date means closed_lost.
sales_cycle_daysINTEGERSales Cycle DaysDATE_DIFF(close_date, created_at, DAY) for closed deals; null while open.
ownerSTRINGOwnerSales rep who owns the opportunity (drawn from a small stable roster).
opp_to_won_rateFLOATOpp-to-Won Rate

Calculated Field. Share of opportunities won, per opportunity created — open deals stay in the base. Cut by Created At for a cohort. About half of every cohort, old or new, is still open, so even old cohorts never mature. Not won ÷ closed.

SAFE_DIVIDE(COUNTIF(is_won), COUNT(opportunity_id))
won_revenueNUMERICClosed-Won Revenue

Calculated Field. Deal amount on won opportunities, USD, summed; open and lost deals add nothing. Cut by Close Date for bookings by month or quarter.

SUM(IF(is_won, amount, 0))
deal_size_bandSTRINGDeal Size Band

Calculated Field. Small (<$15K), Mid ($15-50K), Large ($50-100K) or Enterprise ($100K+), by deal amount. A row-level formula that behaves as a dimension: group and filter by it.

CASE WHEN amount < 15000 THEN 'Small (<$15K)' WHEN amount < 50000 THEN 'Mid ($15-50K)' WHEN amount < 100000 THEN 'Large ($50-100K)' WHEN amount >= 100000 THEN 'Enterprise ($100K+)' END

Relationships

Related data martOnCardinalityMeaning
Accountaccount_id = account_idN:1The company the deal is with.
Campaignprimary_campaign_id = campaign_idN:1The campaign credited with sourcing the deal.
Leadlead_id = lead_idN:1The lead the deal grew out of.

Stage Transitions Data Mart

Stage Transitions

One row per pipeline stage change for a sales opportunity, tracing each deal's path through discovery, demo, proposal and negotiation on the way to a win or a loss. The time spent in each stage before moving to the next is the raw material for bottleneck analysis — where deals get stuck, and for how long.

Fields

ColumnTypeAliasDescription
transition_idSTRINGTransition IDPK. Unique identifier for the stage change.
opportunity_idSTRINGOpportunity IDOpportunity that moved stage. FK to Opportunities
from_stageSTRINGFrom StageStage the opportunity left.
to_stageSTRINGTo StageStage the opportunity entered. Contiguous chain: to_stage of row n = from_stage of row n+1; the last to_stage equals Opportunities.stage.
transitioned_atTIMESTAMPTransitioned AtWhen the stage change happened. Within [Opportunities.created_at, close_date].
days_in_from_stageINTEGERDays In From StageDays spent in the previous stage — the velocity bottleneck driver. Sums (per opportunity) to the sales cycle for closed deals.

Relationships

Related data martOnCardinalityMeaning
Opportunitiesopportunity_id = opportunity_idN:1The deal that moved stage.

Touchpoints Data Mart

Touchpoints

One row per marketing touch a lead has on the way to becoming a customer, credited under a W-shaped multi-touch attribution model that splits credit 30% to the first touch, 30% to lead creation, 30% to opportunity creation and 10% across everything in between. This is the mart that answers "which channels and campaigns actually deserve credit," rather than crediting only the first click or the last one. Multiplied by the deal size in Opportunities, that credit becomes each channel's share of pipeline.

Fields

ColumnTypeAliasDescription
touchpoint_idSTRINGTouchpoint IDPK. Unique identifier for each marketing touch.
lead_idSTRINGLead IDLead that this touch belongs to. FK to Lead
campaign_idSTRINGCampaign IDCampaign associated with this touch. FK to Campaign
occurred_atTIMESTAMPOccurred AtWhen the touch happened.
channelSTRINGChannelChannel where the touch occurred. Equals the campaign's channel; same controlled vocabulary as Campaign.channel.
touch_typeSTRINGTouch TypeKind of interaction. One of: ad_click, form_fill, email_open, email_click, webinar_attend, content_download, demo_request. Consistent with channel (e.g. no email_open on paid_search).
touch_creditFLOATTouch CreditW-shaped credit for this touch. Sums to exactly 1.0 per lead: 30% first touch, 30% lead creation, 30% opportunity creation, 10% across middle touches.
is_first_touchBOOLEANIs First TouchTrue on the lead's earliest touch (exactly one per lead). W-shaped anchor.
is_lead_createBOOLEANIs Lead CreateTrue on the touch that created the lead (exactly one per lead; coincides with Lead.created_at). W-shaped anchor.
is_opp_createBOOLEANIs Opp CreateTrue on the touch that created the opportunity (at most one per lead; only for leads with an opportunity; coincides with Opportunities.created_at). W-shaped anchor.

Relationships

Related data martOnCardinalityMeaning
Campaigncampaign_id = campaign_idN:1The campaign that produced this touch.
Leadlead_id = lead_idN:1The lead who was touched.

Web Sessions Data Mart

Web Sessions

One row per web session, the very top of the funnel, before most visitors are ever identified as a lead. Each session records the traffic source and medium, the landing page, whether it converted into a form submission, and — for the small share of visitors identified through identity stitching — the lead that session belongs to. Because the overwhelming majority of B2B web traffic never converts or gets identified, most sessions carry no lead at all; the ones that do show exactly where anonymous traffic turns into a known contact.

Fields

ColumnTypeAliasDescription
session_idSTRINGSession IDPK. Unique identifier for the web session.
lead_idSTRINGLead IDKnown lead after identity stitching; null for never-identified visitors (the overwhelming majority). FK to Lead
started_atTIMESTAMPStarted AtWhen the session began.
campaign_idSTRINGCampaign IDCampaign that drove the session; null for organic/direct. FK to Campaign
sourceSTRINGSourceTraffic source that referred the session; consistent with the driving campaign's utm_source.
mediumSTRINGMediumMarketing medium (e.g. organic, cpc, email); consistent with the driving campaign's utm_medium.
landing_pageSTRINGLanding PageFirst page viewed in the session.
form_submitsINTEGERForm SubmitsNumber of forms submitted during the session. ≥ 1 when is_conversion is true.
is_conversionBOOLEANIs ConversionWhether the session produced a lead or demo request. Session→lead conversion ~1–3% overall, lowest on paid social.

Relationships

Related data martOnCardinalityMeaning
Campaigncampaign_id = campaign_idN:1The campaign that drove the visit.
Leadlead_id = lead_idN:1The lead this visit was later tied to.

Apply to your project

  1. 1

    Install the Import Model plugin

    One plugin, installed once, in your own OWOX workspace.

    Get the plugin →

  2. 2

    Import this model

    Point it at this bundle and it creates every data mart above, joins and all.

    Open the model →

  3. 3

    Plug in your data and destinations

    Connect your own sources and send the results where your team already works.

    Browse connectors →

4. Optional — customize as you wish. Rename a column, drop a mart, add your own: once it is imported it is yours, and nothing here syncs back.