Skip to main content

Mission Control Revenue Tracking & Attribution Analysis

Date: February 26, 2026 Subject: Qalo Revenue Discrepancy Investigation & System Documentation Discrepancy: Revenue Comparison (298,940.03)vsExecutiveSummary(298,940.03) vs Executive Summary (255,871.60) = $43,068.43

Table of Contents

  1. Executive Summary
  2. How Pixel Tracked Revenue Works
  3. Revenue Comparison vs Executive Summary
  4. Attribution Models Explained
  5. UTM Parameter Analysis
  6. Current Issues & Root Causes
  7. Recommended Fixes

Executive Summary

Key Findings

The $43K discrepancy is caused by:
  1. Different Data Sources:
    • Revenue Comparison uses interaction_insight_summary (attribution data with overcounting)
    • Executive Summary uses shopify_daily_summary (Shopify aggregation, may have sync issues)
  2. Any-Click Attribution Overcounting:
    • Revenue Comparison uses “Any Click” attribution by default
    • Every touchpoint gets 100% credit -> same order counted multiple times
    • Example: 100orderwith3touchpoints=100 order with 3 touchpoints = 300 in Revenue Comparison
  3. Potential Data Sync Issues:
    • shopify_daily_summary table may be missing days or have stale data
    • Executive Summary may understate revenue if daily sync fails

How Pixel Tracked Revenue Works

Q: How is pixel tracked revenue defined?

Answer: Pixel tracked revenue is defined as revenue from orders that have at least one marketing touchpoint tracked by the Mission Control pixel. Technical Implementation: File: eventapp/management/commands/process_ordcredit.py:61-81
File: eventapp/management/commands/process_data.py:1540-1562
File: eventapp/management/commands/process_ordcredit.py:93-115
Result: Orders appear in eventapp_ordercredit -> aggregated into interaction_insight_summary -> displayed as “pixel tracked revenue”

Q: Does pixel revenue match with Shopify? Are untracked orders represented?

Answer: Pixel revenue SHOULD match Shopify, but currently DOES NOT due to:

1. Untracked Orders (No Pixel Touchpoints)

Current Behavior:
  • Orders with NO marketing touchpoints = excluded from attribution reports
  • These orders are in orders table but NOT in eventapp_ordercredit
  • Example: Direct orders from repeat customers who bookmarked the site
File: interaction_insight/selectors.py:1897
Evidence:
Impact: Mission Control underreports total revenue in attribution views (but Executive Summary should show all Shopify revenue).

2. Shopify Daily Summary Table Issues

Current Implementation: File: custom_reports/models.py:46
File: sales_performance/selectors.py:39-40
Problem: The table name is inconsistent:
  • Model uses: shopify_daily_summary
  • Actual table: shopify_daily_data (confirmed by database schema check)
  • This may cause queries to fail or return stale data

Q: Should the pixel track ALL Shopify revenue regardless of source?

Answer: YES, it should, but currently it doesn’t. Current Behavior:
  • YES Pixel tracks transaction events regardless of source
  • YES Orders are synced from Shopify API (all orders)
  • NO Attribution only includes orders with media_source touchpoints
  • NO Direct orders without prior pixel sessions = excluded from attribution
File: eventapp/management/commands/process_ordcredit.py:61
Recommendation: Add a fallback attribution for untracked orders:
  • If no touchpoints found, attribute to “Direct” with credit_score = 1.0
  • This ensures 100% of Shopify revenue is represented in Mission Control

Revenue Comparison vs Executive Summary

Revenue Comparison Page ($298,940.03)

URL: https://app.lunarmc.ai/revenue-comparison Backend Flow:
  1. interaction_insight/views.py:8273 -> RevenuesDashboardGraph.get()
  2. Line 8307: Sets attribution = 'Any Click' (hardcoded!)
  3. Calls NewOrderDetailsChannelData -> OrderDetailsSource
  4. Executes query with SUM(any_click_revenue)/100
Exact Query: File: interaction_insight/selectors.py:1897
Why it’s higher ($298K):
  • Uses Any-Click attribution -> every touchpoint gets 100% credit
  • Example journey: Google Ads -> Email -> Facebook Ads -> Purchase ($100)
    • Google Ads: +$100
    • Email: +$100
    • Facebook Ads: +$100
    • Total: $300 (3x overcounting)

