How to replicate the Model Comparison Tool report from Google Analytics to Google BigQuery

Viewed 201

I have the following report in the demo account of Google Analytics:

https://analytics.google.com/analytics/web/?utm_source=demoaccount&utm_medium=demoaccount&utm_campaign=demoaccount#/report/bf-roi-calculator/a54516992w87479473p92320289/_u.date00=20211101&_u.date01=20211128&_r.attrSel2=preset6&_r.attrSel1=preset1&_r.attrSel3=preset7/

In this report, we can see the different models of conversion attribution, e.g. Last Interaction, Last Non-Direct Click, and Last Google Ads Click. There are also other models, like First Interaction, Position based. Here's Google's documentation about the multi-channel funnels report:

https://support.google.com/analytics/topic/1191164?hl=en&ref_topic=1631741

So far, I have managed to build the following query:

-- Sessions with source/medium, hits, and page path
WITH table_1 AS (
    SELECT 
        fullVisitorId, 
        visitStartTime,
        CONCAT(fullVisitorId, visitId, date) AS session,
        trafficSource.medium, 
        trafficSource.source,
        ANY_VALUE(social.hasSocialSourceReferral) AS social_source_referral,
        trafficSource.campaign,
        ARRAY_AGG(hitNumber ORDER BY hitNumber) AS hit_number,
        ARRAY_AGG(page.pagePath ORDER BY hitNumber) AS page_path
    FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits_
    WHERE _TABLE_SUFFIX BETWEEN '20170727' AND '20170801'
    GROUP BY fullVisitorId, visitStartTime, session, medium, source, campaign),

-- Adding the MCF channel grouping and creating a field that indicates sessions with conversions
table_2 AS (
    SELECT 
        fullVisitorId,
        visitStartTime,
        CASE 
            WHEN source = '(direct)' AND (medium = '(not set)' OR medium = '(none)') THEN 'Direct'
            WHEN medium = 'organic' THEN 'Organic Search'
            WHEN social_source_referral = 'Yes' AND REGEXP_CONTAINS(medium, r'^(social|social-network|social-media|sm|social network|social media)$') THEN 'Social'
            WHEN medium = 'email' THEN 'Email'
            WHEN medium = 'affiliate' THEN 'Affiliate'
            WHEN medium = 'referral' THEN 'Referral'
            WHEN REGEXP_CONTAINS(medium, r'^(cpc|ppc|paidsearch)$') THEN 'Paid Search'
            WHEN REGEXP_CONTAINS(medium, r'^(cpv|cpa|cpp|content-text)$') THEN 'Other Advertising'
            WHEN REGEXP_CONTAINS(medium, r'^(display|cpm|banner)$') THEN 'Display'
            ELSE 'Other' 
        END AS mcf_channel_grouping,
        medium,
        source,
        campaign,
        CAST(
            EXISTS(
                SELECT * 
                FROM UNNEST(page_path) AS x 
                WHERE REGEXP_CONTAINS(x, r'^/ordercompleted\.html')
                ) 
            AS INT64
            ) AS conversion
    FROM table_1 
    ORDER BY fullVisitorId
    ),

-- Filtering by sessions with conversions
table_3 AS (
    SELECT *
    FROM table_2
    WHERE TRUE 
    QUALIFY COUNTIF(conversion = 1) OVER (PARTITION BY fullVisitorId) > 0
    ),

-- Adding the attribution models
table_4 AS (
    SELECT 
        fullVisitorId, 
        DATE(TIMESTAMP_SECONDS(visitStartTime)) AS date,
        visitStartTime AS date_sec, 
        mcf_channel_grouping,
        medium, 
        source, 
        campaign, 
        conversion,
        CASE
            WHEN conversion > 0 AND visitStartTime > LAG(visitStartTime) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime) THEN '1'
            WHEN conversion > 0 AND visitStartTime = FIRST_VALUE(visitStartTime) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime) THEN '1'
            ELSE 'null' 
        END AS last_touch_attribution,
        CASE
            WHEN conversion > 0 AND visitStartTime = FIRST_VALUE(visitStartTime) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime) THEN '1'
            WHEN conversion = 0 AND visitStartTime = FIRST_VALUE(visitStartTime) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime) THEN 'null'
            WHEN conversion = 0 AND LAG(visitStartTime) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime) = FIRST_VALUE(visitStartTime) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime) THEN 'null'
            WHEN SUM(conversion) OVER (PARTITION BY fullVisitorId) > 0 AND visitStartTime < LAST_VALUE(visitStartTime) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
                AND LEAD(source) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime) = 'direct' AND source != 'direct' THEN '1'
            WHEN conversion > 0 AND visitStartTime = LAST_VALUE(visitStartTime) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AND source != 'direct' THEN '1'
            ELSE 'null' 
        END AS last_non_direct,
        CASE
            WHEN MAX(conversion) OVER (PARTITION BY fullVisitorId) = 1 AND visitStartTime = FIRST_VALUE(visitStartTime) OVER (PARTITION BY fullVisitorId ORDER BY visitStartTime) THEN '1'
            ELSE 'null' 
        END AS first_touch_attribution,
        CASE
            WHEN MAX(conversion) OVER (PARTITION BY fullVisitorId) = 1 THEN '1'
            ELSE 'null' 
        END AS any_touch_attribution,
        CASE
            WHEN MAX(conversion) OVER (PARTITION BY fullVisitorId) = 1 AND source = 'blog' THEN '1'
            ELSE 'null' 
        END AS blog_only
    FROM table_3
    ORDER BY fullVisitorId, visitStartTime
    )

SELECT * 
FROM table_4

The issue I have is that the Last Non-Direct model is not calculated correctly and I don't know how to create the look-back window that allows me to set n days prior to conversion.

How could we replicate this report in BigQuery using Standard SQL? Thanks.

0 Answers
Related