Executive Summary Gross Sales ($255,871.60)

URL: https://app.lunarmc.ai/sales-performance Backend Flow:
  1. sales_performance/views.py:87 -> SalesDashboard.get()
  2. Calls GetTotalShopifySalesData + GetSalesDashboardData
  3. Merges results and displays “Gross Sales” card
Exact Query: File: sales_performance/selectors.py:15-21
File: sales_performance/selectors.py:39-40
Why it’s lower ($255K):
  • Uses Shopify aggregation -> each order counted once
  • May be missing data if shopify_daily_summary table has sync issues
  • Should match Shopify Admin (but might be understated if days are missing)

Attribution Models Explained

Q: What is the attribution model for L5 Pixel?

Answer: Mission Control supports FOUR attribution models with a 30-day attribution window (configurable).

1. Any-Click Attribution

How it works: Every touchpoint gets 100% credit. File: eventapp/management/commands/process_ordcredit.py:119-146
File: interaction_insight/selectors.py:1897
Example:
  • Order: $100
  • Touchpoints: Google Ads, Email, Facebook Ads
  • Each gets: $100
  • Total shown: $300 YES (intentional overcounting)
Use Case: Understanding total marketing contribution (all channels that touched the order)

2. First-Click Attribution

How it works: Only the first touchpoint gets 100% credit. File: interaction_insight/selectors.py:1891
File: sales_performance/views.py:204-217 (ProcessInsightSummary.py aggregation)
Example:
  • Touchpoints: Google Ads (2/1) -> Email (2/8) -> Facebook Ads (2/20)
  • Google Ads gets: $100
  • Email gets: $0
  • Facebook Ads gets: $0

3. Last-Click Attribution

How it works: Only the last touchpoint gets 100% credit. File: interaction_insight/selectors.py:1893
File: interaction_insight/management/commands/ProcessInsightSummary.py:219-232
Example:
  • Touchpoints: Google Ads (2/1) -> Email (2/8) -> Facebook Ads (2/20)
  • Google Ads gets: $0
  • Email gets: $0
  • Facebook Ads gets: $100

4. Linear (Equal Weight) Attribution

How it works: Credit is split evenly across all non-excluded touchpoints. File: eventapp/management/commands/process_ordcredit.py:119-146
File: interaction_insight/selectors.py:1895
File: interaction_insight/management/commands/ProcessInsightSummary.py:234-242
Example:
  • Order: $100
  • Touchpoints: Google Ads, Email, Facebook Ads (3 total)
  • Each gets: $33.33 (credit_score = 0.333)
  • Total shown: $100 YES

Attribution Window

File: eventapp/management/commands/process_ordcredit.py:43-49
File: eventapp/management/commands/process_ordcredit.py:61-68
Configuration:
  • Default: 30 days lookback
  • Configurable per client via client.attr_lookup field
  • NOT lifetime: Only looks back X days before purchase
Note: “Direct” touchpoints are excluded from credit distribution unless they’re the ONLY touchpoint.

UTM Parameter Analysis

Current Mission Control Parameters

Reference: Mission Control UTM Guide Example (Facebook Ads):
File: eventapp/models/identity.py:123-132 (MediaAttRule matching)

Q: Why do we need all these parameters?

Current Parameter Breakdown:

Redundancy Analysis

1. l5s=fb is Redundant

Current Usage:
Why it’s redundant:
  • l5ss={{site_source_name}} already contains platform info
  • Facebook’s macro {{site_source_name}} returns values like:
    • “fb” (mobile app)
    • “ig” (Instagram)
    • “facebook” (desktop)
    • “instagram” (explicit)
Recommendation: NO Remove l5s parameter
  • Rely solely on l5ss for platform identification
  • Update MediaAttRule to match on l5ss patterns instead

2. l5m=social is Redundant

Current Usage:
Why it’s redundant:
  • Media type can be inferred from l5s or l5ss:
    • fb, ig, tiktok, snapchat -> Social
    • google, bing -> Search
    • email, klaviyo -> Email
File: interaction_insight/selectors.py:1901-1902
Recommendation: NO Remove l5m parameter
  • Calculate media_type server-side based on media_source
  • Create a mapping table:

3. l5p={{placement}} May Be Useful

Current Usage:
  • Stored but not displayed in standard reports
  • Could be used for:
    • Facebook Placements: Feed, Stories, Reels, Marketplace, etc.
    • Google Placements: Search, Display Network, YouTube, etc.
File: eventapp/models/identity.py
Check if used:
Recommendation: WARNING Keep if used in custom reports, otherwise remove
  • Check with clients if they use placement data
  • If not used, remove to simplify URL structure

Simplified Parameter Structure

Recommended Minimal Parameters:
Mapping:
  • l5ss -> media_source (via MediaAttRule)
  • l5adid -> mkt_content (ad identifier)
  • l5cid -> campaign_id (for ad platform sync)
  • l5c -> mkt_campaign (campaign name)
Benefits:
  • YES Cleaner URLs
  • YES Less client configuration
  • YES Easier troubleshooting
  • YES Maintains full tracking capability

Q: When can clients use L5 UTM vs standard UTM?

Answer: Clients can use EITHER L5 parameters OR standard UTM parameters (or both). Current Implementation: File: eventapp/models/identity.py:123-132 (MediaAttRule)
Precedence:
  1. L5 parameters checked first
  2. If not found, fall back to standard UTM
  3. Allows clients to use existing UTM structure
Example - Both work:
Recommendation:
  • New clients: Use L5 parameters (cleaner, more specific)
  • Existing clients with UTM: Can keep using UTM (backward compatible)
  • Migration path: Add MediaAttRule entries that map standard UTM to media_source
Example MediaAttRule Configuration:

Current Issues & Root Causes

Issue 1: Revenue Comparison Page Shows Inflated Numbers

Root Cause: Hardcoded “Any Click” attribution File: interaction_insight/views.py:8307
Impact:
  • Users see 298Kwhenactualrevenueis298K when actual revenue is 255K
  • 17% overstatement due to multi-touch attribution
  • Confusing when compared to Shopify Admin
Evidence:

Issue 2: Executive Summary Gross Sales May Be Understated

Root Cause: Table name mismatch + potential sync issues File: custom_reports/models.py:46
Database Evidence:
Impact:
  • Query may fail silently
  • Returns stale data or zeros
  • Executive Summary shows lower revenue than actual

Issue 3: MC ROAS and MC CPA Are Redundant

Current Implementation: File: sales_performance/views.py:190-192
What they measure:
  • MC ROAS: pixel_tracked_revenue / ad_spend
  • MC CPA: ad_spend / pixel_tracked_orders
Why they’re redundant: File: sales_performance/views.py:179 (MER calculation)
File: sales_performance/views.py:185 (CAC calculation)
Comparison: Problem:
  • If pixel tracks 90% of orders -> MC ROAS understated by 10%
  • MER is more accurate (uses all Shopify revenue)
  • Showing both metrics is confusing
Recommendation: NO Remove MC ROAS and MC CPA
  • MER and CAC already provide these insights
  • MER is more accurate (includes all revenue)
  • Reduces dashboard clutter

Issue 4: Untracked Orders Excluded from Attribution

Root Cause: Orders without page views are not attributed File: eventapp/management/commands/process_ordcredit.py:61
Scenario:
  1. Customer bookmarks site -> direct to checkout
  2. No page_view events captured
  3. Order completes but has NO touchpoints
  4. Excluded from eventapp_ordercredit table
  5. Missing from attribution reports
Impact:
  • ~5-10% of orders typically have no touchpoints
  • These orders don’t appear in Revenue Comparison or Channel Performance
  • Attribution totals understate true performance
File: interaction_insight/selectors.py:1897

Fix 1: Change Revenue Comparison Default Attribution

Problem: Revenue Comparison hardcodes “Any Click” attribution, causing overcounting. Current Code: File: interaction_insight/views.py:8307
Recommended Fix:
Impact:
  • Revenue Comparison will show 255Kinsteadof255K instead of 298K
  • Matches Executive Summary and Shopify Admin
  • Still allows users to select “Any Click” if desired
Implementation:

Fix 2: Fix Shopify Daily Summary Table Name

Problem: Model points to wrong table name. Current Code: File: custom_reports/models.py:46
Recommended Fix: Option A: Rename the Model (Recommended)
Then run migration:
Option B: Create a View Alias (Quick Fix)
Impact:
  • Executive Summary will pull from correct table
  • Gross Sales will match Shopify Admin
  • Eliminates potential for stale data

Fix 3: Remove MC ROAS and MC CPA from Executive Summary

Problem: Redundant metrics that confuse users. Current Code: File: sales_performance/views.py:190-192
Recommended Fix:
Rationale:
  • MER includes ALL Shopify revenue (more accurate than MC ROAS)
  • CAC is the standard industry metric (CPA is confusing)
  • Pixel tracking coverage is < 100%, so MC metrics understate performance
  • Showing both sets creates confusion about which to trust
Impact:
  • Cleaner dashboard with 2 fewer cards
  • Users see one source of truth (MER) instead of conflicting ROAS values
  • Aligns with industry standards (CAC is standard, not CPA)

Fix 4: Attribute Untracked Orders to “Direct”

Problem: Orders without touchpoints are excluded from attribution. Current Code: File: eventapp/management/commands/process_ordcredit.py:61-81
Recommended Fix:
Impact:
  • 100% of Shopify orders now appear in attribution reports
  • “Direct” channel will show true untracked revenue
  • Revenue Comparison total will match Shopify Admin

Fix 5: Simplify L5 UTM Parameters

Problem: Redundant parameters (l5s, l5m) clutter URLs. Current Parameters:
Recommended Parameters:
Migration Steps:
  1. Update MediaAttRule to match on l5ss only:
  1. Calculate media_type server-side:
File: eventapp/models/identity.py (add method)
  1. Update URL templates:
Impact:
  • 40% shorter URLs
  • Easier client setup (fewer parameters to configure)
  • Maintains full tracking capability
  • Backward compatible (old URLs still work)

Fix 6: Add Revenue Reconciliation Report

Problem: No easy way to see why numbers don’t match. Recommended: Create a new “Revenue Reconciliation” page that shows:
Query for this report:


Implementation Plan

Phase 1: Critical Fixes (Week 1)

  1. Fix Revenue Comparison attribution default
    • File: interaction_insight/views.py:8307
    • Change: 'Any Click' -> 'Last Click'
    • Test: Verify Revenue Comparison shows ~$255K
  2. Fix table name in model
    • File: custom_reports/models.py:46
    • Change: 'shopify_daily_summary' -> 'shopify_daily_data'
    • Run: python manage.py migrate
  3. Remove MC ROAS and MC CPA
    • File: sales_performance/views.py:190-192
    • Remove: Lines that add MC ROAS and MC CPA cards
    • Test: Verify Executive Summary shows only MER and CAC

Phase 2: Attribution Improvements (Week 2-3)

  1. Attribute untracked orders to Direct
    • File: eventapp/management/commands/process_ordcredit.py:81
    • Add: Fallback Direct attribution logic
    • Test: Verify 100% of orders appear in attribution
  2. Add attribution model selector to Revenue Comparison
    • File: Frontend component
    • Add: Dropdown to select First/Last/Any/Linear
    • Default: Last Click

Phase 3: UTM Simplification (Week 4)

  1. Simplify L5 parameters
    • Update: MediaAttRule configuration
    • Remove: Dependencies on l5s and l5m
    • Document: New parameter structure for clients
  2. Create reconciliation report
    • New: /revenue-reconciliation page
    • Shows: All revenue sources side-by-side
    • Explains: Why numbers differ

Testing Checklist

  • Revenue Comparison matches Executive Summary (±$1K)
  • Executive Summary Gross Sales matches Shopify Admin
  • All orders from Shopify appear in attribution (check untracked count = 0)
  • MC ROAS and MC CPA cards removed from dashboard
  • Simplified L5 parameters work for all ad platforms
  • Reconciliation report shows correct breakdowns
  • Performance: Queries run in < 2 seconds

Appendix: SQL Queries for Verification

Query 1: Check for Table Mismatch

Query 2: Compare All Revenue Sources

Query 3: Find Untracked Orders

Query 4: Verify Daily Summary Completeness


Document Version: 1.0 Last Updated: February 26, 2026 Author: Mission Control Engineering Team