├── explores ├── .gitkeep └── sessions.explore.lkml ├── views ├── .gitkeep ├── event_data_dimensions │ ├── .gitkeep │ ├── event_data_user_properties.view.lkml │ ├── items_data.view.lkml │ ├── goals.view.lkml │ ├── event_data_event_params.view.lkml │ ├── event_funnel.view.lkml │ ├── page_funnel.view.lkml │ ├── event_path.view.lkml │ └── page_data.view.lkml ├── audience_cohorts.view.lkml ├── user_previous_session.view.lkml ├── user_segment.view.lkml ├── bqml │ └── predictions.view.lkml └── events.view.lkml ├── attributes ├── .gitkeep ├── datagroups.lkml └── formats.lkml ├── dashboards ├── .gitkeep ├── event_funnel.dashboard.lookml ├── page_funnel.dashboard.lookml ├── campaign_impact.dashboard.lookml └── behavior.dashboard.lookml ├── manifest.lkml ├── models └── ga4.model.lkml ├── marketplace.json ├── LICENSE └── README.md /explores/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /attributes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dashboards/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/event_data_dimensions/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /attributes/datagroups.lkml: -------------------------------------------------------------------------------- 1 | # datagroup: bqml_datagroup { 2 | # #retrain model every week 3 | # sql_trigger: SELECT EXTRACT(week from CURRENT_DATE()) ;; 4 | # } 5 | -------------------------------------------------------------------------------- /attributes/formats.lkml: -------------------------------------------------------------------------------- 1 | named_value_format: hour_format { 2 | value_format: "[h]:mm:ss" 3 | } 4 | 5 | named_value_format: formatted_number { 6 | value_format:"[<1000]0;[<1000000]0.0,\"K\";0.0,,\"M\"" 7 | } 8 | -------------------------------------------------------------------------------- /manifest.lkml: -------------------------------------------------------------------------------- 1 | 2 | ## Connection Constants: 3 | constant: GA4_CONNECTION { 4 | value: "looker-demos" 5 | export: override_required 6 | } 7 | 8 | constant: GA4_SCHEMA { 9 | value: "adh-demo-data-review.analytics_213025502" 10 | export: override_optional 11 | } 12 | 13 | constant: GA4_TABLE_VARIABLE { 14 | value: "events_*" 15 | export: override_optional 16 | } 17 | -------------------------------------------------------------------------------- /models/ga4.model.lkml: -------------------------------------------------------------------------------- 1 | connection: "@{GA4_CONNECTION}" 2 | 3 | label: "Google Analytics 4" 4 | 5 | include: "/dashboards/*.dashboard" 6 | include: "/explores/**/*.explore.lkml" 7 | 8 | datagroup: ga4_default_datagroup { 9 | sql_trigger: SELECT FLOOR(((TIMESTAMP_DIFF(CURRENT_TIMESTAMP(),'1970-01-01 00:00:00',SECOND)) - 60*60*6)/(60*60*24));; 10 | max_cache_age: "1 hour" 11 | } 12 | 13 | persist_with: ga4_default_datagroup 14 | -------------------------------------------------------------------------------- /marketplace.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Google Analytics 4 - Web Analytics", 3 | "category_label": "Models", 4 | "branding": { 5 | "image_uri": "https://marketplace-api.looker.com/block-icons/icon-google-analytics-new.png", 6 | "tagline": "Analyze and activate web-traffic data in BigQuery from GA4." 7 | }, 8 | "constants": { 9 | "GA4_CONNECTION": { 10 | "label": "Connection Name", 11 | "value_constraint": "connection" 12 | }, 13 | "GA4_SCHEMA": { 14 | "label": "GA4 Schema" 15 | }, 16 | "GA4_TABLE_VARIABLE": { 17 | "label": "GA4 Table Variable" 18 | } 19 | }, 20 | "models": [ 21 | { 22 | "name": "ga4", 23 | "connection_constant": "GA4_CONNECTION" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /views/audience_cohorts.view.lkml: -------------------------------------------------------------------------------- 1 | view: audience_cohorts { 2 | derived_table: { 3 | explore_source: sessions { 4 | column: audience_trait {} 5 | column: total_sessions {} 6 | derived_column: rank { 7 | sql: ROW_NUMBER() OVER() ;; 8 | } 9 | 10 | bind_all_filters: yes 11 | sorts: [sessions.total_sessions: desc] 12 | } 13 | } 14 | 15 | dimension: audience_trait { 16 | # Field used to JOIN back to ga_sessions via ga_sessions.audience_traits = audience_cohorts.audience_traits 17 | hidden: yes 18 | } 19 | 20 | dimension: rank { 21 | label: "Audience Trait: Rank by Traffic" 22 | view_label: "Audience" 23 | group_label: "Audience Cohorts" 24 | description: "Dynamic rank for Audience Trait based on web traffic (Sessions). Includes all filters in current query and reranks on each new query." 25 | type: number 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Google 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /explores/sessions.explore.lkml: -------------------------------------------------------------------------------- 1 | include: "/views/*.view.lkml" 2 | include: "/views/*/*.view.lkml" 3 | include: "/attributes/*.lkml" 4 | 5 | explore: sessions { 6 | label: "GA4 Sessions" 7 | description: "Explores Google Analytics sessions data." 8 | 9 | join: audience_cohorts { 10 | type: left_outer 11 | sql_on: ${sessions.audience_trait} = ${audience_cohorts.audience_trait} ;; 12 | relationship: many_to_one 13 | } 14 | 15 | join: events { 16 | view_label: "Events" 17 | sql: LEFT JOIN UNNEST(${sessions.event_data}) as events with offset as event_row ;; 18 | relationship: one_to_many 19 | } 20 | 21 | join: event_data_items { 22 | view_label: "Events" 23 | sql: LEFT JOIN UNNEST(${events.items}) as event_data_items ;; 24 | relationship: one_to_many 25 | required_joins: [events] 26 | } 27 | 28 | join: user_previous_session { 29 | view_label: "GA4 Sessions" 30 | sql_on: ${sessions.sl_key} = ${user_previous_session.sl_key} ;; 31 | relationship: one_to_one 32 | } 33 | 34 | join: user_segment { 35 | type: left_outer 36 | sql_on: ${sessions.user_pseudo_id} = ${user_segment.user_pseudo_id} ;; 37 | relationship: many_to_one 38 | } 39 | 40 | # join: future_purchase_prediction { 41 | # view_label: "BQML" 42 | # relationship: one_to_one 43 | # sql_on: ${sessions.sl_key} = ${future_purchase_prediction.sl_key} ;; 44 | # } 45 | } 46 | -------------------------------------------------------------------------------- /views/user_previous_session.view.lkml: -------------------------------------------------------------------------------- 1 | view: user_previous_session { 2 | derived_table: { 3 | explore_source: sessions { 4 | column: sl_key {} 5 | column: user_pseudo_id {} 6 | column: session_data_session_end_time {} 7 | column: session_data_session_start_time {} 8 | derived_column: prev_session_end_time { 9 | sql: lag(session_data_session_end_time) over (partition by user_pseudo_id order by session_data_session_start_time) ;; 10 | } 11 | } 12 | } 13 | dimension: sl_key { hidden:yes } 14 | dimension: session_data_session_start_time { hidden:yes } 15 | dimension_group: prev_session_end_time { 16 | hidden: yes 17 | type: time 18 | timeframes: [hour,date,week,year,raw] 19 | } 20 | dimension_group: since_previous_session { 21 | view_label: "Audience" 22 | group_label: "User" 23 | type: duration 24 | intervals: [hour,day] 25 | sql_start: ${prev_session_end_time_raw} ;; 26 | sql_end: ${session_data_session_start_time} ;; 27 | } 28 | dimension: days_since_previous_session_tier { 29 | view_label: "Audience" 30 | group_label: "User" 31 | description: "Days since the previous session. 0 if user only has 1 session." 32 | type: tier 33 | style: integer 34 | tiers: [1,2,4,8,15,31,61,121,365] 35 | sql: ${days_since_previous_session};; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /views/event_data_dimensions/event_data_user_properties.view.lkml: -------------------------------------------------------------------------------- 1 | view: event_data_user_properties { 2 | extension: required 3 | 4 | ## Dimensions 5 | dimension: user_property_age { 6 | group_label: "User Properties" 7 | label: "Age" 8 | type: string 9 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "age") ;; 10 | full_suggestions: yes 11 | } 12 | 13 | dimension: user_property_country { 14 | group_label: "User Properties" 15 | label: "Country" 16 | type: string 17 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "country") ;; 18 | full_suggestions: yes 19 | } 20 | 21 | dimension: user_property_device_category { 22 | group_label: "User Properties" 23 | label: "Device Category" 24 | type: string 25 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "device_category") ;; 26 | full_suggestions: yes 27 | } 28 | 29 | dimension: user_property_device_model { 30 | group_label: "User Properties" 31 | label: "Device Model" 32 | type: string 33 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "device_model") ;; 34 | full_suggestions: yes 35 | } 36 | 37 | dimension: user_property_gender { 38 | group_label: "User Properties" 39 | label: "Gender" 40 | type: string 41 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "gender") ;; 42 | full_suggestions: yes 43 | } 44 | 45 | dimension: user_property_interests { 46 | group_label: "User Properties" 47 | label: "Interests" 48 | type: string 49 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "interests") ;; 50 | full_suggestions: yes 51 | } 52 | 53 | dimension: user_property_language { 54 | group_label: "User Properties" 55 | label: "Language" 56 | type: string 57 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "language") ;; 58 | full_suggestions: yes 59 | } 60 | 61 | # dimension: key { 62 | # type: string 63 | # sql: ${TABLE}.key ;; 64 | # } 65 | 66 | # dimension: value__double_value { 67 | # type: number 68 | # sql: ${TABLE}.value.double_value ;; 69 | # group_label: "Value" 70 | # group_item_label: "Double Value" 71 | # } 72 | 73 | # dimension: value__float_value { 74 | # type: number 75 | # sql: ${TABLE}.value.float_value ;; 76 | # group_label: "Value" 77 | # group_item_label: "Float Value" 78 | # } 79 | 80 | # dimension: value__int_value { 81 | # type: number 82 | # sql: ${TABLE}.value.int_value ;; 83 | # group_label: "Value" 84 | # group_item_label: "Int Value" 85 | # } 86 | 87 | # dimension: value__set_timestamp_micros { 88 | # type: number 89 | # sql: ${TABLE}.value.set_timestamp_micros ;; 90 | # group_label: "Value" 91 | # group_item_label: "Set Timestamp Micros" 92 | # } 93 | 94 | # dimension: value__string_value { 95 | # type: string 96 | # sql: ${TABLE}.value.string_value ;; 97 | # group_label: "Value" 98 | # group_item_label: "String Value" 99 | # } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /views/user_segment.view.lkml: -------------------------------------------------------------------------------- 1 | view: user_segment_filters { 2 | extension: required 3 | filter: user_segment_timeframe { 4 | type: date 5 | } 6 | filter: user_segment_landing_page { 7 | type: string 8 | suggest_explore: sessions 9 | suggest_dimension: sessions.landing_page 10 | } 11 | } 12 | 13 | view: user_segment { 14 | derived_table: { 15 | #https://gafourblock.cloud.looker.com/explore/ga4/sessions?qid=TNJNii9UxKynCJltMZZ0iv&toggle=fil 16 | 17 | explore_source: sessions { 18 | column: user_pseudo_id {} 19 | column: total_sessions {} 20 | column: total_purchase_revenue { field: events.total_purchase_revenue } 21 | column: total_transactions { field: events.total_transactions } 22 | bind_filters: { 23 | from_field: user_segment.user_segment_timeframe 24 | to_field: sessions.session_date #bind filters to filter the table when the view is created 25 | } 26 | bind_filters: { 27 | from_field: user_segment.user_segment_landing_page 28 | to_field: sessions.landing_page 29 | } 30 | 31 | } 32 | } 33 | 34 | extends: [user_segment_filters] 35 | 36 | dimension: user_pseudo_id {hidden:yes primary_key:yes} 37 | dimension: total_sessions { 38 | hidden: yes 39 | label: "Sessions Sessions" 40 | description: "Total Number of Sessions (Count)" 41 | #value_format: "[<1000]0;[<1000000]0.0,"K";0.0,,"M"" 42 | type: number 43 | } 44 | dimension: total_purchase_revenue { 45 | hidden: yes 46 | label: "Events Purchase Revenue" 47 | value_format: "$#,##0.00" 48 | type: number 49 | } 50 | dimension: total_transactions { 51 | hidden: yes 52 | label: "Events Transactions" 53 | type: number 54 | } 55 | 56 | 57 | measure: segment_users { 58 | group_label: "In Selected Timeframe" 59 | type: count_distinct 60 | allow_approximate_optimization: yes 61 | sql: ${user_pseudo_id} ;; 62 | } 63 | 64 | measure: retention_rate { 65 | type: number 66 | sql: ${segment_users}/NULLIF(${sessions.total_users},0) ;; 67 | value_format_name: percent_1 68 | } 69 | 70 | measure: segment_sessions { 71 | group_label: "In Selected Timeframe" 72 | type: sum 73 | sql: ${total_sessions} ;; 74 | value_format_name: decimal_0 75 | } 76 | 77 | measure: segment_transaction_revenue { 78 | group_label: "In Selected Timeframe" 79 | type: sum 80 | sql: ${total_purchase_revenue} ;; 81 | value_format_name: usd_0 82 | } 83 | 84 | measure: segment_transaction_revenue_per_user { 85 | group_label: "In Selected Timeframe" 86 | type: number 87 | sql: ${segment_transaction_revenue}/NULLIF(${segment_users},0) ;; 88 | value_format_name: usd 89 | } 90 | 91 | measure: segment_transaction_count { 92 | group_label: "In Selected Timeframe" 93 | type: sum 94 | sql: ${total_transactions} ;; 95 | value_format_name: decimal_0 96 | } 97 | 98 | measure: segment_transaction_conversion_rate { 99 | group_label: "In Selected Timeframe" 100 | type: number 101 | sql: ${segment_transaction_count}/NULLIF(${segment_sessions},0) ;; 102 | value_format_name: percent_1 103 | } 104 | 105 | 106 | } 107 | -------------------------------------------------------------------------------- /views/event_data_dimensions/items_data.view.lkml: -------------------------------------------------------------------------------- 1 | ## Purpose: This view is for defining the 'event_data' 'Item' specific fields. This view unnested from event_data in the 'sessions' explore. 2 | 3 | view: event_data_items { 4 | 5 | ## Dimensions 6 | dimension: affiliation { 7 | group_label: "Items" 8 | type: string 9 | sql: ${TABLE}.affiliation ;; 10 | full_suggestions: yes 11 | } 12 | 13 | dimension: coupon { 14 | group_label: "Items" 15 | type: string 16 | sql: ${TABLE}.coupon ;; 17 | full_suggestions: yes 18 | } 19 | 20 | dimension: creative_name { 21 | group_label: "Items" 22 | type: string 23 | sql: ${TABLE}.creative_name ;; 24 | full_suggestions: yes 25 | } 26 | 27 | dimension: creative_slot { 28 | group_label: "Items" 29 | type: string 30 | sql: ${TABLE}.creative_slot ;; 31 | full_suggestions: yes 32 | } 33 | 34 | dimension: item_brand { 35 | group_label: "Items" 36 | type: string 37 | sql: ${TABLE}.item_brand ;; 38 | full_suggestions: yes 39 | } 40 | 41 | dimension: item_category { 42 | group_label: "Items" 43 | type: string 44 | sql: ${TABLE}.item_category ;; 45 | full_suggestions: yes 46 | } 47 | 48 | dimension: item_category2 { 49 | group_label: "Items" 50 | type: string 51 | sql: ${TABLE}.item_category2 ;; 52 | full_suggestions: yes 53 | } 54 | 55 | dimension: item_category3 { 56 | group_label: "Items" 57 | type: string 58 | sql: ${TABLE}.item_category3 ;; 59 | full_suggestions: yes 60 | } 61 | 62 | dimension: item_category4 { 63 | group_label: "Items" 64 | type: string 65 | sql: ${TABLE}.item_category4 ;; 66 | full_suggestions: yes 67 | } 68 | 69 | dimension: item_category5 { 70 | group_label: "Items" 71 | type: string 72 | sql: ${TABLE}.item_category5 ;; 73 | full_suggestions: yes 74 | } 75 | 76 | dimension: item_id { 77 | group_label: "Items" 78 | type: string 79 | sql: ${TABLE}.item_id ;; 80 | full_suggestions: yes 81 | } 82 | 83 | dimension: item_list_id { 84 | group_label: "Items" 85 | type: string 86 | sql: ${TABLE}.item_list_id ;; 87 | full_suggestions: yes 88 | } 89 | 90 | dimension: item_list_index { 91 | group_label: "Items" 92 | type: string 93 | sql: ${TABLE}.item_list_index ;; 94 | full_suggestions: yes 95 | } 96 | 97 | dimension: item_list_name { 98 | group_label: "Items" 99 | type: string 100 | sql: ${TABLE}.item_list_name ;; 101 | full_suggestions: yes 102 | } 103 | 104 | dimension: item_name { 105 | group_label: "Items" 106 | type: string 107 | sql: ${TABLE}.item_name ;; 108 | full_suggestions: yes 109 | } 110 | 111 | dimension: item_refund { 112 | group_label: "Items" 113 | type: number 114 | sql: ${TABLE}.item_refund ;; 115 | full_suggestions: yes 116 | } 117 | 118 | dimension: item_refund_in_usd { 119 | group_label: "Items" 120 | type: number 121 | sql: ${TABLE}.item_refund_in_usd ;; 122 | full_suggestions: yes 123 | } 124 | 125 | dimension: item_revenue { 126 | group_label: "Items" 127 | type: number 128 | sql: ${TABLE}.item_revenue ;; 129 | full_suggestions: yes 130 | } 131 | 132 | dimension: item_revenue_in_usd { 133 | group_label: "Items" 134 | type: number 135 | sql: ${TABLE}.item_revenue_in_usd ;; 136 | full_suggestions: yes 137 | } 138 | 139 | dimension: item_variant { 140 | group_label: "Items" 141 | type: string 142 | sql: ${TABLE}.item_variant ;; 143 | full_suggestions: yes 144 | } 145 | 146 | dimension: location_id { 147 | group_label: "Items" 148 | type: string 149 | sql: ${TABLE}.location_id ;; 150 | full_suggestions: yes 151 | } 152 | 153 | dimension: price { 154 | group_label: "Items" 155 | type: number 156 | sql: ${TABLE}.price ;; 157 | full_suggestions: yes 158 | } 159 | 160 | dimension: price_in_usd { 161 | group_label: "Items" 162 | type: number 163 | sql: ${TABLE}.price_in_usd ;; 164 | full_suggestions: yes 165 | } 166 | 167 | dimension: promotion_id { 168 | group_label: "Items" 169 | type: string 170 | sql: ${TABLE}.promotion_id ;; 171 | full_suggestions: yes 172 | } 173 | 174 | dimension: promotion_name { 175 | group_label: "Items" 176 | type: string 177 | sql: ${TABLE}.promotion_name ;; 178 | full_suggestions: yes 179 | } 180 | 181 | dimension: quantity { 182 | group_label: "Items" 183 | type: number 184 | sql: ${TABLE}.quantity ;; 185 | full_suggestions: yes 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /views/event_data_dimensions/goals.view.lkml: -------------------------------------------------------------------------------- 1 | # Purpose: To house the fields used to generate Custom Goals. This file is extended into the `event_data` view. 2 | 3 | ### 4 | # Adding New Goal Types: 5 | # To create a new goal type, a new filter will be created. This filter will be used to compare values of an existing dimension. 6 | # Each filter should correspond to an existing dimension (to be used in place of ${new_dimension_to_be_filtered} in Step 2 below). 7 | # 8 | # 1. Add a Filter - 9 | # filter: new_filter_name { 10 | # label: "New Filter Label" 11 | # view_label: "Goals" 12 | # group_label: "Goal Selection" 13 | # description: "New Goal Description" 14 | # 15 | # 2. Add your new filter to the sql parameter of the dynamic_goal, goal_in_query, and has_completed_goal dimensions - 16 | # dimension: dynamic_goal { 17 | # sql: IF( ${has_completed_goal}, CONCAT( 18 | # IF({{ event_name_goal_selection._in_query }}, CONCAT(${event_name}, " "), "") 19 | # , IF({{ page_goal_selection._in_query }}, CONCAT("on ", ${event_param_page}), "") 20 | # ----> , IF({{ new_filter_name._in_query }}, CONCAT(${new_dimension_to_be_filtered}), "") 21 | # ), null );; } 22 | # 23 | # dimension: goal_in_query { 24 | # sql: {{ event_name_goal_selection._in_query }} 25 | # OR {{ page_goal_selection._in_query }} 26 | # ----> OR {{ new_filter_name._in_query }} ;; } 27 | # 28 | # dimension: has_completed_goal { 29 | # sql:if( 30 | # ${goal_in_query} 31 | # , {% condition event_name_goal_selection %} ${event_name} {% endcondition %} 32 | # AND {% condition page_goal_selection %} ${event_param_page} {% endcondition %} 33 | # ----> AND {% condition new_filter_name %} ${new_dimension_to_be_filtered} {% endcondition %} 34 | # , false 35 | # );; } 36 | # 37 | # 3. Add the newly created Filter to the Custom Goals Conversion dashboard and apply to all tiles. 38 | ### 39 | 40 | view: goals { 41 | extension: required 42 | 43 | ## Filters 44 | 45 | filter: event_name_goal_selection { 46 | label: "Event Name" 47 | view_label: "Goals" 48 | group_label: "Goal Selection" 49 | description: "Enter Event Name to be used with Total Conversion measures." 50 | suggest_explore: sessions 51 | suggest_dimension: events.event_name 52 | suggest_persist_for: "0 seconds" 53 | type: string 54 | } 55 | 56 | filter: page_goal_selection { 57 | label: "Page" 58 | view_label: "Goals" 59 | group_label: "Goal Selection" 60 | description: "Enter Page Path to be used with Conversion measures (format should be: '/'). Should not include Hostname." 61 | suggest_explore: sessions 62 | suggest_dimension: events.event_param_page 63 | type: string 64 | } 65 | 66 | ## Dimensions 67 | 68 | dimension: dynamic_goal { 69 | view_label: "Goals" 70 | group_label: "Goals" 71 | description: "Goal label based on Goal selection filters." 72 | type: string 73 | sql: IF( ${has_completed_goal}, CONCAT( 74 | IF({{ event_name_goal_selection._in_query }}, CONCAT(${event_name}, " "), "") 75 | , IF({{ page_goal_selection._in_query }}, CONCAT("on ", ${event_param_page}), "") 76 | ), null );; 77 | } 78 | 79 | dimension: goal_in_query { 80 | description: "Check to verify user has entered a value for at least one goal filter." 81 | hidden: yes 82 | type: yesno 83 | sql: {{ event_name_goal_selection._in_query }} 84 | OR {{ page_goal_selection._in_query }};; 85 | } 86 | 87 | dimension: has_completed_goal { 88 | view_label: "Goals" 89 | group_label: "Goals" 90 | description: "A session that resulted in a conversion (i.e. resulted in reaching successful point on website defined in 'Goal Selection' field)." 91 | type: yesno 92 | sql:if( 93 | ${goal_in_query} 94 | , {% condition event_name_goal_selection %} ${event_name} {% endcondition %} 95 | AND {% condition page_goal_selection %} ${event_param_page} {% endcondition %} 96 | , false 97 | );; 98 | } 99 | 100 | ## Measures 101 | measure: conversion_count { 102 | view_label: "Goals" 103 | group_label: "Goal Conversions" 104 | label: "Total Conversions" 105 | description: "Total number of hits (Page or Event) that are identified as converisons based on 'Goal Selection' filters." 106 | type: count_distinct 107 | allow_approximate_optimization: yes 108 | sql: ${ed_key} ;; 109 | filters: [has_completed_goal: "yes"] 110 | value_format_name: formatted_number 111 | drill_fields: [] 112 | } 113 | 114 | measure: sessions_with_conversions { 115 | view_label: "Goals" 116 | group_label: "Goal Conversions" 117 | label: "Sessions with Conversion" 118 | description: "Sessions that result in a conversion based on 'Goal Selection' filters." 119 | type: count_distinct 120 | allow_approximate_optimization: yes 121 | sql: ${sessions.sl_key} ;; 122 | filters: [has_completed_goal: "yes"] 123 | value_format_name: formatted_number 124 | drill_fields: [client_id, visit_number, sessions_with_conversions] 125 | } 126 | 127 | measure: session_conversion_rate { 128 | view_label: "Goals" 129 | group_label: "Goal Conversions" 130 | label: "Session Conversion Rate" 131 | description: "Percentage of sessions resulting in a conversion based on 'Goal Selection' filters." 132 | type: number 133 | sql: (1.0*${sessions_with_conversions})/NULLIF(${sessions.total_sessions}, 0) ;; 134 | value_format_name: percent_1 135 | drill_fields: [] 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /views/event_data_dimensions/event_data_event_params.view.lkml: -------------------------------------------------------------------------------- 1 | view: event_data_event_params { 2 | extension: required 3 | 4 | ## Event Parameters 5 | ## Because there are multiple "key"/"value" rows per event, these are unnested at the dimension level. 6 | ## This view is included in event_data.view, and not directly joined on the model. 7 | 8 | dimension: event_param_all_data { 9 | group_label: "Event: Parameters" 10 | label: "All Data" 11 | type: number 12 | sql: (SELECT value.double_value FROM UNNEST(event_params) WHERE key = "all_data") ;; 13 | } 14 | 15 | dimension: event_param_campaign { 16 | group_label: "Event: Parameters" 17 | label: "Campaign" 18 | description: "The campaign value. Usually set by the utm_campaign URL parameter." 19 | type: string 20 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "campaign") ;; 21 | full_suggestions: yes 22 | } 23 | 24 | dimension: event_param_clean_event { 25 | group_label: "Event: Parameters" 26 | label: "Clean Event" 27 | type: string 28 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "clean_event") ;; 29 | full_suggestions: yes 30 | } 31 | 32 | dimension: event_param_debug_mode { 33 | group_label: "Event: Parameters" 34 | label: "Debug Mode" 35 | type: number 36 | sql: (SELECT value.int_value FROM UNNEST(event_params) WHERE key = "debug_mode") ;; 37 | } 38 | 39 | dimension: event_param_engaged_session_event { 40 | group_label: "Event: Parameters" 41 | label: "Session Event" 42 | type: number 43 | sql: (SELECT coalesce(cast(value.string_value as INT64),value.int_value) FROM UNNEST(event_params) WHERE key = "engaged_session_event") ;; 44 | } 45 | 46 | dimension: event_param_engagement_time_msec { 47 | group_label: "Event: Parameters" 48 | label: "Engagement Time MSEC" 49 | type: number 50 | sql: (SELECT value.int_value FROM UNNEST(event_params) WHERE key = "engagement_time_msec") ;; 51 | } 52 | 53 | dimension: event_param_entrances { 54 | group_label: "Event: Parameters" 55 | label: "Entrances" 56 | type: number 57 | sql: (SELECT value.int_value FROM UNNEST(event_params) WHERE key = "entrances") ;; 58 | } 59 | 60 | dimension: event_param_ga_session_id { 61 | group_label: "Event: Parameters" 62 | label: "GA Session ID" 63 | type: number 64 | sql: (SELECT value.int_value FROM UNNEST(event_params) WHERE key = "ga_session_id") ;; 65 | full_suggestions: yes 66 | } 67 | 68 | dimension: event_param_ga_session_number { 69 | group_label: "Event: Parameters" 70 | label: "GA Session Number" 71 | type: number 72 | sql: (SELECT value.int_value FROM UNNEST(event_params) WHERE key = "ga_session_number") ;; 73 | } 74 | 75 | dimension: event_param_medium { 76 | group_label: "Event: Parameters" 77 | label: "Medium" 78 | type: string 79 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "medium") ;; 80 | full_suggestions: yes 81 | } 82 | 83 | dimension: event_param_host { 84 | group_label: "Event: Parameters" 85 | label: "Host" 86 | description: "Host of Page View URL" 87 | full_suggestions: yes 88 | type: string 89 | sql: NET.HOST((SELECT value.string_value FROM UNNEST(event_params) WHERE key = "page_location")) ;; 90 | } 91 | 92 | dimension: event_param_page { 93 | group_label: "Event: Parameters" 94 | label: "Page" 95 | description: "The path of the page." 96 | full_suggestions: yes 97 | type: string 98 | sql: coalesce(regexp_extract((SELECT value.string_value FROM UNNEST(event_params) WHERE key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/') ;; 99 | } 100 | 101 | # The "Page" event parameter may not be enabled, in which situation the above regex query will extract the path from the page location value. 102 | # If the "Page" event parameter is enabled, you may use this below dimension instead if desired: 103 | # dimension: event_param_page_path { 104 | # group_label: "Event: Parameters" 105 | # label: "Page" 106 | # description: "The Page Path value" 107 | # full_suggestions: yes 108 | # type: string 109 | # sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "page") ;; 110 | # } 111 | 112 | dimension: event_param_page_location { 113 | group_label: "Event: Parameters" 114 | label: "Page Location" 115 | type: string 116 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "page_location") ;; 117 | full_suggestions: yes 118 | } 119 | 120 | dimension: event_param_page_referrer { 121 | group_label: "Event: Parameters" 122 | label: "Page Referrer" 123 | type: string 124 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "page_referrer") ;; 125 | full_suggestions: yes 126 | } 127 | 128 | dimension: event_param_page_title { 129 | group_label: "Event: Parameters" 130 | label: "Page Title" 131 | description: "The page's title. Multiple pages might have the same page title." 132 | type: string 133 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "page_title") ;; 134 | full_suggestions: yes 135 | } 136 | 137 | dimension: event_param_percent_scrolled { 138 | group_label: "Event: Parameters" 139 | label: "Percent Scrolled" 140 | type: number 141 | sql: (SELECT value.int_value FROM UNNEST(event_params) WHERE key = "percent_scrolled") ;; 142 | } 143 | 144 | dimension: event_param_session_engaged { 145 | group_label: "Event: Parameters" 146 | label: "Session Engaged" 147 | type: number 148 | sql: (SELECT coalesce(cast(value.string_value as INT64),value.int_value) FROM UNNEST(event_params) WHERE key = "session_engaged") ;; 149 | } 150 | 151 | dimension: event_param_source { 152 | group_label: "Event: Parameters" 153 | label: "Source" 154 | type: string 155 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "source") ;; 156 | full_suggestions: yes 157 | } 158 | 159 | dimension: event_param_synthetic_bundle { 160 | group_label: "Event: Parameters" 161 | label: "Synthetic Bundle" 162 | type: number 163 | sql: (SELECT coalesce(cast(value.string_value as INT64),value.int_value) FROM UNNEST(event_params) WHERE key = "synthetic_bundle") ;; 164 | } 165 | 166 | dimension: event_param_term { 167 | # group_label: "Event: Parameters" 168 | # label: "Term" 169 | view_label: "Acquisition" 170 | group_label: "Advertising" 171 | label: "Keyword" 172 | description: "The Event keyword of the traffic source, usually set when the trafficSource.medium is 'organic' or 'cpc'. Can be set by the utm_term URL parameter." 173 | type: string 174 | sql: (SELECT value.string_value FROM UNNEST(event_params) WHERE key = "term") ;; 175 | full_suggestions: yes 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /views/bqml/predictions.view.lkml: -------------------------------------------------------------------------------- 1 | # ######################## TRAINING/TESTING INPUTS ############################# 2 | 3 | 4 | # view: training_input { 5 | # derived_table: { 6 | # explore_source: sessions { 7 | # column: sl_key {} 8 | # column: user_pseudo_id {} 9 | # column: session_attribution_medium {} 10 | # column: session_attribution_channel {} 11 | # column: device_is_mobile {} 12 | # column: geo_data_country {} 13 | # column: total_bounced_sessions {} 14 | # column: pageviews_total { field: events.total_page_views } 15 | # column: transactions_count { field: events.total_transactions } 16 | # column: total_first_visit_sessions {} 17 | # column: will_purchase_in_future {} 18 | # filters: { 19 | # field: sessions.session_date 20 | # value: "180 days ago for 90 days" 21 | # } 22 | # filters: { 23 | # field: sessions.prediction_window_days 24 | # value: "60" 25 | # } 26 | # } 27 | # } 28 | # } 29 | 30 | # view: testing_input { 31 | # derived_table: { 32 | # explore_source: sessions { 33 | # column: sl_key {} 34 | # column: user_pseudo_id {} 35 | # column: session_attribution_medium {} 36 | # column: session_attribution_channel {} 37 | # column: device_is_mobile {} 38 | # column: geo_data_country {} 39 | # column: total_bounced_sessions {} 40 | # column: pageviews_total { field: events.total_page_views } 41 | # column: transactions_count { field: events.total_transactions } 42 | # column: total_first_visit_sessions {} 43 | # column: will_purchase_in_future {} 44 | # filters: { 45 | # field: sessions.session_date 46 | # value: "130 days ago for 90 days" 47 | # } 48 | # filters: { 49 | # field: sessions.prediction_window_days 50 | # value: "60" 51 | # } 52 | # } 53 | # } 54 | # } 55 | # ######################## MODEL ############################# 56 | 57 | # view: future_purchase_model { 58 | # derived_table: { 59 | # datagroup_trigger: bqml_datagroup 60 | # sql_create: 61 | # CREATE OR REPLACE MODEL ${SQL_TABLE_NAME} 62 | # OPTIONS(model_type='logistic_reg' 63 | # , labels=['will_purchase_in_future'] 64 | # ) AS 65 | # SELECT 66 | # * EXCEPT(user_pseudo_id, sl_key) 67 | # FROM ${training_input.SQL_TABLE_NAME};; 68 | # } 69 | # } 70 | 71 | # ######################## TRAINING INFORMATION ############################# 72 | # explore: future_purchase_model_evaluation {} 73 | # explore: future_purchase_model_training_info {} 74 | # explore: roc_curve {} 75 | 76 | # # VIEWS: 77 | # view: future_purchase_model_evaluation { 78 | # derived_table: { 79 | # sql: SELECT * FROM ml.EVALUATE( 80 | # MODEL ${future_purchase_model.SQL_TABLE_NAME}, 81 | # (SELECT * FROM ${testing_input.SQL_TABLE_NAME}));; 82 | # } 83 | # dimension: recall {type: number value_format_name:percent_2} 84 | # dimension: accuracy {type: number value_format_name:percent_2} 85 | # dimension: f1_score {type: number value_format_name:percent_3} 86 | # dimension: log_loss {type: number} 87 | # dimension: roc_auc {type: number} 88 | # } 89 | 90 | # view: roc_curve { 91 | # derived_table: { 92 | # sql: SELECT * FROM ml.ROC_CURVE( 93 | # MODEL ${future_purchase_model.SQL_TABLE_NAME}, 94 | # (SELECT * FROM ${testing_input.SQL_TABLE_NAME}));; 95 | # } 96 | # dimension: threshold { 97 | # type: number 98 | # link: { 99 | # label: "Likely Customers to Purchase" 100 | # url: "/explore/bqml_ga_demo/ga_sessions?fields=ga_sessions.fullVisitorId,future_purchase_prediction.max_predicted_score&f[future_purchase_prediction.predicted_will_purchase_in_future]=%3E%3D{{value}}" 101 | # icon_url: "http://www.looker.com/favicon.ico" 102 | # } 103 | # } 104 | # dimension: recall {type: number value_format_name: percent_2} 105 | # dimension: false_positive_rate {type: number} 106 | # dimension: true_positives {type: number } 107 | # dimension: false_positives {type: number} 108 | # dimension: true_negatives {type: number} 109 | # dimension: false_negatives {type: number } 110 | # dimension: precision { 111 | # type: number 112 | # value_format_name: percent_2 113 | # sql: ${true_positives} / NULLIF((${true_positives} + ${false_positives}),0);; 114 | # } 115 | # measure: total_false_positives { 116 | # type: sum 117 | # sql: ${false_positives} ;; 118 | # } 119 | # measure: total_true_positives { 120 | # type: sum 121 | # sql: ${true_positives} ;; 122 | # } 123 | # dimension: threshold_accuracy { 124 | # type: number 125 | # value_format_name: percent_2 126 | # sql: 1.0*(${true_positives} + ${true_negatives}) / NULLIF((${true_positives} + ${true_negatives} + ${false_positives} + ${false_negatives}),0);; 127 | # } 128 | # dimension: threshold_f1 { 129 | # type: number 130 | # value_format_name: percent_3 131 | # sql: 2.0*${recall}*${precision} / NULLIF((${recall}+${precision}),0);; 132 | # } 133 | # } 134 | 135 | # view: future_purchase_model_training_info { 136 | # derived_table: { 137 | # sql: SELECT * FROM ml.TRAINING_INFO(MODEL ${future_purchase_model.SQL_TABLE_NAME});; 138 | # } 139 | # dimension: training_run {type: number} 140 | # dimension: iteration {type: number} 141 | # dimension: loss_raw {sql: ${TABLE}.loss;; type: number hidden:yes} 142 | # dimension: eval_loss {type: number} 143 | # dimension: duration_ms {label:"Duration (ms)" type: number} 144 | # dimension: learning_rate {type: number} 145 | # measure: total_iterations { 146 | # type: count 147 | # } 148 | # measure: loss { 149 | # value_format_name: decimal_2 150 | # type: sum 151 | # sql: ${loss_raw} ;; 152 | # } 153 | # measure: total_training_time { 154 | # type: sum 155 | # label:"Total Training Time (sec)" 156 | # sql: ${duration_ms}/1000 ;; 157 | # value_format_name: decimal_1 158 | # } 159 | # measure: average_iteration_time { 160 | # type: average 161 | # label:"Average Iteration Time (sec)" 162 | # sql: ${duration_ms}/1000 ;; 163 | # value_format_name: decimal_1 164 | # } 165 | # } 166 | # ########################################## PREDICT FUTURE ############################ 167 | # view: future_input { 168 | # derived_table: { 169 | # explore_source: sessions { 170 | # column: sl_key {} 171 | # column: user_pseudo_id {} 172 | # column: session_attribution_medium {} 173 | # column: session_attribution_channel {} 174 | # column: device_is_mobile {} 175 | # column: geo_data_country {} 176 | # column: total_bounced_sessions {} 177 | # column: pageviews_total { field: events.total_page_views } 178 | # column: transactions_count { field: events.total_transactions } 179 | # column: total_first_visit_sessions {} 180 | # filters: { 181 | # field: sessions.session_date 182 | # value: "360 days" 183 | # } 184 | # } 185 | # } 186 | # } 187 | 188 | 189 | # view: future_purchase_prediction { 190 | # derived_table: { 191 | # sql: SELECT * FROM ml.PREDICT( 192 | # MODEL ${future_purchase_model.SQL_TABLE_NAME}, 193 | # (SELECT * FROM ${future_input.SQL_TABLE_NAME}));; 194 | # } 195 | # dimension: predicted_will_purchase_in_future {type: number} 196 | # dimension: sl_key {type: number hidden:yes} 197 | # dimension: user_pseudo_id {type: number hidden: yes} 198 | # measure: max_predicted_score { 199 | # type: max 200 | # value_format_name: percent_2 201 | # sql: ${predicted_will_purchase_in_future} ;; 202 | # } 203 | # measure: median_predicted_score { 204 | # type: median 205 | # sql: ${predicted_will_purchase_in_future} ;; 206 | # } 207 | # measure: average_predicted_score { 208 | # type: average 209 | # value_format_name: percent_2 210 | # sql: ${predicted_will_purchase_in_future} ;; 211 | # } 212 | # } 213 | -------------------------------------------------------------------------------- /views/event_data_dimensions/event_funnel.view.lkml: -------------------------------------------------------------------------------- 1 | view: event_funnel { 2 | extension: required 3 | 4 | ## Filters 5 | filter: event_1_filter { 6 | view_label: "Event Funnel" 7 | group_label: "Funnel Events" 8 | suggest_explore: sessions 9 | suggest_dimension: events.event_name 10 | description: "Event 1 to be used with Count of Event 1" 11 | } 12 | filter: event_2_filter { 13 | view_label: "Event Funnel" 14 | group_label: "Funnel Events" 15 | suggest_explore: sessions 16 | suggest_dimension: events.event_name 17 | description: "Event 2 to be used with Count of Event 2" 18 | } 19 | filter: event_3_filter { 20 | view_label: "Event Funnel" 21 | group_label: "Funnel Events" 22 | suggest_explore: sessions 23 | suggest_dimension: events.event_name 24 | description: "Event 3 to be used with Count of Event 3" 25 | } 26 | filter: event_4_filter { 27 | view_label: "Event Funnel" 28 | group_label: "Funnel Events" 29 | suggest_explore: sessions 30 | suggest_dimension: events.event_name 31 | description: "Event 4 to be used with Count of Event 4" 32 | } 33 | filter: event_5_filter { 34 | view_label: "Event Funnel" 35 | group_label: "Funnel Events" 36 | suggest_explore: sessions 37 | suggest_dimension: events.event_name 38 | description: "Event 5 to be used with Count of Event 5" 39 | } 40 | filter: event_6_filter { 41 | view_label: "Event Funnel" 42 | group_label: "Funnel Events" 43 | suggest_explore: sessions 44 | suggest_dimension: events.event_name 45 | description: "Event 6 to be used with Count of Event 6" 46 | } 47 | 48 | ## Dimensions 49 | dimension: event_1 { 50 | type: string 51 | hidden: yes 52 | sql: (select event_name from UNNEST(${sessions.event_data}) where event_rank = 1) ;; 53 | } 54 | dimension: event_2 { 55 | type: string 56 | hidden: yes 57 | sql: (select event_name from UNNEST(${sessions.event_data}) where event_rank = 2) ;; 58 | } 59 | dimension: event_3 { 60 | type: string 61 | hidden: yes 62 | sql: (select event_name from UNNEST(${sessions.event_data}) where event_rank = 3) ;; 63 | } 64 | dimension: event_4 { 65 | type: string 66 | hidden: yes 67 | sql: (select event_name from UNNEST(${sessions.event_data}) where event_rank = 4) ;; 68 | } 69 | dimension: event_5 { 70 | type: string 71 | hidden: yes 72 | sql: (select event_name from UNNEST(${sessions.event_data}) where event_rank = 5) ;; 73 | } 74 | dimension: event_6 { 75 | type: string 76 | hidden: yes 77 | sql: (select event_name from UNNEST(${sessions.event_data}) where event_rank = 6) ;; 78 | } 79 | 80 | dimension: event_1_tag { 81 | type: number 82 | hidden: yes 83 | sql: case when {% condition event_1_filter %} ${event_1} {% endcondition %} and ${event_1} is not null then 1 else 0 end ;; 84 | } 85 | dimension: event_2_tag { 86 | type: number 87 | hidden: yes 88 | sql: case when {% condition event_1_filter %} ${event_1} {% endcondition %} 89 | and {% condition event_2_filter %} ${event_2} {% endcondition %} 90 | and ${event_2} is not null then 1 else 0 end ;; 91 | } 92 | dimension: event_3_tag { 93 | type: number 94 | hidden: yes 95 | sql: case when {% condition event_1_filter %} ${event_1} {% endcondition %} 96 | and {% condition event_2_filter %} ${event_2} {% endcondition %} 97 | and {% condition event_3_filter %} ${event_3} {% endcondition %} 98 | and ${event_2} is not null 99 | and ${event_3} is not null then 1 else 0 end ;; 100 | } 101 | dimension: event_4_tag { 102 | type: number 103 | hidden: yes 104 | sql: case when {% condition event_1_filter %} ${event_1} {% endcondition %} 105 | and {% condition event_2_filter %} ${event_2} {% endcondition %} 106 | and {% condition event_3_filter %} ${event_3} {% endcondition %} 107 | and {% condition event_4_filter %} ${event_4} {% endcondition %} 108 | and ${event_2} is not null 109 | and ${event_3} is not null 110 | and ${event_4} is not null then 1 else 0 end ;; 111 | } 112 | dimension: event_5_tag { 113 | type: number 114 | hidden: yes 115 | sql: case when {% condition event_1_filter %} ${event_1} {% endcondition %} 116 | and {% condition event_2_filter %} ${event_2} {% endcondition %} 117 | and {% condition event_3_filter %} ${event_3} {% endcondition %} 118 | and {% condition event_4_filter %} ${event_4} {% endcondition %} 119 | and {% condition event_5_filter %} ${event_5} {% endcondition %} 120 | and ${event_2} is not null 121 | and ${event_3} is not null 122 | and ${event_4} is not null 123 | and ${event_5} is not null then 1 else 0 end ;; 124 | } 125 | dimension: event_6_tag { 126 | type: number 127 | hidden: yes 128 | sql: case when {% condition event_1_filter %} ${event_1} {% endcondition %} 129 | and {% condition event_2_filter %} ${event_2} {% endcondition %} 130 | and {% condition event_3_filter %} ${event_3} {% endcondition %} 131 | and {% condition event_4_filter %} ${event_4} {% endcondition %} 132 | and {% condition event_5_filter %} ${event_5} {% endcondition %} 133 | and {% condition event_6_filter %} ${event_6} {% endcondition %} 134 | and ${event_2} is not null 135 | and ${event_3} is not null 136 | and ${event_4} is not null 137 | and ${event_5} is not null 138 | and ${event_6} is not null then 1 else 0 end ;; 139 | } 140 | 141 | 142 | ## Measures 143 | measure: count_of_event_1 { 144 | view_label: "Event Funnel" 145 | type: sum 146 | sql: ${event_1_tag} ;; 147 | label: "{% if event_1_filter._in_query %} 148 | {{_filters['event_1_filter']}} 149 | {% else %} 150 | Count of Event 1 151 | {% endif %}" 152 | description: "Count of Event 1 to be used with Event 1 filter, if no filter is selected it shows all events" 153 | } 154 | 155 | measure: count_of_event_2 { 156 | view_label: "Event Funnel" 157 | type: sum 158 | sql: ${event_2_tag} ;; 159 | label: "{% if event_2_filter._in_query %} 160 | {{_filters['event_2_filter']}} 161 | {% else %} 162 | Count of Event 2 163 | {% endif %}" 164 | description: "Count of Event 2 to be used with Event 2 filter, if no filter is selected it shows all events" 165 | } 166 | 167 | measure: count_of_event_3 { 168 | view_label: "Event Funnel" 169 | type: sum 170 | sql: ${event_3_tag} ;; 171 | label: "{% if event_3_filter._in_query %} 172 | {{_filters['event_3_filter']}} 173 | {% else %} 174 | Count of Event 3 175 | {% endif %}" 176 | description: "Count of Event 3 to be used with Event 3 filter, if no filter is selected it shows all events" 177 | } 178 | 179 | measure: count_of_event_4 { 180 | view_label: "Event Funnel" 181 | type: sum 182 | sql: ${event_4_tag} ;; 183 | label: "{% if event_4_filter._in_query %} 184 | {{_filters['event_4_filter']}} 185 | {% else %} 186 | Count of Event 4 187 | {% endif %}" 188 | description: "Count of Event 4 to be used with Event 4 filter, if no filter is selected it shows all events" 189 | } 190 | 191 | measure: count_of_event_5 { 192 | view_label: "Event Funnel" 193 | type: sum 194 | sql: ${event_5_tag} ;; 195 | label: "{% if event_5_filter._in_query %} 196 | {{_filters['event_5_filter']}} 197 | {% else %} 198 | Count of Event 5 199 | {% endif %}" 200 | description: "Count of Event 5 to be used with Event 5 filter, if no filter is selected it shows all events" 201 | } 202 | 203 | measure: count_of_event_6 { 204 | view_label: "Event Funnel" 205 | type: sum 206 | sql: ${event_6_tag} ;; 207 | label: "{% if event_6_filter._in_query %} 208 | {{_filters['event_6_filter']}} 209 | {% else %} 210 | Count of Event 6 211 | {% endif %}" 212 | description: "Count of Event 6 to be used with Event 6 filter, if no filter is selected it shows all events" 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /views/event_data_dimensions/page_funnel.view.lkml: -------------------------------------------------------------------------------- 1 | view: page_funnel { 2 | extension: required 3 | 4 | ## Filters 5 | filter: page_1_filter { 6 | view_label: "Page Funnel" 7 | group_label: "Funnel Pages" 8 | suggest_explore: sessions 9 | suggest_dimension: events.event_param_page 10 | description: "Page 1 Filter, to be used with Count of Page 1" 11 | } 12 | 13 | filter: page_2_filter { 14 | view_label: "Page Funnel" 15 | group_label: "Funnel Pages" 16 | suggest_explore: sessions 17 | suggest_dimension: events.event_param_page 18 | description: "Page 2 Filter, to be used with Count of Page 2" 19 | } 20 | 21 | filter: page_3_filter { 22 | view_label: "Page Funnel" 23 | group_label: "Funnel Pages" 24 | suggest_explore: sessions 25 | suggest_dimension: events.event_param_page 26 | description: "Page 3 Filter, to be used with Count of Page 3" 27 | } 28 | 29 | filter: page_4_filter { 30 | view_label: "Page Funnel" 31 | group_label: "Funnel Pages" 32 | suggest_explore: sessions 33 | suggest_dimension: events.event_param_page 34 | description: "Page 4 Filter, to be used with Count of Page 4" 35 | } 36 | 37 | filter: page_5_filter { 38 | view_label: "Page Funnel" 39 | group_label: "Funnel Pages" 40 | suggest_explore: sessions 41 | suggest_dimension: events.event_param_page 42 | description: "Page 5 Filter, to be used with Count of Page 5" 43 | } 44 | 45 | filter: page_6_filter { 46 | view_label: "Page Funnel" 47 | group_label: "Funnel Pages" 48 | suggest_explore: sessions 49 | suggest_dimension: events.event_param_page 50 | description: "Page 6 Filter, to be used with Count of Page 6" 51 | } 52 | 53 | ## Dimensions 54 | dimension: sl_key { 55 | type: string 56 | sql: ${TABLE}.sl_key ;; 57 | hidden: yes 58 | primary_key: yes 59 | } 60 | dimension: page_1 { 61 | type: string 62 | hidden: yes 63 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/') from UNNEST(${sessions.event_data}) where page_view_rank = 1) ;; 64 | } 65 | dimension: page_2 { 66 | type: string 67 | hidden: yes 68 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/') from UNNEST(${sessions.event_data}) where page_view_rank = 2) ;; 69 | } 70 | dimension: page_3 { 71 | type: string 72 | hidden: yes 73 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/') from UNNEST(${sessions.event_data}) where page_view_rank = 3) ;; 74 | } 75 | dimension: page_4 { 76 | type: string 77 | hidden: yes 78 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/') from UNNEST(${sessions.event_data}) where page_view_rank = 4) ;; 79 | } 80 | dimension: page_5 { 81 | type: string 82 | hidden: yes 83 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/') from UNNEST(${sessions.event_data}) where page_view_rank = 5) ;; 84 | } 85 | dimension: page_6 { 86 | type: string 87 | hidden: yes 88 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/') from UNNEST(${sessions.event_data}) where page_view_rank = 6) ;; 89 | } 90 | 91 | dimension: page_1_tag { 92 | type: number 93 | hidden: yes 94 | sql: case when {% condition page_1_filter %} ${page_1} {% endcondition %} and ${page_1} is not null then 1 else 0 end ;; 95 | } 96 | dimension: page_2_tag { 97 | type: number 98 | hidden: yes 99 | sql: case when {% condition page_1_filter %} ${page_1} {% endcondition %} 100 | and {% condition page_2_filter %} ${page_2} {% endcondition %} 101 | and ${page_2} is not null then 1 else 0 end ;; 102 | } 103 | dimension: page_3_tag { 104 | type: number 105 | hidden: yes 106 | sql: case when {% condition page_1_filter %} ${page_1} {% endcondition %} 107 | and {% condition page_2_filter %} ${page_2} {% endcondition %} 108 | and {% condition page_3_filter %} ${page_3} {% endcondition %} 109 | and ${page_2} is not null 110 | and ${page_3} is not null then 1 else 0 end ;; 111 | } 112 | dimension: page_4_tag { 113 | type: number 114 | hidden: yes 115 | sql: case when {% condition page_1_filter %} ${page_1} {% endcondition %} 116 | and {% condition page_2_filter %} ${page_2} {% endcondition %} 117 | and {% condition page_3_filter %} ${page_3} {% endcondition %} 118 | and {% condition page_4_filter %} ${page_4} {% endcondition %} 119 | and ${page_2} is not null 120 | and ${page_3} is not null 121 | and ${page_4} is not null then 1 else 0 end ;; 122 | } 123 | dimension: page_5_tag { 124 | type: number 125 | hidden: yes 126 | sql: case when {% condition page_1_filter %} ${page_1} {% endcondition %} 127 | and {% condition page_2_filter %} ${page_2} {% endcondition %} 128 | and {% condition page_3_filter %} ${page_3} {% endcondition %} 129 | and {% condition page_4_filter %} ${page_4} {% endcondition %} 130 | and {% condition page_5_filter %} ${page_5} {% endcondition %} 131 | and ${page_2} is not null 132 | and ${page_3} is not null 133 | and ${page_4} is not null 134 | and ${page_5} is not null then 1 else 0 end ;; 135 | } 136 | dimension: page_6_tag { 137 | type: number 138 | hidden: yes 139 | sql: case when {% condition page_1_filter %} ${page_1} {% endcondition %} 140 | and {% condition page_2_filter %} ${page_2} {% endcondition %} 141 | and {% condition page_3_filter %} ${page_3} {% endcondition %} 142 | and {% condition page_4_filter %} ${page_4} {% endcondition %} 143 | and {% condition page_5_filter %} ${page_5} {% endcondition %} 144 | and {% condition page_6_filter %} ${page_6} {% endcondition %} 145 | and ${page_2} is not null 146 | and ${page_3} is not null 147 | and ${page_4} is not null 148 | and ${page_5} is not null 149 | and ${page_6} is not null then 1 else 0 end ;; 150 | } 151 | 152 | ## Measures 153 | 154 | measure: count_of_page_1 { 155 | view_label: "Page Funnel" 156 | type: sum 157 | sql: ${page_1_tag} ;; 158 | label: "{% if page_1_filter._in_query %} 159 | {{_filters['page_1_filter']}} 160 | {% else %} 161 | Count of Page 1 162 | {% endif %}" 163 | description: "Count of Page 1 to be used with Page 1 filter, if no filter is selected it shows all Pages" 164 | } 165 | 166 | measure: count_of_page_2 { 167 | view_label: "Page Funnel" 168 | type: sum 169 | sql: ${page_2_tag} ;; 170 | label: "{% if page_2_filter._in_query %} 171 | {{_filters['page_2_filter']}} 172 | {% else %} 173 | Count of Page 2 174 | {% endif %}" 175 | description: "Count of Page 2 to be used with Page 2 filter, if no filter is selected it shows all Pages" 176 | } 177 | 178 | measure: count_of_page_3 { 179 | view_label: "Page Funnel" 180 | type: sum 181 | sql: ${page_3_tag} ;; 182 | label: "{% if page_3_filter._in_query %} 183 | {{_filters['page_3_filter']}} 184 | {% else %} 185 | Count of Page 3 186 | {% endif %}" 187 | description: "Count of Page 3 to be used with Page 3 filter, if no filter is selected it shows all Pages" 188 | } 189 | 190 | measure: count_of_page_4 { 191 | view_label: "Page Funnel" 192 | type: sum 193 | sql: ${page_4_tag} ;; 194 | label: "{% if page_4_filter._in_query %} 195 | {{_filters['page_4_filter']}} 196 | {% else %} 197 | Count of Page 4 198 | {% endif %}" 199 | description: "Count of Page 4 to be used with Page 4 filter, if no filter is selected it shows all Pages" 200 | } 201 | 202 | measure: count_of_page_5 { 203 | view_label: "Page Funnel" 204 | type: sum 205 | sql: ${page_5_tag} ;; 206 | label: "{% if page_5_filter._in_query %} 207 | {{_filters['page_5_filter']}} 208 | {% else %} 209 | Count of Page 5 210 | {% endif %}" 211 | description: "Count of Page 5 to be used with Page 5 filter, if no filter is selected it shows all Pages" 212 | } 213 | 214 | measure: count_of_page_6 { 215 | view_label: "Page Funnel" 216 | type: sum 217 | sql: ${page_6_tag} ;; 218 | label: "{% if page_6_filter._in_query %} 219 | {{_filters['page_6_filter']}} 220 | {% else %} 221 | Count of Page 6 222 | {% endif %}" 223 | description: "Count of Page 6 to be used with Page 6 filter, if no filter is selected it shows all Pages" 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /dashboards/event_funnel.dashboard.lookml: -------------------------------------------------------------------------------- 1 | - dashboard: ga4_event_funnel 2 | title: "[GA4] Event Funnel" 3 | layout: newspaper 4 | preferred_viewer: dashboards-next 5 | elements: 6 | - title: Event Funnel 7 | name: Event Funnel 8 | model: ga4 9 | explore: sessions 10 | type: looker_column 11 | fields: [sessions.audience_trait, sessions.count_of_event_1, sessions.count_of_event_2, 12 | sessions.count_of_event_3, sessions.count_of_event_4, sessions.count_of_event_5, 13 | sessions.count_of_event_6] 14 | sorts: [sessions.count_of_event_1 desc] 15 | limit: 12 16 | x_axis_gridlines: false 17 | y_axis_gridlines: true 18 | show_view_names: false 19 | show_y_axis_labels: true 20 | show_y_axis_ticks: true 21 | y_axis_tick_density: default 22 | y_axis_tick_density_custom: 5 23 | show_x_axis_label: true 24 | show_x_axis_ticks: true 25 | y_axis_scale_mode: linear 26 | x_axis_reversed: false 27 | y_axis_reversed: false 28 | plot_size_by_field: false 29 | trellis: row 30 | stacking: '' 31 | limit_displayed_rows: false 32 | legend_position: center 33 | point_style: none 34 | show_value_labels: false 35 | label_density: 25 36 | x_axis_scale: auto 37 | y_axis_combined: true 38 | ordering: none 39 | show_null_labels: false 40 | show_totals_labels: false 41 | show_silhouette: false 42 | totals_color: "#808080" 43 | series_types: {} 44 | show_dropoff: true 45 | defaults_version: 1 46 | hidden_fields: [] 47 | y_axes: [] 48 | listen: 49 | Landing Page: sessions.landing_page 50 | Audience Selector: sessions.audience_selector 51 | Event 1: sessions.event_1_filter 52 | Event 2: sessions.event_2_filter 53 | Event 3: sessions.event_3_filter 54 | Event 4: sessions.event_4_filter 55 | Event 5: sessions.event_5_filter 56 | Event 6: sessions.event_6_filter 57 | Goal Event: events.event_name 58 | row: 4 59 | col: 0 60 | width: 24 61 | height: 14 62 | - name: '' 63 | type: text 64 | title_text: '' 65 | subtitle_text: '' 66 | body_text: "
\n\t
\n\t\t

GA4 Event Flow Event Funnel

What\ 68 | \ are customers clicking on our site?\n
Recommended Action\U0001f447\ 69 | \ Update the filters above to create your own custom event flow. Alter the audience\ 70 | \ cohort to dynamically view your funnel.

\n
" 71 | row: 0 72 | col: 0 73 | width: 24 74 | height: 4 75 | - name: " (2)" 76 | type: text 77 | title_text: '' 78 | subtitle_text: '' 79 | body_text: "
\n\t

Customer Event Flow

What are customers clicking before our conversion event?
\nRecommended\ 82 | \ Action\U0001f447 Use the Goal Event filter at the top to choose a conversion\ 83 | \ event.\n

\n
" 84 | row: 18 85 | col: 0 86 | width: 24 87 | height: 4 88 | - title: Event Action % of Total Funnel 89 | name: Event Action % of Total Funnel 90 | model: ga4 91 | explore: sessions 92 | type: looker_column 93 | fields: [sessions.count_of_event_1, sessions.count_of_event_2, sessions.count_of_event_3, 94 | sessions.count_of_event_4, sessions.count_of_event_5, sessions.count_of_event_6] 95 | sorts: [sessions.count_of_event_1 desc] 96 | limit: 12 97 | x_axis_gridlines: false 98 | y_axis_gridlines: true 99 | show_view_names: false 100 | show_y_axis_labels: true 101 | show_y_axis_ticks: true 102 | y_axis_tick_density: default 103 | y_axis_tick_density_custom: 5 104 | show_x_axis_label: true 105 | show_x_axis_ticks: true 106 | y_axis_scale_mode: linear 107 | x_axis_reversed: false 108 | y_axis_reversed: false 109 | plot_size_by_field: false 110 | trellis: '' 111 | stacking: '' 112 | limit_displayed_rows: false 113 | legend_position: center 114 | point_style: none 115 | show_value_labels: false 116 | label_density: 25 117 | x_axis_scale: auto 118 | y_axis_combined: true 119 | ordering: none 120 | show_null_labels: false 121 | show_totals_labels: false 122 | show_silhouette: false 123 | totals_color: "#808080" 124 | series_types: {} 125 | show_dropoff: true 126 | defaults_version: 1 127 | hidden_fields: [] 128 | y_axes: [] 129 | listen: 130 | Landing Page: sessions.landing_page 131 | Audience Selector: sessions.audience_selector 132 | Event 1: sessions.event_1_filter 133 | Event 2: sessions.event_2_filter 134 | Event 3: sessions.event_3_filter 135 | Event 4: sessions.event_4_filter 136 | Event 5: sessions.event_5_filter 137 | Event 6: sessions.event_6_filter 138 | Goal Event: events.event_name 139 | row: 22 140 | col: 0 141 | width: 24 142 | height: 8 143 | - title: Event Flow 144 | name: Event Flow 145 | model: ga4 146 | explore: sessions 147 | type: looker_grid 148 | fields: [events.event_name, events.current_event_plus_1, events.current_event_plus_2, 149 | events.current_event_plus_3, events.current_event_plus_4, events.current_event_plus_5, 150 | events.current_event_plus_6, sessions.total_sessions] 151 | sorts: [sessions.total_sessions desc] 152 | limit: 12 153 | show_view_names: false 154 | show_row_numbers: true 155 | transpose: false 156 | truncate_text: true 157 | hide_totals: false 158 | hide_row_totals: false 159 | size_to_fit: true 160 | table_theme: white 161 | limit_displayed_rows: false 162 | enable_conditional_formatting: false 163 | header_text_alignment: left 164 | header_font_size: 12 165 | rows_font_size: 12 166 | conditional_formatting_include_totals: false 167 | conditional_formatting_include_nulls: false 168 | x_axis_gridlines: false 169 | y_axis_gridlines: true 170 | show_y_axis_labels: true 171 | show_y_axis_ticks: true 172 | y_axis_tick_density: default 173 | y_axis_tick_density_custom: 5 174 | show_x_axis_label: true 175 | show_x_axis_ticks: true 176 | y_axis_scale_mode: linear 177 | x_axis_reversed: false 178 | y_axis_reversed: false 179 | plot_size_by_field: false 180 | trellis: '' 181 | stacking: '' 182 | legend_position: center 183 | point_style: none 184 | show_value_labels: false 185 | label_density: 25 186 | x_axis_scale: auto 187 | y_axis_combined: true 188 | ordering: none 189 | show_null_labels: false 190 | show_totals_labels: false 191 | show_silhouette: false 192 | totals_color: "#808080" 193 | series_types: {} 194 | show_dropoff: true 195 | defaults_version: 1 196 | hidden_fields: [] 197 | y_axes: [] 198 | listen: 199 | Landing Page: sessions.landing_page 200 | Audience Selector: sessions.audience_selector 201 | Goal Event: events.event_name 202 | row: 30 203 | col: 0 204 | width: 24 205 | height: 7 206 | filters: 207 | - name: Landing Page 208 | title: Landing Page 209 | type: field_filter 210 | default_value: '' 211 | allow_multiple_values: true 212 | required: false 213 | ui_config: 214 | type: tag_list 215 | display: popover 216 | options: [] 217 | model: ga4 218 | explore: sessions 219 | listens_to_filters: [] 220 | field: sessions.landing_page 221 | - name: Event 1 222 | title: Event 1 223 | type: field_filter 224 | default_value: '' 225 | allow_multiple_values: true 226 | required: false 227 | ui_config: 228 | type: tag_list 229 | display: popover 230 | options: [] 231 | model: ga4 232 | explore: sessions 233 | listens_to_filters: [] 234 | field: sessions.event_1_filter 235 | - name: Event 2 236 | title: Event 2 237 | type: field_filter 238 | default_value: '' 239 | allow_multiple_values: true 240 | required: false 241 | ui_config: 242 | type: tag_list 243 | display: popover 244 | options: [] 245 | model: ga4 246 | explore: sessions 247 | listens_to_filters: [] 248 | field: sessions.event_2_filter 249 | - name: Event 3 250 | title: Event 3 251 | type: field_filter 252 | default_value: '' 253 | allow_multiple_values: true 254 | required: false 255 | ui_config: 256 | type: tag_list 257 | display: popover 258 | options: [] 259 | model: ga4 260 | explore: sessions 261 | listens_to_filters: [] 262 | field: sessions.event_3_filter 263 | - name: Event 4 264 | title: Event 4 265 | type: field_filter 266 | default_value: '' 267 | allow_multiple_values: true 268 | required: false 269 | ui_config: 270 | type: tag_list 271 | display: popover 272 | options: [] 273 | model: ga4 274 | explore: sessions 275 | listens_to_filters: [] 276 | field: sessions.event_4_filter 277 | - name: Event 5 278 | title: Event 5 279 | type: field_filter 280 | default_value: '' 281 | allow_multiple_values: true 282 | required: false 283 | ui_config: 284 | type: tag_list 285 | display: popover 286 | options: [] 287 | model: ga4 288 | explore: sessions 289 | listens_to_filters: [] 290 | field: sessions.event_5_filter 291 | - name: Event 6 292 | title: Event 6 293 | type: field_filter 294 | default_value: '' 295 | allow_multiple_values: true 296 | required: false 297 | ui_config: 298 | type: tag_list 299 | display: popover 300 | options: [] 301 | model: ga4 302 | explore: sessions 303 | listens_to_filters: [] 304 | field: sessions.event_6_filter 305 | - name: Goal Event 306 | title: Goal Event 307 | type: field_filter 308 | default_value: '' 309 | allow_multiple_values: true 310 | required: false 311 | ui_config: 312 | type: tag_list 313 | display: popover 314 | options: [] 315 | model: ga4 316 | explore: sessions 317 | listens_to_filters: [] 318 | field: events.event_name 319 | - name: Audience Selector 320 | title: Audience Selector 321 | type: field_filter 322 | default_value: Device 323 | allow_multiple_values: true 324 | required: false 325 | ui_config: 326 | type: dropdown_menu 327 | display: inline 328 | options: [] 329 | model: ga4 330 | explore: sessions 331 | listens_to_filters: [] 332 | field: sessions.audience_selector -------------------------------------------------------------------------------- /dashboards/page_funnel.dashboard.lookml: -------------------------------------------------------------------------------- 1 | 2 | - dashboard: ga4_page_funnel 3 | title: "[GA4] Page Funnel" 4 | layout: newspaper 5 | preferred_viewer: dashboards-next 6 | elements: 7 | - title: Page Funnel 8 | name: Page Funnel 9 | model: ga4 10 | explore: sessions 11 | type: looker_column 12 | fields: [sessions.audience_trait, sessions.count_of_page_1, sessions.count_of_page_2, 13 | sessions.count_of_page_3, sessions.count_of_page_4, sessions.count_of_page_5, 14 | sessions.count_of_page_6] 15 | limit: 12 16 | x_axis_gridlines: false 17 | y_axis_gridlines: true 18 | show_view_names: false 19 | show_y_axis_labels: true 20 | show_y_axis_ticks: true 21 | y_axis_tick_density: default 22 | y_axis_tick_density_custom: 5 23 | show_x_axis_label: true 24 | show_x_axis_ticks: true 25 | y_axis_scale_mode: linear 26 | x_axis_reversed: false 27 | y_axis_reversed: false 28 | plot_size_by_field: false 29 | trellis: row 30 | stacking: '' 31 | limit_displayed_rows: false 32 | legend_position: center 33 | point_style: none 34 | show_value_labels: false 35 | label_density: 25 36 | x_axis_scale: auto 37 | y_axis_combined: true 38 | ordering: none 39 | show_null_labels: false 40 | show_totals_labels: false 41 | show_silhouette: false 42 | totals_color: "#808080" 43 | series_types: {} 44 | show_dropoff: true 45 | defaults_version: 1 46 | hidden_fields: [] 47 | y_axes: [] 48 | listen: 49 | Session Date: sessions.session_date 50 | Host Name: events.event_param_host 51 | Audience Selector: sessions.audience_selector 52 | Page 3: sessions.page_3_filter 53 | Page 2: sessions.page_2_filter 54 | Page 1: sessions.page_1_filter 55 | Page 4: sessions.page_4_filter 56 | Page 5: sessions.page_5_filter 57 | Page 6: sessions.page_6_filter 58 | row: 4 59 | col: 0 60 | width: 24 61 | height: 14 62 | - name: '' 63 | type: text 64 | title_text: '' 65 | subtitle_text: '' 66 | body_text: "
\n\t
\n\t\t

GA4 Page Pathing Page Funnel

How\ 68 | \ are customers moving through our site?
Recommended Action\U0001f447\ 69 | Update the filters above to create your own custom path pathing funnel. Then\ 70 | \ link from any page in the funnel to see what actions occur on that page.

\n\ 71 |
" 72 | row: 0 73 | col: 0 74 | width: 24 75 | height: 4 76 | - name: " (2)" 77 | type: text 78 | title_text: '' 79 | subtitle_text: '' 80 | body_text: "
\n\t

Page Path Funnel

How\ 82 | \ are people moving through the website as a % of Total
\nRecommended\ 83 | \ Action\U0001f447 Use the page filters at the top to define the different\ 84 | \ steps in the funnel.\n

\n
" 85 | row: 18 86 | col: 0 87 | width: 24 88 | height: 4 89 | - title: Page Path Funnel % of Total 90 | name: Page Path Funnel % of Total 91 | model: ga4 92 | explore: sessions 93 | type: looker_column 94 | fields: [sessions.count_of_page_1, sessions.count_of_page_2, sessions.count_of_page_3, 95 | sessions.count_of_page_4, sessions.count_of_page_5, sessions.count_of_page_6] 96 | limit: 12 97 | x_axis_gridlines: false 98 | y_axis_gridlines: true 99 | show_view_names: false 100 | show_y_axis_labels: true 101 | show_y_axis_ticks: true 102 | y_axis_tick_density: default 103 | y_axis_tick_density_custom: 5 104 | show_x_axis_label: true 105 | show_x_axis_ticks: true 106 | y_axis_scale_mode: linear 107 | x_axis_reversed: false 108 | y_axis_reversed: false 109 | plot_size_by_field: false 110 | trellis: '' 111 | stacking: '' 112 | limit_displayed_rows: false 113 | legend_position: center 114 | point_style: none 115 | show_value_labels: false 116 | label_density: 25 117 | x_axis_scale: auto 118 | y_axis_combined: true 119 | ordering: none 120 | show_null_labels: false 121 | show_totals_labels: false 122 | show_silhouette: false 123 | totals_color: "#808080" 124 | series_types: {} 125 | show_dropoff: true 126 | defaults_version: 1 127 | hidden_fields: [] 128 | y_axes: [] 129 | listen: 130 | Session Date: sessions.session_date 131 | Host Name: events.event_param_host 132 | Audience Selector: sessions.audience_selector 133 | Page 3: sessions.page_3_filter 134 | Page 2: sessions.page_2_filter 135 | Page 1: sessions.page_1_filter 136 | Page 4: sessions.page_4_filter 137 | Page 5: sessions.page_5_filter 138 | Page 6: sessions.page_6_filter 139 | row: 22 140 | col: 0 141 | width: 24 142 | height: 8 143 | - title: Top Page Paths 144 | name: Top Page Paths 145 | model: ga4 146 | explore: sessions 147 | type: looker_grid 148 | fields: [sessions.total_sessions, events.event_param_page, events.current_page_plus_1, 149 | events.current_page_plus_2, events.current_page_plus_3, events.current_page_plus_4, 150 | events.current_page_plus_5, events.current_page_plus_6] 151 | sorts: [sessions.total_sessions desc] 152 | limit: 12 153 | show_view_names: false 154 | show_row_numbers: true 155 | transpose: false 156 | truncate_text: true 157 | hide_totals: false 158 | hide_row_totals: false 159 | size_to_fit: true 160 | table_theme: white 161 | limit_displayed_rows: false 162 | enable_conditional_formatting: false 163 | header_text_alignment: left 164 | header_font_size: 12 165 | rows_font_size: 12 166 | conditional_formatting_include_totals: false 167 | conditional_formatting_include_nulls: false 168 | x_axis_gridlines: false 169 | y_axis_gridlines: true 170 | show_y_axis_labels: true 171 | show_y_axis_ticks: true 172 | y_axis_tick_density: default 173 | y_axis_tick_density_custom: 5 174 | show_x_axis_label: true 175 | show_x_axis_ticks: true 176 | y_axis_scale_mode: linear 177 | x_axis_reversed: false 178 | y_axis_reversed: false 179 | plot_size_by_field: false 180 | trellis: '' 181 | stacking: '' 182 | legend_position: center 183 | point_style: none 184 | show_value_labels: false 185 | label_density: 25 186 | x_axis_scale: auto 187 | y_axis_combined: true 188 | ordering: none 189 | show_null_labels: false 190 | show_totals_labels: false 191 | show_silhouette: false 192 | totals_color: "#808080" 193 | series_types: {} 194 | show_dropoff: true 195 | defaults_version: 1 196 | hidden_fields: [] 197 | y_axes: [] 198 | listen: 199 | Session Date: sessions.session_date 200 | Host Name: events.event_param_host 201 | Audience Selector: sessions.audience_selector 202 | row: 34 203 | col: 0 204 | width: 24 205 | height: 7 206 | - name: " (3)" 207 | type: text 208 | title_text: '' 209 | subtitle_text: '' 210 | body_text: "
\n\t

Natural Page Path

How\ 212 | \ are users naturally flowing through the site?
\nRecommended Action\U0001f447\ 213 | \ Drill in to see the breakdown by source medium.\n

\n
" 214 | row: 30 215 | col: 0 216 | width: 24 217 | height: 4 218 | filters: 219 | - name: Session Date 220 | title: Session Date 221 | type: field_filter 222 | default_value: 7 day 223 | allow_multiple_values: true 224 | required: false 225 | ui_config: 226 | type: relative_timeframes 227 | display: inline 228 | options: [] 229 | model: ga4 230 | explore: sessions 231 | listens_to_filters: [] 232 | field: sessions.session_date 233 | - name: Host Name 234 | title: Host Name 235 | type: field_filter 236 | default_value: '' 237 | allow_multiple_values: true 238 | required: false 239 | ui_config: 240 | type: tag_list 241 | display: popover 242 | options: [] 243 | model: ga4 244 | explore: sessions 245 | listens_to_filters: [] 246 | field: events.event_param_host 247 | - name: Page 1 248 | title: Page 1 249 | type: field_filter 250 | default_value: '' 251 | allow_multiple_values: true 252 | required: false 253 | ui_config: 254 | type: tag_list 255 | display: popover 256 | options: [] 257 | model: ga4 258 | explore: sessions 259 | listens_to_filters: [] 260 | field: sessions.page_1_filter 261 | - name: Page 2 262 | title: Page 2 263 | type: field_filter 264 | default_value: '' 265 | allow_multiple_values: true 266 | required: false 267 | ui_config: 268 | type: tag_list 269 | display: popover 270 | options: [] 271 | model: ga4 272 | explore: sessions 273 | listens_to_filters: [] 274 | field: sessions.page_2_filter 275 | - name: Page 3 276 | title: Page 3 277 | type: field_filter 278 | default_value: '' 279 | allow_multiple_values: true 280 | required: false 281 | ui_config: 282 | type: tag_list 283 | display: popover 284 | options: [] 285 | model: ga4 286 | explore: sessions 287 | listens_to_filters: [] 288 | field: sessions.page_3_filter 289 | - name: Page 4 290 | title: Page 4 291 | type: field_filter 292 | default_value: '' 293 | allow_multiple_values: true 294 | required: false 295 | ui_config: 296 | type: tag_list 297 | display: popover 298 | options: [] 299 | model: ga4 300 | explore: sessions 301 | listens_to_filters: [] 302 | field: sessions.page_4_filter 303 | - name: Page 5 304 | title: Page 5 305 | type: field_filter 306 | default_value: '' 307 | allow_multiple_values: true 308 | required: false 309 | ui_config: 310 | type: tag_list 311 | display: popover 312 | options: [] 313 | model: ga4 314 | explore: sessions 315 | listens_to_filters: [] 316 | field: sessions.page_5_filter 317 | - name: Page 6 318 | title: Page 6 319 | type: field_filter 320 | default_value: '' 321 | allow_multiple_values: true 322 | required: false 323 | ui_config: 324 | type: tag_list 325 | display: popover 326 | options: [] 327 | model: ga4 328 | explore: sessions 329 | listens_to_filters: [] 330 | field: sessions.page_6_filter 331 | - name: Audience Selector 332 | title: Audience Selector 333 | type: field_filter 334 | default_value: Device 335 | allow_multiple_values: true 336 | required: false 337 | ui_config: 338 | type: dropdown_menu 339 | display: inline 340 | options: [] 341 | model: ga4 342 | explore: sessions 343 | listens_to_filters: [] 344 | field: sessions.audience_selector -------------------------------------------------------------------------------- /views/event_data_dimensions/event_path.view.lkml: -------------------------------------------------------------------------------- 1 | ## Purpose: This view is for defining the "Event Path" dimensions, it is extended into events.view 2 | 3 | ## The default Event Path is comprised of the Event Name and the Page Location URL Path. 4 | ## In the SQL definitions below, the Event Name is called by "event_history.event_name" 5 | ## The Page Location URL Path is called by coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 6 | ## It is likely that additional customization of the event path will be required after non-default GA4 Tags are added to your event parameters. 7 | ## Using the [ (select value.value_type from UNNEST(event_params) where key = "GA4_TAG") ] format will facilitate adding these new tags to the event path. 8 | 9 | view: event_path { 10 | extension: required 11 | 12 | ## Event Path Dimensions 13 | dimension: event_path_1 { 14 | view_label: "Event Flow" 15 | group_label: "Event Path" 16 | description: "1st Event in Session." 17 | type: string 18 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 19 | from UNNEST(${sessions.event_data}) as event_history 20 | where event_history.event_rank = 1 limit 1) ;; 21 | #sql: case when ${event_rank} = 1 then ${full_event} else null end ;; 22 | full_suggestions: yes 23 | } 24 | dimension: event_path_2 { 25 | view_label: "Event Flow" 26 | group_label: "Event Path" 27 | description: "2nd Event in Session." 28 | type: string 29 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 30 | from UNNEST(${sessions.event_data}) as event_history 31 | where event_history.event_rank = 2 limit 1) ;; 32 | #sql: case when ${event_rank} = 2 then ${full_event} else null end ;; 33 | full_suggestions: yes 34 | } 35 | dimension: event_path_3 { 36 | view_label: "Event Flow" 37 | group_label: "Event Path" 38 | description: "3rd Event in Session." 39 | type: string 40 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 41 | from UNNEST(${sessions.event_data}) as event_history 42 | where event_history.event_rank = 3 limit 1) ;; 43 | # sql: case when ${event_rank} = 3 then ${full_event} else null end ;; 44 | full_suggestions: yes 45 | } 46 | dimension: event_path_4 { 47 | view_label: "Event Flow" 48 | group_label: "Event Path" 49 | description: "4th Event in Session." 50 | type: string 51 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 52 | from UNNEST(${sessions.event_data}) as event_history 53 | where event_history.event_rank = 4 limit 1) ;; 54 | # sql: case when ${event_rank} = 4 then ${full_event} else null end ;; 55 | full_suggestions: yes 56 | } 57 | dimension: event_path_5 { 58 | view_label: "Event Flow" 59 | group_label: "Event Path" 60 | description: "5th Event in Session." 61 | type: string 62 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 63 | from UNNEST(${sessions.event_data}) as event_history 64 | where event_history.event_rank = 5 limit 1) ;; 65 | # sql: case when ${event_rank} = 5 then ${full_event} else null end ;; 66 | full_suggestions: yes 67 | } 68 | dimension: event_path_6 { 69 | view_label: "Event Flow" 70 | group_label: "Event Path" 71 | description: "6th Event in Session." 72 | type: string 73 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 74 | from UNNEST(${sessions.event_data}) as event_history 75 | where event_history.event_rank = 6 limit 1) ;; 76 | # sql: case when ${event_rank} = 6 then ${full_event} else null end ;; 77 | full_suggestions: yes 78 | } 79 | dimension: event_path_7 { 80 | view_label: "Event Flow" 81 | group_label: "Event Path" 82 | description: "7th Event in Session." 83 | type: string 84 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 85 | from UNNEST(${sessions.event_data}) as event_history 86 | where event_history.event_rank = 7 limit 1) ;; 87 | # sql: case when ${event_rank} = 7 then ${full_event} else null end ;; 88 | full_suggestions: yes 89 | } 90 | dimension: event_path_8 { 91 | view_label: "Event Flow" 92 | group_label: "Event Path" 93 | description: "8th Event in Session." 94 | type: string 95 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 96 | from UNNEST(${sessions.event_data}) as event_history 97 | where event_history.event_rank = 8 limit 1) ;; 98 | # sql: case when ${event_rank} = 8 then ${full_event} else null end ;; 99 | full_suggestions: yes 100 | } 101 | dimension: event_path_9 { 102 | view_label: "Event Flow" 103 | group_label: "Event Path" 104 | description: "9th Event in Session." 105 | type: string 106 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 107 | from UNNEST(${sessions.event_data}) as event_history 108 | where event_history.event_rank = 9 limit 1) ;; 109 | # sql: case when ${event_rank} = 9 then ${full_event} else null end ;; 110 | full_suggestions: yes 111 | } 112 | 113 | ## Relative full_event Path Dimensions 114 | dimension: current_event_plus_1 { 115 | view_label: "Event Flow" 116 | group_label: "Relative Event Path" 117 | description: "Event Path for Event that came directly before current Event." 118 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 119 | from UNNEST(${sessions.event_data}) as event_history 120 | where event_history.event_rank = (${TABLE}.event_rank + 1) limit 1) ;; 121 | full_suggestions: yes 122 | type: string 123 | } 124 | dimension: current_event_plus_2 { 125 | view_label: "Event Flow" 126 | group_label: "Relative Event Path" 127 | description: "Event Path for Event that came 2 Events before current Event." 128 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 129 | from UNNEST(${sessions.event_data}) as event_history 130 | where event_history.event_rank = (${TABLE}.event_rank + 2) limit 1) ;; 131 | full_suggestions: yes 132 | type: string 133 | } 134 | dimension: current_event_plus_3 { 135 | view_label: "Event Flow" 136 | group_label: "Relative Event Path" 137 | description: "Event Path for Event that came 3 Events before current Event." 138 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 139 | from UNNEST(${sessions.event_data}) as event_history 140 | where event_history.event_rank = (${TABLE}.event_rank + 3) limit 1) ;; 141 | full_suggestions: yes 142 | type: string 143 | } 144 | dimension: current_event_plus_4 { 145 | view_label: "Event Flow" 146 | group_label: "Relative Event Path" 147 | description: "Event Path for Event that came 4 Events before current Event." 148 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 149 | from UNNEST(${sessions.event_data}) as event_history 150 | where event_history.event_rank = (${TABLE}.event_rank + 4) limit 1) ;; 151 | full_suggestions: yes 152 | type: string 153 | } 154 | dimension: current_event_plus_5 { 155 | view_label: "Event Flow" 156 | group_label: "Relative Event Path" 157 | description: "Event Path for Event that came 5 Events before current Event." 158 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 159 | from UNNEST(${sessions.event_data}) as event_history 160 | where event_history.event_rank = (${TABLE}.event_rank + 5) limit 1) ;; 161 | full_suggestions: yes 162 | type: string 163 | } 164 | dimension: current_event_plus_6 { 165 | view_label: "Event Flow" 166 | group_label: "Relative Event Path" 167 | description: "Event Path for Event that came 6 Events before current Event." 168 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 169 | from UNNEST(${sessions.event_data}) as event_history 170 | where event_history.event_rank = (${TABLE}.event_rank + 6) limit 1) ;; 171 | full_suggestions: yes 172 | type: string 173 | } 174 | dimension: current_event_plus_7 { 175 | view_label: "Event Flow" 176 | group_label: "Relative Event Path" 177 | description: "Event Path for Event that came 7 Events before current Event." 178 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 179 | from UNNEST(${sessions.event_data}) as event_history 180 | where event_history.event_rank = (${TABLE}.event_rank + 7) limit 1) ;; 181 | full_suggestions: yes 182 | type: string 183 | } 184 | dimension: current_event_plus_8 { 185 | view_label: "Event Flow" 186 | group_label: "Relative Event Path" 187 | description: "Event Path for Event that came 8 Events before current Event." 188 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 189 | from UNNEST(${sessions.event_data}) as event_history 190 | where event_history.event_rank = (${TABLE}.event_rank + 8) limit 1) ;; 191 | full_suggestions: yes 192 | type: string 193 | } 194 | dimension: current_event_plus_9 { 195 | view_label: "Event Flow" 196 | group_label: "Relative Event Path" 197 | description: "Event Path for Event that came 9 Events before current Event." 198 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 199 | from UNNEST(${sessions.event_data}) as event_history 200 | where event_history.event_rank = (${TABLE}.event_rank + 9) limit 1) ;; 201 | full_suggestions: yes 202 | type: string 203 | } 204 | 205 | ## Reverse full_event Path Dimensions 206 | 207 | dimension: current_event_minus_1 { 208 | view_label: "Event Flow" 209 | group_label: "Reverse Event Path" 210 | description: "Event Path for Event that came directly after current Event." 211 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 212 | from UNNEST(${sessions.event_data}) as event_history 213 | where event_history.event_rank = (${TABLE}.event_rank - 1) limit 1) ;; 214 | full_suggestions: yes 215 | type: string 216 | } 217 | dimension: current_event_minus_2 { 218 | view_label: "Event Flow" 219 | group_label: "Reverse Event Path" 220 | description: "Event Path for Event that came 2 Events after current Event." 221 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 222 | from UNNEST(${sessions.event_data}) as event_history 223 | where event_history.event_rank = (${TABLE}.event_rank - 2) limit 1) ;; 224 | full_suggestions: yes 225 | type: string 226 | } 227 | dimension: current_event_minus_3 { 228 | view_label: "Event Flow" 229 | group_label: "Reverse Event Path" 230 | description: "Event Path for Event that came 3 Events after current Event." 231 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 232 | from UNNEST(${sessions.event_data}) as event_history 233 | where event_history.event_rank = (${TABLE}.event_rank - 3) limit 1) ;; 234 | full_suggestions: yes 235 | type: string 236 | } 237 | dimension: current_event_minus_4 { 238 | view_label: "Event Flow" 239 | group_label: "Reverse Event Path" 240 | description: "Event Path for Event that came 4 Events after current Event." 241 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 242 | from UNNEST(${sessions.event_data}) as event_history 243 | where event_history.event_rank = (${TABLE}.event_rank - 4) limit 1) ;; 244 | full_suggestions: yes 245 | type: string 246 | } 247 | dimension: current_event_minus_5 { 248 | view_label: "Event Flow" 249 | group_label: "Reverse Event Path" 250 | description: "Event Path for Event that came 5 Events after current Event." 251 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 252 | from UNNEST(${sessions.event_data}) as event_history 253 | where event_history.event_rank = (${TABLE}.event_rank - 5) limit 1) ;; 254 | full_suggestions: yes 255 | type: string 256 | } 257 | dimension: current_event_minus_6 { 258 | view_label: "Event Flow" 259 | group_label: "Reverse Event Path" 260 | description: "Event Path for Event that came 6 Events after current Event." 261 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 262 | from UNNEST(${sessions.event_data}) as event_history 263 | where event_history.event_rank = (${TABLE}.event_rank - 6) limit 1) ;; 264 | full_suggestions: yes 265 | type: string 266 | } 267 | dimension: current_event_minus_7 { 268 | view_label: "Event Flow" 269 | group_label: "Reverse Event Path" 270 | description: "Event Path for Event that came 7 Events after current Event." 271 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 272 | from UNNEST(${sessions.event_data}) as event_history 273 | where event_history.event_rank = (${TABLE}.event_rank - 7) limit 1) ;; 274 | full_suggestions: yes 275 | type: string 276 | } 277 | dimension: current_event_minus_8 { 278 | view_label: "Event Flow" 279 | group_label: "Reverse Event Path" 280 | description: "Event Path for Event that came 8 Events after current Event." 281 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 282 | from UNNEST(${sessions.event_data}) as event_history 283 | where event_history.event_rank = (${TABLE}.event_rank - 8) limit 1) ;; 284 | full_suggestions: yes 285 | type: string 286 | } 287 | dimension: current_event_minus_9 { 288 | view_label: "Event Flow" 289 | group_label: "Reverse Event Path" 290 | description: "Event Path for Event that came 9 Events after current Event." 291 | sql: (select event_history.event_name||': '||coalesce(coalesce(regexp_extract((select value.string_value from UNNEST(event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?#]+)"),'/'),"") 292 | from UNNEST(${sessions.event_data}) as event_history 293 | where event_history.event_rank = (${TABLE}.event_rank - 9) limit 1) ;; 294 | full_suggestions: yes 295 | type: string 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /views/events.view.lkml: -------------------------------------------------------------------------------- 1 | ## PURPOSE: This view is for a convenient location to define dimensions and measures sourced from the event_data element in sessions. 2 | ## Event_Data represents the source event level rows from the GA Export Dataset. 3 | ## The following views are defined in this file: 4 | ## - event_data 5 | ## - event_data_event_params 6 | ## - event_data_user_properties 7 | ## - goals 8 | ## - page_data 9 | ## - event_path 10 | 11 | include: "event_data_dimensions/*.view" 12 | 13 | view: events { 14 | extends: [event_data_event_params, event_data_user_properties, goals, page_data, event_path] 15 | 16 | ## Dimensions 17 | 18 | dimension: ed_key { 19 | type: string 20 | primary_key: yes 21 | hidden: yes 22 | sql: ${sl_key}||${event_rank} ;; 23 | } 24 | 25 | dimension: sl_key { 26 | type: string 27 | hidden: yes 28 | sql: ${TABLE}.sl_key ;; 29 | } 30 | 31 | dimension: event_rank { 32 | label: "Event Rank" 33 | type: number 34 | sql: ${TABLE}.event_rank ;; 35 | description: "Event Rank in Session, 1st Event = Event Rank 1." 36 | full_suggestions: yes 37 | } 38 | 39 | dimension: reverse_event_rank { 40 | label: "Reverse Event Rank" 41 | type: number 42 | sql: ${TABLE}.reverse_event_rank ;; 43 | description: "Reverse Event Rank in Session. Last Event = Reverse Event Rank 1." 44 | full_suggestions: yes 45 | } 46 | 47 | # dimension_group: event { 48 | # label: "Event" 49 | # type: time 50 | # timeframes: [date,day_of_month,day_of_week,day_of_week_index,day_of_year,month,month_name,month_num,fiscal_quarter,fiscal_quarter_of_year,year] 51 | # sql: ${TABLE}.event_date ;; 52 | # } 53 | 54 | dimension_group: event_time { 55 | type: time 56 | timeframes: [date,day_of_month,day_of_week,day_of_week_index,day_of_year,month,month_name,month_num,fiscal_quarter,fiscal_quarter_of_year,year,time,hour,hour_of_day] 57 | label: "Event" 58 | sql: TIMESTAMP_MICROS(${TABLE}.event_timestamp) ;; 59 | description: "Event Date/Time from Event Timestamp." 60 | } 61 | 62 | dimension: event_timestamp { hidden: yes sql: ${TABLE}.event_timestamp ;; } 63 | 64 | dimension: time_to_next_event { 65 | label: "Time on Event" 66 | description: "Time user spent on Event, measured as duration from event to the subsequent event." 67 | sql: ${TABLE}.time_to_next_event ;; 68 | type: number 69 | value_format_name: hour_format 70 | } 71 | 72 | dimension: event_name { 73 | label: "Event Name" 74 | type: string 75 | sql: ${TABLE}.event_name ;; 76 | full_suggestions: yes 77 | } 78 | 79 | dimension: full_event { 80 | view_label: "Behavior" 81 | ## Customize with your specific event parameters that encompass the specific points of interest in your event. 82 | type: string 83 | sql: ${event_name}||': '||coalesce(${events.event_param_page},"") ;; 84 | full_suggestions: yes 85 | } 86 | 87 | dimension: event_bundle_sequence_id { 88 | type: number 89 | sql: ${TABLE}.event_bundle_sequence_id ;; 90 | full_suggestions: yes 91 | } 92 | 93 | dimension: event_dimensions__hostname { 94 | type: string 95 | sql: ${TABLE}.event_dimensions.hostname ;; 96 | group_label: "Event Dimensions" 97 | group_item_label: "Hostname" 98 | full_suggestions: yes 99 | } 100 | 101 | dimension: event_previous_timestamp { 102 | type: number 103 | sql: ${TABLE}.event_previous_timestamp ;; 104 | full_suggestions: yes 105 | } 106 | 107 | dimension: event_server_timestamp_offset { 108 | type: number 109 | sql: ${TABLE}.event_server_timestamp_offset ;; 110 | full_suggestions: yes 111 | } 112 | 113 | dimension: event_value_in_usd { 114 | type: number 115 | sql: ${TABLE}.event_value_in_usd ;; 116 | full_suggestions: yes 117 | } 118 | 119 | dimension: items { 120 | hidden: yes 121 | sql: ${TABLE}.items ;; 122 | ## This is the parent dimension for the items fields within the event_data_items view. 123 | } 124 | 125 | dimension: platform { 126 | type: string 127 | sql: ${TABLE}.platform ;; 128 | full_suggestions: yes 129 | } 130 | dimension: stream_id { 131 | type: string 132 | sql: ${TABLE}.stream_id ;; 133 | full_suggestions: yes 134 | } 135 | 136 | ## App Info Fields 137 | dimension: app_info__firebase_app_id { 138 | type: string 139 | sql: ${TABLE}.app_info.firebase_app_id ;; 140 | full_suggestions: yes 141 | group_label: "App Info" 142 | group_item_label: "Firebase App ID" 143 | } 144 | 145 | dimension: app_info__id { 146 | type: string 147 | sql: ${TABLE}.app_info.id ;; 148 | full_suggestions: yes 149 | group_label: "App Info" 150 | group_item_label: "ID" 151 | } 152 | 153 | dimension: app_info__install_source { 154 | type: string 155 | sql: ${TABLE}.app_info.install_source ;; 156 | full_suggestions: yes 157 | group_label: "App Info" 158 | group_item_label: "Install Source" 159 | } 160 | 161 | dimension: app_info__install_store { 162 | type: string 163 | sql: ${TABLE}.app_info.install_store ;; 164 | full_suggestions: yes 165 | group_label: "App Info" 166 | group_item_label: "Install Store" 167 | } 168 | 169 | dimension: app_info__version { 170 | type: string 171 | sql: ${TABLE}.app_info.version ;; 172 | full_suggestions: yes 173 | group_label: "App Info" 174 | group_item_label: "Version" 175 | } 176 | 177 | 178 | ## Device Fields 179 | dimension: device__advertising_id { 180 | type: string 181 | sql: ${TABLE}.device.advertising_id ;; 182 | full_suggestions: yes 183 | group_label: "Device" 184 | group_item_label: "Advertising ID" 185 | } 186 | 187 | dimension: device__browser { 188 | type: string 189 | sql: ${TABLE}.device.browser ;; 190 | full_suggestions: yes 191 | group_label: "Device" 192 | group_item_label: "Browser" 193 | } 194 | 195 | dimension: device__browser_version { 196 | type: string 197 | sql: ${TABLE}.device.browser_version ;; 198 | full_suggestions: yes 199 | group_label: "Device" 200 | group_item_label: "Browser Version" 201 | } 202 | 203 | dimension: device__category { 204 | type: string 205 | sql: ${TABLE}.device.category ;; 206 | full_suggestions: yes 207 | group_label: "Device" 208 | group_item_label: "Category" 209 | } 210 | 211 | dimension: device__is_limited_ad_tracking { 212 | type: string 213 | sql: ${TABLE}.device.is_limited_ad_tracking ;; 214 | full_suggestions: yes 215 | group_label: "Device" 216 | group_item_label: "Is Limited Ad Tracking" 217 | } 218 | 219 | dimension: device__language { 220 | type: string 221 | sql: ${TABLE}.device.language ;; 222 | full_suggestions: yes 223 | group_label: "Device" 224 | group_item_label: "Language" 225 | } 226 | 227 | dimension: device__mobile_brand_name { 228 | type: string 229 | sql: ${TABLE}.device.mobile_brand_name ;; 230 | full_suggestions: yes 231 | group_label: "Device" 232 | group_item_label: "Mobile Brand Name" 233 | } 234 | 235 | dimension: device__mobile_marketing_name { 236 | type: string 237 | sql: ${TABLE}.device.mobile_marketing_name ;; 238 | full_suggestions: yes 239 | group_label: "Device" 240 | group_item_label: "Mobile Marketing Name" 241 | } 242 | 243 | dimension: device__mobile_model_name { 244 | type: string 245 | sql: ${TABLE}.device.mobile_model_name ;; 246 | full_suggestions: yes 247 | group_label: "Device" 248 | group_item_label: "Mobile Model Name" 249 | } 250 | 251 | dimension: device__mobile_os_hardware_model { 252 | type: string 253 | sql: ${TABLE}.device.mobile_os_hardware_model ;; 254 | full_suggestions: yes 255 | group_label: "Device" 256 | group_item_label: "Mobile OS Hardware Model" 257 | } 258 | 259 | dimension: device__operating_system { 260 | type: string 261 | sql: ${TABLE}.device.operating_system ;; 262 | full_suggestions: yes 263 | group_label: "Device" 264 | group_item_label: "Operating System" 265 | } 266 | 267 | dimension: device__operating_system_version { 268 | type: string 269 | sql: ${TABLE}.device.operating_system_version ;; 270 | full_suggestions: yes 271 | group_label: "Device" 272 | group_item_label: "Operating System Version" 273 | } 274 | 275 | dimension: device__time_zone_offset_seconds { 276 | type: number 277 | sql: ${TABLE}.device.time_zone_offset_seconds ;; 278 | group_label: "Device" 279 | group_item_label: "Time Zone Offset Seconds" 280 | } 281 | 282 | dimension: device__vendor_id { 283 | type: string 284 | sql: ${TABLE}.device.vendor_id ;; 285 | full_suggestions: yes 286 | group_label: "Device" 287 | group_item_label: "Vendor ID" 288 | } 289 | 290 | dimension: device__web_info__browser { 291 | type: string 292 | sql: ${TABLE}.device.web_info.browser ;; 293 | full_suggestions: yes 294 | group_label: "Device Web Info" 295 | group_item_label: "Browser" 296 | } 297 | 298 | dimension: device__web_info__browser_version { 299 | type: string 300 | sql: ${TABLE}.device.web_info.browser_version ;; 301 | full_suggestions: yes 302 | group_label: "Device Web Info" 303 | group_item_label: "Browser Version" 304 | } 305 | 306 | dimension: device__web_info__hostname { 307 | type: string 308 | sql: ${TABLE}.device.web_info.hostname ;; 309 | full_suggestions: yes 310 | group_label: "Device Web Info" 311 | group_item_label: "Hostname" 312 | } 313 | 314 | 315 | ## ECommerce Fields 316 | dimension: ecommerce__purchase_revenue { 317 | type: number 318 | sql: ${TABLE}.ecommerce.purchase_revenue ;; 319 | group_label: "Ecommerce" 320 | group_item_label: "Purchase Revenue" 321 | value_format_name: usd 322 | } 323 | 324 | dimension: ecommerce__purchase_revenue_in_usd { 325 | type: number 326 | sql: ${TABLE}.ecommerce.purchase_revenue_in_usd ;; 327 | group_label: "Ecommerce" 328 | group_item_label: "Purchase Revenue In USD" 329 | value_format_name: usd 330 | } 331 | 332 | dimension: ecommerce__refund_value { 333 | type: number 334 | sql: ${TABLE}.ecommerce.refund_value ;; 335 | group_label: "Ecommerce" 336 | group_item_label: "Refund Value" 337 | value_format_name: usd 338 | } 339 | 340 | dimension: ecommerce__refund_value_in_usd { 341 | type: number 342 | sql: ${TABLE}.ecommerce.refund_value_in_usd ;; 343 | group_label: "Ecommerce" 344 | group_item_label: "Refund Value In USD" 345 | value_format_name: usd 346 | } 347 | 348 | dimension: ecommerce__shipping_value { 349 | type: number 350 | sql: ${TABLE}.ecommerce.shipping_value ;; 351 | group_label: "Ecommerce" 352 | group_item_label: "Shipping Value" 353 | value_format_name: usd 354 | } 355 | 356 | dimension: ecommerce__shipping_value_in_usd { 357 | type: number 358 | sql: ${TABLE}.ecommerce.shipping_value_in_usd ;; 359 | group_label: "Ecommerce" 360 | group_item_label: "Shipping Value In USD" 361 | value_format_name: usd 362 | } 363 | 364 | dimension: ecommerce__tax_value { 365 | type: number 366 | sql: ${TABLE}.ecommerce.tax_value ;; 367 | group_label: "Ecommerce" 368 | group_item_label: "Tax Value" 369 | value_format_name: usd 370 | } 371 | 372 | dimension: ecommerce__tax_value_in_usd { 373 | type: number 374 | sql: ${TABLE}.ecommerce.tax_value_in_usd ;; 375 | group_label: "Ecommerce" 376 | group_item_label: "Tax Value In USD" 377 | value_format_name: usd 378 | } 379 | 380 | dimension: ecommerce__total_item_quantity { 381 | type: number 382 | sql: ${TABLE}.ecommerce.total_item_quantity ;; 383 | group_label: "Ecommerce" 384 | group_item_label: "Total Item Quantity" 385 | value_format_name: decimal_0 386 | } 387 | 388 | dimension: ecommerce__transaction_id { 389 | type: string 390 | sql: ${TABLE}.ecommerce.transaction_id ;; 391 | full_suggestions: yes 392 | group_label: "Ecommerce" 393 | group_item_label: "Transaction ID" 394 | } 395 | 396 | dimension: ecommerce__unique_items { 397 | type: number 398 | sql: ${TABLE}.ecommerce.unique_items ;; 399 | group_label: "Ecommerce" 400 | group_item_label: "Unique Items" 401 | value_format_name: decimal_0 402 | } 403 | 404 | 405 | ## Geo Fields 406 | dimension: geo__city { 407 | type: string 408 | sql: ${TABLE}.geo.city ;; 409 | full_suggestions: yes 410 | group_label: "Geo" 411 | group_item_label: "City" 412 | } 413 | 414 | dimension: geo__continent { 415 | type: string 416 | sql: ${TABLE}.geo.continent ;; 417 | full_suggestions: yes 418 | group_label: "Geo" 419 | group_item_label: "Continent" 420 | } 421 | 422 | dimension: geo__country { 423 | type: string 424 | sql: ${TABLE}.geo.country ;; 425 | full_suggestions: yes 426 | group_label: "Geo" 427 | group_item_label: "Country" 428 | map_layer_name: countries 429 | } 430 | 431 | dimension: geo__metro { 432 | type: string 433 | sql: ${TABLE}.geo.metro ;; 434 | full_suggestions: yes 435 | group_label: "Geo" 436 | group_item_label: "Metro" 437 | } 438 | 439 | dimension: geo__region { 440 | type: string 441 | sql: ${TABLE}.geo.region ;; 442 | full_suggestions: yes 443 | group_label: "Geo" 444 | group_item_label: "Region" 445 | map_layer_name: us_states 446 | } 447 | 448 | dimension: geo__sub_continent { 449 | type: string 450 | sql: ${TABLE}.geo.sub_continent ;; 451 | full_suggestions: yes 452 | group_label: "Geo" 453 | group_item_label: "Sub Continent" 454 | } 455 | 456 | 457 | ## Traffic Source Fields 458 | dimension: traffic_source__medium { 459 | view_label: "Acquisition" 460 | type: string 461 | sql: ${TABLE}.traffic_source.medium ;; 462 | full_suggestions: yes 463 | group_label: "User Traffic Source" 464 | group_item_label: "Medium" 465 | description: "The medium of the traffic source for the user's original first visit (Saved up to 1 Year by Default)." 466 | } 467 | 468 | dimension: traffic_source__name { 469 | view_label: "Acquisition" 470 | type: string 471 | sql: ${TABLE}.traffic_source.name ;; 472 | full_suggestions: yes 473 | group_label: "User Traffic Source" 474 | description: "The name of the traffic source for the user's original first visit (Saved up to 1 Year by Default)." 475 | group_item_label: "Name" 476 | } 477 | 478 | dimension: traffic_source__source { 479 | view_label: "Acquisition" 480 | type: string 481 | sql: ${TABLE}.traffic_source.source ;; 482 | full_suggestions: yes 483 | group_label: "User Traffic Source" 484 | group_item_label: "Source" 485 | description: "The source of the traffic source for the user's original first visit (Saved up to 1 Year by Default)." 486 | } 487 | 488 | 489 | ## User Fields 490 | dimension: user_first_touch_timestamp { 491 | type: number 492 | sql: ${TABLE}.user_first_touch_timestamp ;; 493 | } 494 | 495 | dimension: user_ltv__currency { 496 | type: string 497 | sql: ${TABLE}.user_ltv.currency ;; 498 | full_suggestions: yes 499 | group_label: "User Ltv" 500 | group_item_label: "Currency" 501 | } 502 | 503 | dimension: user_ltv__revenue { 504 | type: number 505 | sql: ${TABLE}.user_ltv.revenue ;; 506 | group_label: "User Ltv" 507 | group_item_label: "Revenue" 508 | } 509 | 510 | dimension: user_properties { 511 | hidden: yes 512 | sql: ${TABLE}.user_properties ;; 513 | } 514 | 515 | dimension: user_pseudo_id { 516 | type: string 517 | sql: ${TABLE}.user_pseudo_id ;; 518 | full_suggestions: yes 519 | } 520 | 521 | # dimension: user_id 522 | 523 | ## Measures 524 | 525 | measure: total_events { 526 | view_label: "Behavior" 527 | group_label: "Events" 528 | description: "The total number of events for the session." 529 | type: count 530 | # view_label: "Metrics" 531 | # group_label: "Event Data" 532 | # label: "Total Events" 533 | } 534 | 535 | measure: total_unique_events { 536 | view_label: "Behavior" 537 | group_label: "Events" 538 | label: "Unique Events" 539 | description: "Total Unique Events (Unique by Full Event Definition)" 540 | #description: "Unique Events are interactions with content by a single user within a single session that can be tracked separately from pageviews or screenviews. " 541 | type: count_distinct 542 | sql: ${sl_key} ;; 543 | } 544 | 545 | 546 | measure: total_page_views { 547 | # view_label: "Metrics" 548 | # group_label: "Event Data" 549 | # label: "Total Page Views" 550 | view_label: "Behavior" 551 | group_label: "Pages" 552 | label: "Pageviews" 553 | description: "The total number of pageviews for the property." 554 | type: count 555 | filters: [event_name: "page_view"] 556 | value_format_name: formatted_number 557 | } 558 | 559 | measure: total_unique_page_views { 560 | # view_label: "Metrics" 561 | # group_label: "Event Data" 562 | # label: "Total Unique Page Views" 563 | view_label: "Behavior" 564 | group_label: "Pages" 565 | label: "Unique Pageviews" 566 | description: "Unique Pageviews are the number of sessions during which the specified page was viewed at least once. A unique pageview is counted for each page URL + page title combination." 567 | type: count_distinct 568 | sql: CONCAT(${event_param_ga_session_id}, ${event_param_page}, ${event_param_page_title}) ;; 569 | value_format_name: formatted_number 570 | filters: [event_name: "page_view"] 571 | } 572 | 573 | measure: total_engaged_events { 574 | type: count_distinct 575 | view_label: "Behavior" 576 | group_label: "Events" 577 | label: "Engaged Events" 578 | #description: "" 579 | filters: [event_param_engaged_session_event: ">0"] 580 | } 581 | 582 | ## ECommerce 583 | 584 | measure: total_transactions { 585 | group_label: "Ecommerce" 586 | label: "Transactions" 587 | type: count_distinct 588 | sql: ${ecommerce__transaction_id} ;; 589 | filters: [ecommerce__transaction_id: "-(not set)"] 590 | } 591 | 592 | measure: transaction_revenue_per_user { 593 | group_label: "Ecommerce" 594 | type: number 595 | sql: 1.0 * (${total_purchase_revenue}/NULLIF(${sessions.total_users},0)) ;; 596 | value_format_name: usd 597 | } 598 | 599 | measure: transaction_conversion_rate { 600 | group_label: "Ecommerce" 601 | label: "Transaction Conversion Rate" 602 | type: number 603 | sql: 1.0 * (${total_transactions}/NULLIF(${sessions.total_sessions},0)) ;; 604 | value_format_name: percent_2 605 | } 606 | 607 | measure: total_purchase_revenue { 608 | group_label: "Ecommerce" 609 | label: "Purchase Revenue" 610 | type: sum_distinct 611 | sql: ${ecommerce__purchase_revenue} ;; 612 | sql_distinct_key: ${ecommerce__transaction_id} ;; 613 | value_format_name: usd 614 | } 615 | 616 | measure: total_purchase_revenue_usd { 617 | group_label: "Ecommerce" 618 | label: "Purchase Revenue (USD)" 619 | type: sum 620 | sql: ${ecommerce__purchase_revenue_in_usd} ;; 621 | # sql_distinct_key: ${ecommerce__transaction_id} ;; 622 | value_format_name: usd 623 | } 624 | 625 | measure: total_refund_value { 626 | group_label: "Ecommerce" 627 | label: "Refund Value" 628 | type: sum_distinct 629 | sql: ${ecommerce__refund_value} ;; 630 | sql_distinct_key: ${ecommerce__transaction_id} ;; 631 | value_format_name: usd 632 | } 633 | 634 | measure: total_refund_value_usd { 635 | group_label: "Ecommerce" 636 | label: "Refund Value (USD)" 637 | type: sum_distinct 638 | sql: ${ecommerce__refund_value_in_usd} ;; 639 | sql_distinct_key: ${ecommerce__transaction_id} ;; 640 | value_format_name: usd 641 | } 642 | 643 | measure: total_shipping_value { 644 | group_label: "Ecommerce" 645 | label: "Shipping Value" 646 | type: sum_distinct 647 | sql: ${ecommerce__shipping_value} ;; 648 | sql_distinct_key: ${ecommerce__transaction_id} ;; 649 | value_format_name: usd 650 | } 651 | 652 | measure: total_shipping_value_usd { 653 | group_label: "Ecommerce" 654 | label: "Shipping Value (USD)" 655 | type: sum_distinct 656 | sql: ${ecommerce__shipping_value_in_usd} ;; 657 | sql_distinct_key: ${ecommerce__transaction_id} ;; 658 | value_format_name: usd 659 | } 660 | 661 | measure: total_tax_value { 662 | group_label: "Ecommerce" 663 | label: "Tax Value" 664 | type: sum_distinct 665 | sql: ${ecommerce__tax_value} ;; 666 | sql_distinct_key: ${ecommerce__transaction_id} ;; 667 | value_format_name: usd 668 | } 669 | 670 | measure: total_tax_value_usd { 671 | group_label: "Ecommerce" 672 | label: "Tax Value (USD)" 673 | type: sum_distinct 674 | sql: ${ecommerce__tax_value_in_usd} ;; 675 | sql_distinct_key: ${ecommerce__transaction_id} ;; 676 | value_format_name: usd 677 | } 678 | 679 | measure: total_item_quantity { 680 | group_label: "Ecommerce" 681 | label: "Transaction Items" 682 | type: sum_distinct 683 | sql: ${ecommerce__total_item_quantity} ;; 684 | sql_distinct_key: ${ecommerce__transaction_id} ;; 685 | value_format_name: decimal_0 686 | } 687 | 688 | measure: total_unique_items { 689 | group_label: "Ecommerce" 690 | label: "Unique Items" 691 | type: sum_distinct 692 | sql: ${ecommerce__unique_items} ;; 693 | sql_distinct_key: ${ecommerce__transaction_id} ;; 694 | value_format_name: decimal_0 695 | } 696 | 697 | # ----- Sets of fields for drilling ------ 698 | set: detail { 699 | fields: [ 700 | event_name, 701 | traffic_source__name, 702 | device__mobile_model_name, 703 | device__mobile_brand_name, 704 | device__web_info__hostname, 705 | event_dimensions__hostname, 706 | device__mobile_marketing_name 707 | ] 708 | } 709 | } 710 | -------------------------------------------------------------------------------- /views/event_data_dimensions/page_data.view.lkml: -------------------------------------------------------------------------------- 1 | ## Purpose: This view is for defining the 'page_view' specific fields. This view is extended into 'event_data'. 2 | 3 | view: page_data { 4 | extension: required 5 | 6 | dimension: page_view_rank { 7 | view_label: "Page Flow" 8 | group_label: "Page Path" 9 | label: "Page View Rank" 10 | description: "Rank of 'Page View' Event, 1 = First Event" 11 | type: number 12 | sql: ${TABLE}.page_view_rank ;; 13 | } 14 | 15 | dimension: page_view_reverse_rank { 16 | view_label: "Page Flow" 17 | group_label: "Page Path" 18 | label: "Page View Reverse Rank" 19 | description: "Reverse Rank of 'Page View' Event, 1 = Last Event" 20 | type: number 21 | sql: ${TABLE}.page_view_reverse_rank ;; 22 | } 23 | 24 | dimension: time_to_next_page { 25 | view_label: "Behavior" 26 | group_label: "Time on Page" 27 | label: "Time on Page" 28 | description: "Time user spent on page. Single page_view Sessions have 0 Duration." 29 | type: number 30 | sql: ${TABLE}.time_to_next_page ;; 31 | value_format_name: hour_format 32 | } 33 | 34 | dimension: is_landing_page { 35 | view_label: "Behavior" 36 | group_label: "Page Filters" 37 | description: "Use to filter for first pageview of a session. Use with Page dimensions." 38 | type: yesno 39 | sql: ${page_view_rank} = 1 ;; 40 | full_suggestions: yes 41 | } 42 | 43 | dimension: is_exit_page { 44 | view_label: "Behavior" 45 | group_label: "Page Filters" 46 | description: "If this hit was the last pageview or screenview hit of a session, this is set to true." 47 | type: yesno 48 | sql: ${page_view_reverse_rank} = 1 ;; 49 | full_suggestions: yes 50 | } 51 | 52 | dimension: is_bounce { 53 | view_label: "Behavior" 54 | group_label: "Page Filters" 55 | label: "Is Bounce?" 56 | description: "If this hit was the last pageview or screenview hit of a session, this is set to true." 57 | type: yesno 58 | sql: ${sessions.session_data_page_view_count} = 1 ;; 59 | full_suggestions: yes 60 | } 61 | 62 | ## Page Path Dimensions 63 | dimension: page_path_1 { 64 | view_label: "Page Flow" 65 | group_label: "Page Path" 66 | description: "1st Page in Session." 67 | type: string 68 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 69 | from UNNEST(${sessions.event_data}) as event_history 70 | where event_history.page_view_rank = 1 71 | and event_history.event_name = "page_view" limit 1) ;; 72 | # sql: case when ${page_view_rank} = 1 then ${event_param_page} else null end ;; 73 | full_suggestions: yes 74 | } 75 | dimension: page_path_2 { 76 | view_label: "Page Flow" 77 | group_label: "Page Path" 78 | description: "2nd Page in Session." 79 | type: string 80 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 81 | from UNNEST(${sessions.event_data}) as event_history 82 | where event_history.page_view_rank = 2 83 | and event_history.event_name = "page_view" limit 1) ;; 84 | # sql: case when ${page_view_rank} = 2 then ${event_param_page} else null end ;; 85 | full_suggestions: yes 86 | } 87 | dimension: page_path_3 { 88 | view_label: "Page Flow" 89 | group_label: "Page Path" 90 | description: "3rd Page in Session." 91 | type: string 92 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 93 | from UNNEST(${sessions.event_data}) as event_history 94 | where event_history.page_view_rank = 3 95 | and event_history.event_name = "page_view" limit 1) ;; 96 | # sql: case when ${page_view_rank} = 3 then ${event_param_page} else null end ;; 97 | full_suggestions: yes 98 | } 99 | dimension: page_path_4 { 100 | view_label: "Page Flow" 101 | group_label: "Page Path" 102 | description: "4th Page in Session." 103 | type: string 104 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 105 | from UNNEST(${sessions.event_data}) as event_history 106 | where event_history.page_view_rank = 4 107 | and event_history.event_name = "page_view" limit 1) ;; 108 | # sql: case when ${page_view_rank} = 4 then ${event_param_page} else null end ;; 109 | full_suggestions: yes 110 | } 111 | dimension: page_path_5 { 112 | view_label: "Page Flow" 113 | group_label: "Page Path" 114 | description: "5th Page in Session." 115 | type: string 116 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 117 | from UNNEST(${sessions.event_data}) as event_history 118 | where event_history.page_view_rank = 5 119 | and event_history.event_name = "page_view" limit 1) ;; 120 | # sql: case when ${page_view_rank} = 5 then ${event_param_page} else null end ;; 121 | full_suggestions: yes 122 | } 123 | dimension: page_path_6 { 124 | view_label: "Page Flow" 125 | group_label: "Page Path" 126 | description: "6th Page in Session." 127 | type: string 128 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 129 | from UNNEST(${sessions.event_data}) as event_history 130 | where event_history.page_view_rank = 6 131 | and event_history.event_name = "page_view" limit 1) ;; 132 | # sql: case when ${page_view_rank} = 6 then ${event_param_page} else null end ;; 133 | full_suggestions: yes 134 | } 135 | dimension: page_path_7 { 136 | view_label: "Page Flow" 137 | group_label: "Page Path" 138 | description: "4th Page in Session." 139 | type: string 140 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 141 | from UNNEST(${sessions.event_data}) as event_history 142 | where event_history.page_view_rank = 7 143 | and event_history.event_name = "page_view" limit 1) ;; 144 | # sql: case when ${page_view_rank} = 7 then ${event_param_page} else null end ;; 145 | full_suggestions: yes 146 | } 147 | dimension: page_path_8 { 148 | view_label: "Page Flow" 149 | group_label: "Page Path" 150 | description: "5th Page in Session." 151 | type: string 152 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 153 | from UNNEST(${sessions.event_data}) as event_history 154 | where event_history.page_view_rank = 8 155 | and event_history.event_name = "page_view" limit 1) ;; 156 | # sql: case when ${page_view_rank} = 8 then ${event_param_page} else null end ;; 157 | full_suggestions: yes 158 | } 159 | dimension: page_path_9 { 160 | view_label: "Page Flow" 161 | group_label: "Page Path" 162 | description: "6th Page in Session." 163 | type: string 164 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 165 | from UNNEST(${sessions.event_data}) as event_history 166 | where event_history.page_view_rank = 9 167 | and event_history.event_name = "page_view" limit 1) ;; 168 | # sql: case when ${page_view_rank} = 9 then ${event_param_page} else null end ;; 169 | full_suggestions: yes 170 | } 171 | 172 | ## Relative Page Path Dimensions 173 | dimension: current_page_plus_1 { 174 | view_label: "Page Flow" 175 | group_label: "Relative Page Path" 176 | description: "Page Path for page that came directly before current page." 177 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 178 | from UNNEST(${sessions.event_data}) as event_history 179 | where event_history.page_view_rank = (${TABLE}.page_view_rank + 1) 180 | and event_history.event_name = "page_view" limit 1) ;; 181 | full_suggestions: yes 182 | type: string 183 | } 184 | dimension: current_page_plus_2 { 185 | view_label: "Page Flow" 186 | group_label: "Relative Page Path" 187 | description: "Page Path for page that came 2 pages before current page." 188 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 189 | from UNNEST(${sessions.event_data}) as event_history 190 | where event_history.page_view_rank = (${TABLE}.page_view_rank + 2) 191 | and event_history.event_name = "page_view" limit 1) ;; 192 | full_suggestions: yes 193 | type: string 194 | } 195 | dimension: current_page_plus_3 { 196 | view_label: "Page Flow" 197 | group_label: "Relative Page Path" 198 | description: "Page Path for page that came 3 pages before current page." 199 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 200 | from UNNEST(${sessions.event_data}) as event_history 201 | where event_history.page_view_rank = (${TABLE}.page_view_rank + 3) 202 | and event_history.event_name = "page_view" limit 1) ;; 203 | full_suggestions: yes 204 | type: string 205 | } 206 | dimension: current_page_plus_4 { 207 | view_label: "Page Flow" 208 | group_label: "Relative Page Path" 209 | description: "Page Path for page that came 4 pages before current page." 210 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 211 | from UNNEST(${sessions.event_data}) as event_history 212 | where event_history.page_view_rank = (${TABLE}.page_view_rank + 4) 213 | and event_history.event_name = "page_view" limit 1) ;; 214 | full_suggestions: yes 215 | type: string 216 | } 217 | dimension: current_page_plus_5 { 218 | view_label: "Page Flow" 219 | group_label: "Relative Page Path" 220 | description: "Page Path for page that came 5 pages before current page." 221 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 222 | from UNNEST(${sessions.event_data}) as event_history 223 | where event_history.page_view_rank = (${TABLE}.page_view_rank + 5) 224 | and event_history.event_name = "page_view" limit 1) ;; 225 | full_suggestions: yes 226 | type: string 227 | } 228 | dimension: current_page_plus_6 { 229 | view_label: "Page Flow" 230 | group_label: "Relative Page Path" 231 | description: "Page Path for page that came 6 pages before current page." 232 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 233 | from UNNEST(${sessions.event_data}) as event_history 234 | where event_history.page_view_rank = (${TABLE}.page_view_rank + 6) 235 | and event_history.event_name = "page_view" limit 1) ;; 236 | full_suggestions: yes 237 | type: string 238 | } 239 | dimension: current_page_plus_7 { 240 | view_label: "Page Flow" 241 | group_label: "Relative Page Path" 242 | description: "Page Path for page that came 7 pages before current page." 243 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 244 | from UNNEST(${sessions.event_data}) as event_history 245 | where event_history.page_view_rank = (${TABLE}.page_view_rank + 7) 246 | and event_history.event_name = "page_view" limit 1) ;; 247 | full_suggestions: yes 248 | type: string 249 | } 250 | dimension: current_page_plus_8 { 251 | view_label: "Page Flow" 252 | group_label: "Relative Page Path" 253 | description: "Page Path for page that came 8 pages before current page." 254 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 255 | from UNNEST(${sessions.event_data}) as event_history 256 | where event_history.page_view_rank = (${TABLE}.page_view_rank + 8) 257 | and event_history.event_name = "page_view" limit 1) ;; 258 | full_suggestions: yes 259 | type: string 260 | } 261 | dimension: current_page_plus_9 { 262 | view_label: "Page Flow" 263 | group_label: "Relative Page Path" 264 | description: "Page Path for page that came 9 pages before current page." 265 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 266 | from UNNEST(${sessions.event_data}) as event_history 267 | where event_history.page_view_rank = (${TABLE}.page_view_rank + 9) 268 | and event_history.event_name = "page_view" limit 1) ;; 269 | full_suggestions: yes 270 | type: string 271 | } 272 | 273 | ## Reverse Page Path Dimensions 274 | dimension: current_page_minus_1 { 275 | view_label: "Page Flow" 276 | group_label: "Reverse Page Path" 277 | description: "Page Path for page that came directly after current page." 278 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 279 | from UNNEST(${sessions.event_data}) as event_history 280 | where event_history.page_view_rank = (${TABLE}.page_view_rank - 1) 281 | and event_history.event_name = "page_view" limit 1) ;; 282 | full_suggestions: yes 283 | type: string 284 | } 285 | dimension: current_page_minus_2 { 286 | view_label: "Page Flow" 287 | group_label: "Reverse Page Path" 288 | description: "Page Path for page that came 2 pages after current page." 289 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 290 | from UNNEST(${sessions.event_data}) as event_history 291 | where event_history.page_view_rank = (${TABLE}.page_view_rank - 2) 292 | and event_history.event_name = "page_view" limit 1) ;; 293 | full_suggestions: yes 294 | type: string 295 | } 296 | dimension: current_page_minus_3 { 297 | view_label: "Page Flow" 298 | group_label: "Reverse Page Path" 299 | description: "Page Path for page that came 3 pages after current page." 300 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 301 | from UNNEST(${sessions.event_data}) as event_history 302 | where event_history.page_view_rank = (${TABLE}.page_view_rank - 3) 303 | and event_history.event_name = "page_view" limit 1) ;; 304 | full_suggestions: yes 305 | type: string 306 | } 307 | dimension: current_page_minus_4 { 308 | view_label: "Page Flow" 309 | group_label: "Reverse Page Path" 310 | description: "Page Path for page that came 4 pages after current page." 311 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 312 | from UNNEST(${sessions.event_data}) as event_history 313 | where event_history.page_view_rank = (${TABLE}.page_view_rank - 4) 314 | and event_history.event_name = "page_view" limit 1) ;; 315 | full_suggestions: yes 316 | type: string 317 | } 318 | dimension: current_page_minus_5 { 319 | view_label: "Page Flow" 320 | group_label: "Reverse Page Path" 321 | description: "Page Path for page that came 5 pages after current page." 322 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 323 | from UNNEST(${sessions.event_data}) as event_history 324 | where event_history.page_view_rank = (${TABLE}.page_view_rank - 5) 325 | and event_history.event_name = "page_view" limit 1) ;; 326 | full_suggestions: yes 327 | type: string 328 | } 329 | dimension: current_page_minus_6 { 330 | view_label: "Page Flow" 331 | group_label: "Reverse Page Path" 332 | description: "Page Path for page that came 6 pages after current page." 333 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 334 | from UNNEST(${sessions.event_data}) as event_history 335 | where event_history.page_view_rank = (${TABLE}.page_view_rank - 6) 336 | and event_history.event_name = "page_view" limit 1) ;; 337 | full_suggestions: yes 338 | type: string 339 | } 340 | dimension: current_page_minus_7 { 341 | view_label: "Page Flow" 342 | group_label: "Reverse Page Path" 343 | description: "Page Path for page that came 7 pages after current page." 344 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 345 | from UNNEST(${sessions.event_data}) as event_history 346 | where event_history.page_view_rank = (${TABLE}.page_view_rank - 7) 347 | and event_history.event_name = "page_view" limit 1) ;; 348 | full_suggestions: yes 349 | type: string 350 | } 351 | dimension: current_page_minus_8 { 352 | view_label: "Page Flow" 353 | group_label: "Reverse Page Path" 354 | description: "Page Path for page that came 8 pages after current page." 355 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 356 | from UNNEST(${sessions.event_data}) as event_history 357 | where event_history.page_view_rank = (${TABLE}.page_view_rank - 8) 358 | and event_history.event_name = "page_view" limit 1) ;; 359 | full_suggestions: yes 360 | type: string 361 | } 362 | dimension: current_page_minus_9 { 363 | view_label: "Page Flow" 364 | group_label: "Reverse Page Path" 365 | description: "Page Path for page that came 9 pages after current page." 366 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 367 | from UNNEST(${sessions.event_data}) as event_history 368 | where event_history.page_view_rank = (${TABLE}.page_view_rank - 9) 369 | and event_history.event_name = "page_view" limit 1) ;; 370 | full_suggestions: yes 371 | type: string 372 | } 373 | 374 | 375 | ## Measures 376 | measure: total_entrances { 377 | view_label: "Behavior" 378 | group_label: "Pages" 379 | label: "Entrances" 380 | description: "The number of entrances to the property measured as the first pageview in a session, typically used with Landing Page." 381 | type: count_distinct 382 | filters: [is_landing_page: "yes"] 383 | sql: ${ed_key} ;; 384 | value_format_name: formatted_number 385 | } 386 | measure: entrance_rate { 387 | view_label: "Behavior" 388 | group_label: "Pages" 389 | label: "Entrance Rate" 390 | description:"The percentage of 'Page View' events in which this page was the entrance." 391 | type: number 392 | sql: ${total_entrances}/nullif(${total_page_views},0) ;; 393 | value_format_name: percent_2 394 | } 395 | measure: total_bounce { 396 | view_label: "Behavior" 397 | group_label: "Pages" 398 | label: "Bounces" 399 | type: count_distinct 400 | sql: ${sl_key} ;; 401 | filters: [is_bounce: "yes", event_name: "page_view"] 402 | value_format_name: formatted_number 403 | } 404 | measure: bounce_rate { 405 | view_label: "Behavior" 406 | group_label: "Pages" 407 | label: "Bounce Rate" 408 | type: number 409 | sql: ${total_bounce}/nullif(${total_page_views},0) ;; 410 | value_format_name: percent_2 411 | } 412 | measure: total_exits { 413 | view_label: "Behavior" 414 | group_label: "Pages" 415 | label: "Exits" 416 | description: "The number of exits from the property." 417 | type: count_distinct 418 | filters: [is_exit_page: "yes"] 419 | sql: ${ed_key} ;; 420 | value_format_name: formatted_number 421 | } 422 | measure: exit_rate { 423 | view_label: "Behavior" 424 | group_label: "Pages" 425 | label: "Exit Rate" 426 | description: "Exit is (number of exits) / (number of pageviews) for the page or set of pages. It indicates how often users exit from that page or set of pages when they view the page(s)." 427 | type: number 428 | sql: ${total_exits}/nullif(${total_page_views},0) ;; 429 | value_format_name: percent_2 430 | } 431 | measure: average_time_to_next_page { 432 | view_label: "Behavior" 433 | group_label: "Pages" 434 | label: "Average Time on Page" 435 | description: "Avg time a user spent on a specific page. Note that Single Page_View Sessions are excluded from this measure." 436 | type: average 437 | sql: coalesce(${time_to_next_page},0) ;; 438 | filters: [time_to_next_page: ">0"] ## Filtering out 0 Duration Page View Events, which occurs when a session only has one page_view. 439 | value_format_name: hour_format 440 | } 441 | 442 | } 443 | -------------------------------------------------------------------------------- /dashboards/campaign_impact.dashboard.lookml: -------------------------------------------------------------------------------- 1 | - dashboard: ga4_campaign_impact 2 | title: "[GA4] Campaign Impact" 3 | layout: newspaper 4 | preferred_viewer: dashboards-next 5 | elements: 6 | - title: Users saw the campaign page 7 | name: Users saw the campaign page 8 | model: ga4 9 | explore: sessions 10 | type: single_value 11 | fields: [sessions.total_users, user_segment.segment_users, user_segment.retention_rate] 12 | filters: 13 | events.event_param_page: '' 14 | limit: 500 15 | custom_color_enabled: true 16 | show_single_value_title: true 17 | show_comparison: false 18 | comparison_type: value 19 | comparison_reverse_colors: false 20 | show_comparison_label: true 21 | enable_conditional_formatting: true 22 | conditional_formatting_include_totals: false 23 | conditional_formatting_include_nulls: false 24 | conditional_formatting: [{type: not null, value: !!null '', background_color: "#1A73E8", 25 | font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 26 | palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab}, bold: false, italic: false, 27 | strikethrough: false, fields: !!null ''}] 28 | x_axis_gridlines: false 29 | y_axis_gridlines: true 30 | show_view_names: false 31 | show_y_axis_labels: true 32 | show_y_axis_ticks: true 33 | y_axis_tick_density: default 34 | y_axis_tick_density_custom: 5 35 | show_x_axis_label: true 36 | show_x_axis_ticks: true 37 | y_axis_scale_mode: linear 38 | x_axis_reversed: false 39 | y_axis_reversed: false 40 | plot_size_by_field: false 41 | trellis: '' 42 | stacking: '' 43 | limit_displayed_rows: false 44 | legend_position: center 45 | point_style: none 46 | show_value_labels: false 47 | label_density: 25 48 | x_axis_scale: auto 49 | y_axis_combined: true 50 | ordering: none 51 | show_null_labels: false 52 | show_totals_labels: false 53 | show_silhouette: false 54 | totals_color: "#808080" 55 | defaults_version: 1 56 | series_types: {} 57 | hidden_fields: [user_segment.segment_users, user_segment.retention_rate] 58 | listen: 59 | Audience Selector: sessions.audience_selector 60 | Campaign Date: sessions.session_date 61 | User Return Date: user_segment.user_segment_timeframe 62 | Page: sessions.landing_page 63 | row: 5 64 | col: 0 65 | width: 12 66 | height: 4 67 | - title: Users Returned 68 | name: Users Returned 69 | model: ga4 70 | explore: sessions 71 | type: single_value 72 | fields: [sessions.total_users, user_segment.segment_users, user_segment.retention_rate] 73 | filters: 74 | events.event_param_page: '' 75 | limit: 500 76 | custom_color_enabled: true 77 | show_single_value_title: true 78 | show_comparison: true 79 | comparison_type: value 80 | comparison_reverse_colors: false 81 | show_comparison_label: true 82 | enable_conditional_formatting: true 83 | conditional_formatting_include_totals: false 84 | conditional_formatting_include_nulls: false 85 | conditional_formatting: [{type: not null, value: !!null '', background_color: "#1A73E8", 86 | font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 87 | palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab}, bold: false, italic: false, 88 | strikethrough: false, fields: !!null ''}] 89 | x_axis_gridlines: false 90 | y_axis_gridlines: true 91 | show_view_names: false 92 | show_y_axis_labels: true 93 | show_y_axis_ticks: true 94 | y_axis_tick_density: default 95 | y_axis_tick_density_custom: 5 96 | show_x_axis_label: true 97 | show_x_axis_ticks: true 98 | y_axis_scale_mode: linear 99 | x_axis_reversed: false 100 | y_axis_reversed: false 101 | plot_size_by_field: false 102 | trellis: '' 103 | stacking: '' 104 | limit_displayed_rows: false 105 | legend_position: center 106 | point_style: none 107 | show_value_labels: false 108 | label_density: 25 109 | x_axis_scale: auto 110 | y_axis_combined: true 111 | ordering: none 112 | show_null_labels: false 113 | show_totals_labels: false 114 | show_silhouette: false 115 | totals_color: "#808080" 116 | defaults_version: 1 117 | series_types: {} 118 | hidden_fields: [sessions.total_users] 119 | listen: 120 | Audience Selector: sessions.audience_selector 121 | Campaign Date: sessions.session_date 122 | User Return Date: user_segment.user_segment_timeframe 123 | Page: sessions.landing_page 124 | row: 5 125 | col: 12 126 | width: 12 127 | height: 4 128 | - title: Retained User Transaction Conversion Rate 129 | name: Retained User Transaction Conversion Rate 130 | model: ga4 131 | explore: sessions 132 | type: single_value 133 | fields: [events.transaction_conversion_rate, user_segment.segment_transaction_conversion_rate] 134 | filters: 135 | events.event_param_page: '' 136 | limit: 500 137 | dynamic_fields: [{_kind_hint: measure, table_calculation: change, _type_hint: number, 138 | category: table_calculation, expression: "${user_segment.segment_transaction_conversion_rate}-${events.transaction_conversion_rate}", 139 | label: Change, value_format: !!null '', value_format_name: percent_1}] 140 | custom_color_enabled: true 141 | show_single_value_title: true 142 | show_comparison: true 143 | comparison_type: change 144 | comparison_reverse_colors: false 145 | show_comparison_label: true 146 | enable_conditional_formatting: true 147 | conditional_formatting_include_totals: false 148 | conditional_formatting_include_nulls: false 149 | comparison_label: conversion rate driven by campaign 150 | conditional_formatting: [{type: not null, value: !!null '', background_color: "#EA4335", 151 | font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 152 | palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab}, bold: false, italic: false, 153 | strikethrough: false, fields: !!null ''}] 154 | x_axis_gridlines: false 155 | y_axis_gridlines: true 156 | show_view_names: false 157 | show_y_axis_labels: true 158 | show_y_axis_ticks: true 159 | y_axis_tick_density: default 160 | y_axis_tick_density_custom: 5 161 | show_x_axis_label: true 162 | show_x_axis_ticks: true 163 | y_axis_scale_mode: linear 164 | x_axis_reversed: false 165 | y_axis_reversed: false 166 | plot_size_by_field: false 167 | trellis: '' 168 | stacking: '' 169 | limit_displayed_rows: false 170 | legend_position: center 171 | point_style: none 172 | show_value_labels: false 173 | label_density: 25 174 | x_axis_scale: auto 175 | y_axis_combined: true 176 | ordering: none 177 | show_null_labels: false 178 | show_totals_labels: false 179 | show_silhouette: false 180 | totals_color: "#808080" 181 | defaults_version: 1 182 | series_types: {} 183 | hidden_fields: [events.transaction_conversion_rate] 184 | listen: 185 | Audience Selector: sessions.audience_selector 186 | Campaign Date: sessions.session_date 187 | User Return Date: user_segment.user_segment_timeframe 188 | Page: sessions.landing_page 189 | row: 9 190 | col: 12 191 | width: 12 192 | height: 4 193 | - title: Transaction Conversion Rate 194 | name: Transaction Conversion Rate 195 | model: ga4 196 | explore: sessions 197 | type: single_value 198 | fields: [events.transaction_conversion_rate, user_segment.segment_transaction_conversion_rate] 199 | filters: 200 | events.event_param_page: '' 201 | limit: 500 202 | dynamic_fields: [{_kind_hint: measure, table_calculation: change, _type_hint: number, 203 | category: table_calculation, expression: "${user_segment.segment_transaction_conversion_rate}-${events.transaction_conversion_rate}", 204 | label: Change, value_format: !!null '', value_format_name: percent_1}] 205 | custom_color_enabled: true 206 | show_single_value_title: true 207 | show_comparison: false 208 | comparison_type: change 209 | comparison_reverse_colors: false 210 | show_comparison_label: true 211 | enable_conditional_formatting: true 212 | conditional_formatting_include_totals: false 213 | conditional_formatting_include_nulls: false 214 | comparison_label: conversion rate driven by campaign 215 | conditional_formatting: [{type: not null, value: !!null '', background_color: "#EA4335", 216 | font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 217 | palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab}, bold: false, italic: false, 218 | strikethrough: false, fields: !!null ''}] 219 | x_axis_gridlines: false 220 | y_axis_gridlines: true 221 | show_view_names: false 222 | show_y_axis_labels: true 223 | show_y_axis_ticks: true 224 | y_axis_tick_density: default 225 | y_axis_tick_density_custom: 5 226 | show_x_axis_label: true 227 | show_x_axis_ticks: true 228 | y_axis_scale_mode: linear 229 | x_axis_reversed: false 230 | y_axis_reversed: false 231 | plot_size_by_field: false 232 | trellis: '' 233 | stacking: '' 234 | limit_displayed_rows: false 235 | legend_position: center 236 | point_style: none 237 | show_value_labels: false 238 | label_density: 25 239 | x_axis_scale: auto 240 | y_axis_combined: true 241 | ordering: none 242 | show_null_labels: false 243 | show_totals_labels: false 244 | show_silhouette: false 245 | totals_color: "#808080" 246 | defaults_version: 1 247 | series_types: {} 248 | hidden_fields: [user_segment.segment_transaction_conversion_rate, change] 249 | listen: 250 | Audience Selector: sessions.audience_selector 251 | Campaign Date: sessions.session_date 252 | User Return Date: user_segment.user_segment_timeframe 253 | Page: sessions.landing_page 254 | row: 9 255 | col: 0 256 | width: 12 257 | height: 4 258 | - title: Revenue per User 259 | name: Revenue per User 260 | model: ga4 261 | explore: sessions 262 | type: single_value 263 | fields: [events.transaction_revenue_per_user] 264 | filters: 265 | events.event_param_page: '' 266 | limit: 500 267 | column_limit: 50 268 | dynamic_fields: [{_kind_hint: measure, table_calculation: change, _type_hint: number, 269 | category: table_calculation, expression: "${user_segment.segment_transaction_revenue_per_user}/${events.transaction_revenue_per_user}-1", 270 | label: Change, value_format: !!null '', value_format_name: percent_0, is_disabled: true}] 271 | custom_color_enabled: true 272 | show_single_value_title: true 273 | show_comparison: false 274 | comparison_type: value 275 | comparison_reverse_colors: false 276 | show_comparison_label: true 277 | enable_conditional_formatting: true 278 | conditional_formatting_include_totals: false 279 | conditional_formatting_include_nulls: false 280 | custom_color: "#ffffff" 281 | conditional_formatting: [{type: not null, value: !!null '', background_color: "#F9AB00", 282 | font_color: "#ffffff", color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 283 | palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab}, bold: false, italic: false, 284 | strikethrough: false, fields: !!null ''}] 285 | x_axis_gridlines: false 286 | y_axis_gridlines: true 287 | show_view_names: false 288 | show_y_axis_labels: true 289 | show_y_axis_ticks: true 290 | y_axis_tick_density: default 291 | y_axis_tick_density_custom: 5 292 | show_x_axis_label: true 293 | show_x_axis_ticks: true 294 | y_axis_scale_mode: linear 295 | x_axis_reversed: false 296 | y_axis_reversed: false 297 | plot_size_by_field: false 298 | trellis: '' 299 | stacking: '' 300 | limit_displayed_rows: false 301 | legend_position: center 302 | point_style: none 303 | show_value_labels: false 304 | label_density: 25 305 | x_axis_scale: auto 306 | y_axis_combined: true 307 | ordering: none 308 | show_null_labels: false 309 | show_totals_labels: false 310 | show_silhouette: false 311 | totals_color: "#808080" 312 | defaults_version: 1 313 | series_types: {} 314 | hidden_fields: [] 315 | y_axes: [] 316 | listen: 317 | Audience Selector: sessions.audience_selector 318 | Campaign Date: sessions.session_date 319 | User Return Date: user_segment.user_segment_timeframe 320 | Page: sessions.landing_page 321 | row: 13 322 | col: 0 323 | width: 12 324 | height: 4 325 | - title: Revenue per Retained User 326 | name: Revenue per Retained User 327 | model: ga4 328 | explore: sessions 329 | type: single_value 330 | fields: [user_segment.segment_transaction_revenue_per_user, events.transaction_revenue_per_user] 331 | filters: 332 | events.event_param_page: '' 333 | limit: 500 334 | column_limit: 50 335 | dynamic_fields: [{category: table_calculation, expression: "${user_segment.segment_transaction_revenue_per_user}/${events.transaction_revenue_per_user}-1", 336 | label: Change, value_format: !!null '', value_format_name: percent_0, _kind_hint: measure, 337 | table_calculation: change, _type_hint: number}] 338 | custom_color_enabled: true 339 | show_single_value_title: true 340 | show_comparison: true 341 | comparison_type: change 342 | comparison_reverse_colors: false 343 | show_comparison_label: true 344 | enable_conditional_formatting: true 345 | conditional_formatting_include_totals: false 346 | conditional_formatting_include_nulls: false 347 | custom_color: '' 348 | comparison_label: revenue per user driven by campaign 349 | conditional_formatting: [{type: not null, value: !!null '', background_color: "#F9AB00", 350 | font_color: "#ffffff", color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 351 | palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab}, bold: false, italic: false, 352 | strikethrough: false, fields: !!null ''}] 353 | x_axis_gridlines: false 354 | y_axis_gridlines: true 355 | show_view_names: false 356 | show_y_axis_labels: true 357 | show_y_axis_ticks: true 358 | y_axis_tick_density: default 359 | y_axis_tick_density_custom: 5 360 | show_x_axis_label: true 361 | show_x_axis_ticks: true 362 | y_axis_scale_mode: linear 363 | x_axis_reversed: false 364 | y_axis_reversed: false 365 | plot_size_by_field: false 366 | trellis: '' 367 | stacking: '' 368 | limit_displayed_rows: false 369 | legend_position: center 370 | point_style: none 371 | show_value_labels: false 372 | label_density: 25 373 | x_axis_scale: auto 374 | y_axis_combined: true 375 | ordering: none 376 | show_null_labels: false 377 | show_totals_labels: false 378 | show_silhouette: false 379 | totals_color: "#808080" 380 | defaults_version: 1 381 | series_types: {} 382 | hidden_fields: [events.transactions_per_user, events.transaction_revenue_per_user] 383 | listen: 384 | Audience Selector: sessions.audience_selector 385 | Campaign Date: sessions.session_date 386 | User Return Date: user_segment.user_segment_timeframe 387 | Page: sessions.landing_page 388 | row: 13 389 | col: 12 390 | width: 12 391 | height: 4 392 | - title: Impact by Audience 393 | name: Impact by Audience 394 | model: ga4 395 | explore: sessions 396 | type: looker_grid 397 | fields: [sessions.audience_trait, sessions.total_users, user_segment.segment_users, 398 | events.transaction_revenue_per_user, user_segment.segment_transaction_revenue_per_user, 399 | events.transaction_conversion_rate, user_segment.segment_transaction_conversion_rate] 400 | filters: 401 | events.event_param_page: '' 402 | sorts: [conversion_rate_change desc] 403 | limit: 500 404 | column_limit: 50 405 | dynamic_fields: [{_kind_hint: measure, table_calculation: retention_rate, _type_hint: number, 406 | category: table_calculation, expression: "${user_segment.segment_users}/${sessions.total_users}", 407 | label: Retention Rate, value_format: !!null '', value_format_name: percent_1}, 408 | {_kind_hint: measure, table_calculation: conversion_rate_change, _type_hint: number, 409 | category: table_calculation, expression: "${user_segment.segment_transaction_conversion_rate}-${events.transaction_conversion_rate}", 410 | label: Conversion Rate Change, value_format: !!null '', value_format_name: percent_1}, 411 | {category: table_calculation, expression: "(${user_segment.segment_transaction_revenue_per_user}/${events.transaction_revenue_per_user})\ 412 | \ -1", label: Rev per User Change, value_format: !!null '', value_format_name: percent_1, 413 | _kind_hint: measure, table_calculation: rev_per_user_change, _type_hint: number}] 414 | show_view_names: false 415 | show_row_numbers: true 416 | transpose: false 417 | truncate_text: true 418 | hide_totals: false 419 | hide_row_totals: false 420 | size_to_fit: true 421 | table_theme: white 422 | limit_displayed_rows: false 423 | enable_conditional_formatting: false 424 | header_text_alignment: left 425 | header_font_size: '12' 426 | rows_font_size: '14' 427 | conditional_formatting_include_totals: false 428 | conditional_formatting_include_nulls: false 429 | show_sql_query_menu_options: false 430 | column_order: ["$$$_row_numbers_$$$", sessions.audience_trait, retention_rate, 431 | events.transaction_revenue_per_user, user_segment.segment_transaction_revenue_per_user, 432 | rev_per_user_change, events.transaction_conversion_rate, user_segment.segment_transaction_conversion_rate, 433 | conversion_rate_change] 434 | show_totals: true 435 | show_row_totals: true 436 | series_labels: 437 | events.transactions_per_user: Transactions / User 438 | user_segment.segment_transaction_revenue_per_user: Revenue / Retained User 439 | user_segment.segment_transaction_conversion_rate: Retained User Conversion Rate 440 | events.transaction_conversion_rate: Conversion Rate 441 | rev_per_user_change: Δ 442 | conversion_rate_change: Δ 443 | events.transaction_revenue_per_user: Revenue / User 444 | series_cell_visualizations: 445 | events.transactions_per_user: 446 | is_active: false 447 | retention_rate: 448 | is_active: true 449 | conversion_rate_change: 450 | is_active: true 451 | rev_per_user_change: 452 | is_active: true 453 | header_background_color: "#7CB342" 454 | x_axis_gridlines: false 455 | y_axis_gridlines: true 456 | show_y_axis_labels: true 457 | show_y_axis_ticks: true 458 | y_axis_tick_density: default 459 | y_axis_tick_density_custom: 5 460 | show_x_axis_label: true 461 | show_x_axis_ticks: true 462 | y_axis_scale_mode: linear 463 | x_axis_reversed: false 464 | y_axis_reversed: false 465 | plot_size_by_field: false 466 | trellis: '' 467 | stacking: '' 468 | legend_position: center 469 | point_style: none 470 | show_value_labels: false 471 | label_density: 25 472 | x_axis_scale: auto 473 | y_axis_combined: true 474 | ordering: none 475 | show_null_labels: false 476 | show_totals_labels: false 477 | show_silhouette: false 478 | totals_color: "#808080" 479 | defaults_version: 1 480 | series_types: {} 481 | hidden_fields: [sessions.total_users, user_segment.segment_users] 482 | listen: 483 | Audience Selector: sessions.audience_selector 484 | Campaign Date: sessions.session_date 485 | User Return Date: user_segment.user_segment_timeframe 486 | Page: sessions.landing_page 487 | row: 17 488 | col: 0 489 | width: 24 490 | height: 8 491 | - name: '' 492 | type: text 493 | title_text: '' 494 | subtitle_text: '' 495 | body_text: "
\n\t
\n\t\t

GA4 Campaign Impact

Recommended\ 497 | \ Action
\n Select a period and landing page for a campaign\ 498 | \ you ran, and measure its retention and upsell impact. Observe\ 499 | \ which audiences are benefitting the most from this campaign to better\ 500 | \ target in the future.\n

\n
" 501 | row: 0 502 | col: 0 503 | width: 24 504 | height: 5 505 | filters: 506 | - name: Campaign Date 507 | title: Campaign Date 508 | type: field_filter 509 | default_value: 30 day 510 | allow_multiple_values: true 511 | required: false 512 | ui_config: 513 | type: advanced 514 | display: inline 515 | options: [] 516 | model: ga4 517 | explore: sessions 518 | listens_to_filters: [] 519 | field: sessions.session_date 520 | - name: User Return Date 521 | title: User Return Date 522 | type: field_filter 523 | default_value: 7 day 524 | allow_multiple_values: true 525 | required: false 526 | ui_config: 527 | type: advanced 528 | display: popover 529 | options: [] 530 | model: ga4 531 | explore: sessions 532 | listens_to_filters: [] 533 | field: user_segment.user_segment_timeframe 534 | - name: Page 535 | title: Page 536 | type: field_filter 537 | default_value: "/" 538 | allow_multiple_values: true 539 | required: false 540 | ui_config: 541 | type: tag_list 542 | display: popover 543 | options: [] 544 | model: ga4 545 | explore: sessions 546 | listens_to_filters: [] 547 | field: sessions.landing_page 548 | - name: Audience Selector 549 | title: Audience Selector 550 | type: field_filter 551 | default_value: Channel 552 | allow_multiple_values: true 553 | required: false 554 | ui_config: 555 | type: dropdown_menu 556 | display: inline 557 | options: [] 558 | model: ga4 559 | explore: sessions 560 | listens_to_filters: [] 561 | field: sessions.audience_selector -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Google Analytics 4 2 | 3 | ## What does this Looker Block do for me? 4 | 5 | This block allows GA4 users to continue to view the dashboards and metrics that they are familiar with from GA360. 6 | In order to mirror a lot of the high level dashboards you see in your existing GA 360 UI by looking at an Overview, Behavior, Audiences, Acquisition, and Custom Goal Conversions, this block creates: 7 | 8 | - An Incremental Persistent Derived Table that Sessionizes the Event Data (Sessions.view) 9 | - Event Level Data linked to a specific Session (events.view + extended views) 10 | - Retention Cohort Analysis capabilities (audience_cohorts.view) 11 | - Looker dimension for every combination of \_event\_name\_ / \_event\_params.key\_ and \_user_properties_ (event\_data\_dimensions folder) for the automatically collected data. 12 | 13 | GA4 data is exported in the format of a single flat table with a new entry for each event 14 | This is is similar to Google's Firebase output and can be difficult to query due to date-based partitioned tables and a need for unnesting in all but the most high-level queries. 15 | 16 | Documentation for getting GA4 data into BigQuery can be found on the Google Analytics support site [here](https://support.google.com/analytics/answer/9823238?hl=en#zippy=%2Cin-this-article) 17 | 18 | # GA4 Data Structure 19 | The GA4 (Google Analytics 4) data is exported as date-partitioned tables consisting of event-level rows. 20 | 21 | For anyone moving to GA4 from GA360, this represents a shift in scope. GA360 exported data had rows unique to a session, with nested information about individual hits (or events). 22 | 23 | Each row in the event tables is a record of one event. There are several standard columns: event_date, event_timestamp, event_name, user_pseudo_id, for a full list of fields exported by default, see https://support.google.com/firebase/answer/7029846. In addition to single-value fields, there are nested fields as well. 24 | 25 | The simpler nested fields can be referenced with dot-notation sql definitions, as shown in this example of the “ECommerce Purchase Revenue” dimension: 26 | dimension: ecommerce__purchase_revenue { 27 | type: number 28 | sql: ${TABLE}.ecommerce.purchase_revenue ;; 29 | group_label: "Ecommerce" 30 | group_item_label: "Purchase Revenue" 31 | value_format_name: usd 32 | } 33 | Here, “purchase_revenue” is an element of the ecommerce field. 34 | 35 | However, Some elements within GA4 are packaged as repeating key/value pairs such as the “event_params” field: 36 | 37 | `event_params:[ 38 | { 39 | "value": { 40 | "string_value": "https://www.google.com/" 41 | }, 42 | "key": "page_location" 43 | }, 44 | { 45 | "value": { 46 | "string_value": "Google" 47 | }, 48 | "key": "page_title" 49 | }, 50 | { 51 | "value": { 52 | "int_value": "1" 53 | }, 54 | "key": "ga_session_number" 55 | }, 56 | { 57 | "value": { 58 | "int_value": "1234567890" 59 | }, 60 | "key": "ga_session_id" 61 | } 62 | ]` 63 | 64 | The structure for each element in this array is essentially: 65 | 66 | KEY 67 | - KEY_VALUE 68 | 69 | VALUE 70 | - INT_VALUE 71 | - DOUBLE_VALUE 72 | - FLOAT_VALUE 73 | - STRING_VALUE 74 | 75 | As shown above, there are multiple “key” possibilities as well as multiple “value” possibilities within each key. We will also explain the relationship between these nested fields and their LookML views/dimensions below. 76 | 77 | Many desired metrics will be focused on session-level behavior. To facilitate this, sessions need to be identified across multiple rows. 78 | 79 | # Sessionization 80 | The core component of the GA4 Block is the sessions.view file. This file contains the derived table that groups the event rows into session rows. This is started by identifying and isolating the session-level key (referred to throughout the block as “sl_key”). The four components of this sl_key are: 81 | 82 | Session Date 83 | The session date is extracted directly from the table name, using the BigQuery “_TABLE_SUFFIX” function which becomes available when the table source for the query includes a wildcard. (For example: select * from events_* would query across all tables that begin with “events_”. In this scenario, you can also select all or portions of the table name to be displayed in the results as a populated column). Because of this, sessions in which events span multiple days will be counted as one session in each day. This is an inherited behavior from existing processes: If a session crosses a day boundary (e.g. if it starts at 11:55 pm and ends at 12:05 am), it is considered a single session, though it is counted once for each day. (https://support.google.com/analytics/answer/9191807) 84 | 85 | GA Session ID 86 | This session identifier is used in conjunction with the user ID (user_pseudo_id by default) and the GA Session Number to uniquely identify a session. The GA Session ID by itself may not be unique. 87 | 88 | GA Session Number 89 | This number indicates the session frequency of a particular user. Each user’s first visit will be 1.. 90 | 91 | User Pseudo ID 92 | This is the default User Identification value populated in GA4. 93 | 94 | This ‘sl_key’, along with its components and all columns from the source event row, are grouped within a CTE titled “session_list_with_event_history” alongside several calculations: 95 | 96 | Event Rank 97 | This is a rank function (no duplicate values) ordered by event_timestamp. Each event will have a rank > 0. 98 | 99 | Time To Next Event 100 | This is a timestamp_difference function between the event_timestamp of the following event and the event_timestamp of the current event. 101 | 102 | Page View Rank 103 | This is a rank function exclusively of ‘page_view’ events ordered by event_timestamp. Each ‘page_view’ event will have a rank > 0. Non ‘page_view’ events will have a rank of 0. 104 | 105 | Page View Reverse Rank 106 | Similar to the Page View Rank, however ordered by descending event_timestamp. 107 | 108 | Time To Next Page 109 | This timestamp_difference function will only get elapsed time between the present ‘page_view’ event and the following ‘page_view’ event. If a session only has one ‘page_view’ event, this value will be 0. 110 | 111 | The results of the “session_list_with_event_history” CTE are then utilized for the following processes: 112 | 113 | “Session_facts” CTE: 114 | - Session Event Count - A count of all events in a given session (grouped by sl_key). 115 | - Session Page View Count - A count of all “page_view” events in a given session (grouped by sl_key). 116 | - Engaged Events - A count of all events identified as ‘Engaged’, an event_parameter (grouped by sl_key). 117 | - Is Engaged Session? - A boolean (yes/no) value indicating if the session contained one or more events with a ‘session_engaged’ positive value (grouped by sl_key). 118 | - Is First Visit Session? - A boolean (yes/no) value indicating if the session contains a ‘first_visit’ event, indicative of a first visit session. 119 | - Session Length Minutes - A timestamp_difference function between the first event_timestamp in a session and the last event_timestamp in a session. Sessions with a singular event_timestamp (even with multiple events) will have a value of 0. 120 | 121 | “Session Tags” CTE: 122 | The purpose of this CTE is to extract session-specific tags for Medium, Source, Campaign, and Page Referrer values. These values follow the “Last Non-Direct Click” method of attribution. For the purposes of this block, the “traffic_source” column present in the source event tables was not used. The “traffic_source” values are set on a user’s initial visit to a site or application, and these values can persist beyond the scope of a single session. 123 | - Medium 124 | - Source 125 | - Campaign 126 | - Page Referrer 127 | 128 | “DeviceGeo” CTE: 129 | The device and geographic metadata of a session are being extracted from the “session_start” event. 130 | 131 | “Session Event Packing” CTE: 132 | This process takes the original row output of “session_list_with_event_history” and condenses it into one row per session, with all the event history of the session nested into an array. This is used later for efficient unnesting of elements without needing to re-group events into sessions at the time of the query. The output is the sl_key, its components, and a nested field called “event_data”. 133 | 134 | The final select statement in this derived table combines the elements of each process into one row for each session that contains: 135 | - SL_KEY 136 | - Session Date 137 | - GA Session ID 138 | - GA Session Number 139 | - User Pseudo ID 140 | - Session Attribution - Nested Element with output of “session_tags”. 141 | - Session Data - Nested Element with output of “session_facts”. 142 | - Device Data - Nested Element with Device columns from output of “DeviceGeo”. 143 | - Geo Data - Nested Element with Geo columns from output of “DeviceGeo”. 144 | - Event Data - Array of all event components that make up this session. 145 | 146 | ## Incremental Derived Table 147 | The output of this SQL query is stored as an incremental persistent derived table. This allows appending of new rows to an existing table, instead of a complete drop/create with every scheduled run. The key upon which the incremental updates happen is “Session Date”. To accommodate potential delays in full data delivery, the increment_offset is set to 3. This means for each run, up to 3 days of data may be inserted. 148 | 149 | The initial build of this table will generate a SQL query inserting “1=1”, running across all event tables present in the target dataset. Subsequent runs will insert appropriate “WHERE” syntax to limit the results to the date range specified by the “increment_offset” value. 150 | 151 | NOTE: This process of incrementally storing session-data will effectively duplicate the volume of data being exported by GA4. It is important to be aware of the increase in storage; however, this also increases your ability to perform analytics. 152 | 153 | # Looker Model and Views 154 | File Structure 155 | The components of the GA4 Block are isolated into folders for the file type/purpose. From the top down the folders are: 156 | - Attributes. The files contained within this folder are attributes that may be included in an explore/model file. By default the two attribute types included are: datagroups, formats (custom value format definitions) 157 | - Dashboards. All included LookML dashboards are present within this folder 158 | - Explores. Explores have been separated from the model file for potential re-use/extension/refinement. The only explore included by default is “sessions”. This “sessions” explore is where the attributes defined above are being included, as well as all views utilized. 159 | - Models. The GA4 model file is present here. It includes the sessions explore, the LookML dashboards, and a datagroup specific to this model. 160 | - Views 161 | - - BQML Sub-Folder contains the predictions.view file that creates the BQML propensity model. This view is commented-out by default. (See BQML under Notes) 162 | - - Event Data Dimensions Sub-Folder contains views that are extended or unnested via the “Events” view in the parent folder. 163 | - The remaining files are the primary views not directly related to Events. 164 | - Other. manifest.lkml is present in the root directory, and is where the instance constants are defined. 165 | 166 | ## Model File 167 | ### Views 168 | “sessions.view” 169 | This is the base view of the sessions explore of the GA4 model. While GA4 is event based, the data has been sessionized to mimic the analytics available in GA360. This was done with a SQL derived table, and the majority of dimensions defined are direct references to output of the query. Some fields of note are: 170 | 171 | - Audience Selector. This parameter is used in conjunction with the “Audience Trait” dimension, to dynamically update the content delivered on a report. 172 | - Audience Trait. This dimension populates with content from other referenced dimensions, based on the selected value of the “Audience Selector” parameter. 173 | - Landing/Exit Page. These dimensions sub-select within unnested event_data values to obtain the page_view events with the highest ‘page_view_rank’ and ‘reverse_page_view_rank’ values for each session. 174 | - Session Attribution Channel. This dimension is calculated on values from various session attribution fields, and its definition is based on the default channel groupings defined here https://support.google.com/analytics/answer/9756891. 175 | - Session Data Is Bounce?. “Bounce” is not a value present in the GA4 data. This determination is using session length, as all “single page view” sessions will also have a 0 session duration, fulfilling the requirements of traditional bounce determinations. 176 | - GA4 BQML Fields. These three fields are used when generating the BQML purchase propensity model. By default, the prediction_window_days parameter value is set on the predictions.view file where needed. These fields are commented out by default (See BQML under Notes). 177 | 178 | “events.view” 179 | The events view brings together the event level data defined in the various event_data_dimensions views. Additionally event-level dimensions and measures are defined in this view. 180 | 181 | As the event data is a representation of the original source rows from your events_* tables, there are a mixture of single-value fields and simple nested fields, as well as repeating key/value fields available within the unnested event_data fields. The single-value fields and simple nested fields are defined within this “events.view” file. The repeating key/value fields for the event parameters have been defined in “event_data_event_params.view”, and the repeating key/value fields for the user properties have been defined in “event_data_user_properties.view”. Both “event_data_event_params.view” and “event_data_user_properties.view” are extended into events.view. 182 | 183 | The definition for a repeating key/value field uses the following format: 184 | (SELECT value.*value_type* FROM UNNEST(*nested_field*) WHERE key = "*key_value*") 185 | 186 | 187 | Here is an example of LookML used to define a nested dimension. 188 | dimension: event_param_all_data { 189 | group_label: "Event: Parameters" 190 | label: "All Data" 191 | type: number 192 | sql: (SELECT value.double_value FROM UNNEST(event_params) WHERE key = "all_data") ;; 193 | } 194 | 195 | Using this method of sub-selecting allows a single row to return for an event with all event parameters selected in horizontally extending columns. If we were to unnest event_params directly and define the dimensions from the unnested results, there would be multiple rows per event: 196 | 197 | | Row* | Key | String Value | Int Value | Double Value | Float Value | 198 | |------|-----|--------------|------------|-------------|-------------| 199 | | 1 | a | null | null | 1.1 | null | 200 | | 2 | b | abc | null | null | null | 201 | | 3 | c | null | 61 | null | null | 202 | *Row Implied 203 | 204 | This is desired on some data, such as the nested ITEMS records. In the case of ITEMS, each nested record is a unique ITEM from the user's purchase, and expanding these into new rows makes sense for filtering and accurate aggregate measures. However, for the purposes of analysis at the event-level, we want one row with columns representing all of these possible keys. 205 | 206 | “event_data_event_params.view” 207 | Each event parameter you enable on GA4 will need to have a new dimension and any applicable measures created. The dimensions included in this block correspond to the list of automatically tracked events listed here https://support.google.com/analytics/answer/9234069?hl=en. 208 | 209 | If you are initiating the block with a large amount of custom event parameters already in place, it may be beneficial to obtain a list of them along with the value types that are populated: 210 | 211 | 212 | Sample Query for obtaining a list of all event parameter keys and their respective values: 213 | 214 | SELECT ep.key 215 | , case when count(value.string_value) > 0 then true else false end as string_value_populated 216 | , case when count(value.int_value) > 0 then true else false end as int_value_populated 217 | , case when count(value.double_value) > 0 then true else false end as double_value_populated 218 | , case when count(value.float_value) > 0 then true else false end as float_value_populated 219 | FROM \`YOUR\_PROJECT.GA4\_DATASET.events\_\*\` e 220 | , UNNEST(event_params) ep 221 | group by 1 222 | order by 1 asc 223 | 224 | “event_data_user_properties.view” 225 | Similar to the event parameters, user properties are likely to include custom attributes or tags. 226 | 227 | “goals.view” 228 | This file is to facilitate the creation of custom cohorts for analysis, based on any data available. It is another view file that is extended into “events.view”, and not directly referenced in the model file. By default, the goals are centered around the event name and the “page” value for that event. It is expected that these default goal points will be customized or expanded on with the addition of custom events and/or event parameters. Instructions on how to add new goals, or new variables to filter on in the goal dashboard, are provided in the view file. 229 | 230 | “page_data.view” 231 | Another file that is extended into “events.view”, and not referenced in the model directly. Page Data takes advantage of the ‘page_view_rank’ and ‘reverse_page_view_rank’ fields inserted during the initial CTE of the sessions table. These fields allow for analysis of ‘page_view’ events within a session without the need for another derived table. 232 | 233 | Similar to how the landing and exit pages are obtained at the session-level, we are able to query within the scope of the session from within the unnested element. For example we can obtain the 3rd page view in a session with this dimension: 234 | 235 | 236 | dimension: page_path_3 { 237 | view_label: "Page Flow" 238 | group_label: "Page Path" 239 | description: "3rd Page in Session." 240 | type: string 241 | sql: (select coalesce(regexp_extract((select value.string_value from UNNEST(event_history.event_params) where key = "page_location"),r"(?:.*?[\.][^\/]*)([\/][^\?]+)"),'/') 242 | from UNNEST(${sessions.event_data}) as event_history 243 | where event_history.page_view_rank = 3 244 | and event_history.event_name = "page_view" limit 1) ;; 245 | } 246 | 247 | If we look at the sql here, and remove the regular expression elements, this is what is occurring: 248 | The sessions table is linked to the events table on the model on the SL_KEY. 249 | When the UNNEST of event_data as event_history occurs, it happens from the scope of an event already associated with a session, and this unnesting is within the scope of the session (all unnested elements belong to the same SL_KEY). 250 | The page_location value for the event in the session to which the original event belongs, and also has a page_view_rank of 3 is returned. 251 | The process of looking “up” at the parent field, re-unnesting, and returning to the original event allows for horizontal columns of page activity to be returned for a single session. 252 | 253 | This series of sub-selects defines the page flow, relative path, and relative reverse path of ‘page_view’ events. These have been defined up to 9 iterations (9 Path Dimensions, 9 Relative Path Dimensions, 9 Relative Reverse Path Dimensions), but there is no limit. Additional length to the path can be added by adjusting the iteration on the sql definition of the desired field. 254 | 255 | “event_path.view” 256 | The event_path.view file is structured similarly to the “page_data.view” file, with an emphasis on event_rank instead of page_view_rank. Functionally the definition of the dimensions are the same, and this view is likewise extended into “events.view” instead of being referenced directly in the model. 257 | 258 | “page_funnel.view” 259 | The Page Funnel view is extended into “sessions.view”. The dimensions and measures defined here are purpose-built for use with a Page View Funnel/Flow. The same extraction of pages by rank as was used in “page_data.view” is utilized here, with definitions up to 6 pages present by default. 260 | 261 | The “tag” dimensions are what qualifies subsequent page views for inclusion in the resultset. If you filter for a value on Page 1, any subsequent page views that do not follow a qualifying “Page 1” event will be excluded from the measures defined in this view. This process repeats for all subsequently filtered page ranks (up to 6). This can be seen in the difference between the page_1_tag dimension and page_6_tag: 262 | 263 | 264 | dimension: page_1_tag { 265 | ... 266 | sql: case when {% condition page_1_filter %} ${page_1} {% endcondition %} 267 | and ${page_1} is not null then 1 else 0 end ;; } 268 | 269 | dimension: page_6_tag { 270 | ... 271 | sql: case when {% condition page_1_filter %} ${page_1} {% endcondition %} 272 | and {% condition page_2_filter %} ${page_2} {% endcondition %} 273 | and {% condition page_3_filter %} ${page_3} {% endcondition %} 274 | and {% condition page_4_filter %} ${page_4} {% endcondition %} 275 | and {% condition page_5_filter %} ${page_5} {% endcondition %} 276 | and {% condition page_6_filter %} ${page_6} {% endcondition %} 277 | and ${page_1} is not null and ${page_2} is not null and ${page_3} is not null 278 | and ${page_4} is not null and ${page_5} is not null and ${page_6} is not null 279 | then 1 else 0 end ;; } 280 | 281 | “event_funnel.view” 282 | The event_funnel view is set up similarly to “page_funnel.view”, and is extended into “sessions.view” instead of being referenced in the model. As with the page_funnel, you can easily add/remove further iterations to the funnel by adding new dimensions with incrementing event_rank references. Due to the nature of the event data populated in GA4, it is possible for several (3 or more) events to fire with the exact same timestamp. For example: When a new user visits a site, they will generate “First Visit”, “Session Start”, and “Page View” events with identical event_timestamps. Due to this, the practicality of this funnel is limited without enhancing the event being pulled to include additional event parameters. Instead of “event_name”, another calculated dimension [such as “Full Event”] could be used, or additional filters to exclude events outside of the scope of the request could be added to increase the utility of this view. 283 | 284 | ## Customizations 285 | * Event Parameters 286 | Each Event Parameter you enable on GA4 will need to have a new dimension and any applicable measures created, the dimensions included in this block correspond to the list of automatically tracked events [here] (https://support.google.com/analytics/answer/9234069?hl=en). 287 | 288 | Sample Query for obtaining a list of all event parameter keys and what value they use: 289 | ``` 290 | SELECT ep.key 291 | , case when count(value.string_value) > 0 then true else false end as string_value_populated 292 | , case when count(value.int_value) > 0 then true else false end as int_value_populated 293 | , case when count(value.double_value) > 0 then true else false end as double_value_populated 294 | , case when count(value.float_value) > 0 then true else false end as float_value_populated 295 | FROM \`YOUR\_PROJECT.GA4\_DATASET.events\_\*\` e 296 | , UNNEST(event_params) ep 297 | group by 1 298 | order by 1 asc 299 | ``` 300 | 301 | * Goals 302 | The Custom Goal Conversions by default are only focused on Event Type and Page Name. Typically the goals would include fields that are populated in instance-specific event parameters. To enable new goal filters, please see the goals.view file for guidance. 303 | 304 | ## Notes and Other Known Issues 305 | 306 | * The initial run of the Incremental Persistent Derived Table will execute with a where clause of "WHERE 1=1". This will query all historical data in your GA4 Dataset across all date-partitioned tables. If you do not wish to have all historical data, you can add a hard date filter to the where clause within the "session\_list\_with\_event\_history" cte on sessions.view's derived table definition. 307 | * If you are utilizing user\_id instead of user\_pseudo\_id, you will need to replace references to the user\_pseudo\_id with user\_id in the derived key ("sl\_key") definition in sessions.view's derived table definition, and in the user-centric measure definitions. 308 | * BQML Customer Purchase Propensity Score: This block includes a demonstration of utilizing GA4 data to train a BQML customer purchase propensity score. To ease implementation costs, this has been commented-out by default. To implement this feature, uncomment the BQML View Files and BQML Fields on the sessions.view file. 309 | 310 | ## Coming Soon 311 | 1. Leverage advanced analytics to be able to predict which customers are likely to make another purchase in the future based off of their historical actions. 312 | 2. Better understand your customers by looking at their natural pathing through pages and events through your pages alongside the ability to create completely custom page and event paths to conduct any A/B testing to see how customers are trending. 313 | 3. You can look at the successes of your marketing campaigns as well by using the campaign impact dashboard to identify a specific cohort of customers you targeted with a campaign and seeing how that particular customer base has trended over time to see if the campaign had any effect. 314 | 4. Looker will offer an out of the box data action to enable you to push data back into your GA console. 315 | -------------------------------------------------------------------------------- /dashboards/behavior.dashboard.lookml: -------------------------------------------------------------------------------- 1 | - dashboard: behavior 2 | title: "[GA4] Behavior" 3 | layout: newspaper 4 | preferred_viewer: dashboards-next 5 | elements: 6 | - title: Page Views 7 | name: Page Views 8 | model: ga4 9 | explore: sessions 10 | type: single_value 11 | fields: [events.total_page_views, events.total_unique_page_views] 12 | limit: 500 13 | column_limit: 50 14 | custom_color_enabled: true 15 | show_single_value_title: true 16 | show_comparison: true 17 | comparison_type: value 18 | comparison_reverse_colors: false 19 | show_comparison_label: true 20 | enable_conditional_formatting: true 21 | conditional_formatting_include_totals: false 22 | conditional_formatting_include_nulls: false 23 | custom_color: "#FFF" 24 | comparison_label: Unique Page Views 25 | conditional_formatting: [{type: not null, value: !!null '', background_color: "#c73727", 26 | font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 27 | palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab}, bold: false, italic: false, 28 | strikethrough: false, fields: !!null ''}] 29 | x_axis_gridlines: false 30 | y_axis_gridlines: true 31 | show_view_names: false 32 | show_y_axis_labels: true 33 | show_y_axis_ticks: true 34 | y_axis_tick_density: default 35 | y_axis_tick_density_custom: 5 36 | show_x_axis_label: true 37 | show_x_axis_ticks: true 38 | y_axis_scale_mode: linear 39 | x_axis_reversed: false 40 | y_axis_reversed: false 41 | plot_size_by_field: false 42 | trellis: '' 43 | stacking: '' 44 | limit_displayed_rows: false 45 | legend_position: center 46 | point_style: none 47 | show_value_labels: false 48 | label_density: 25 49 | x_axis_scale: auto 50 | y_axis_combined: true 51 | ordering: none 52 | show_null_labels: false 53 | show_totals_labels: false 54 | show_silhouette: false 55 | totals_color: "#808080" 56 | defaults_version: 1 57 | series_types: {} 58 | hidden_fields: [] 59 | y_axes: [] 60 | listen: 61 | Date: sessions.session_date 62 | Landing Page: sessions.landing_page 63 | row: 7 64 | col: 0 65 | width: 24 66 | height: 4 67 | - title: Top Pages 68 | name: Top Pages 69 | model: ga4 70 | explore: sessions 71 | type: looker_bar 72 | fields: [events.total_page_views, events.total_unique_page_views, events.event_param_page] 73 | filters: 74 | events.event_param_page: "-EMPTY" 75 | sorts: [events.total_page_views desc] 76 | limit: 500 77 | column_limit: 50 78 | x_axis_gridlines: false 79 | y_axis_gridlines: false 80 | show_view_names: false 81 | show_y_axis_labels: true 82 | show_y_axis_ticks: true 83 | y_axis_tick_density: default 84 | y_axis_tick_density_custom: 5 85 | show_x_axis_label: false 86 | show_x_axis_ticks: true 87 | y_axis_scale_mode: linear 88 | x_axis_reversed: false 89 | y_axis_reversed: false 90 | plot_size_by_field: false 91 | trellis: '' 92 | stacking: '' 93 | limit_displayed_rows: true 94 | legend_position: center 95 | point_style: circle 96 | show_value_labels: true 97 | label_density: 25 98 | x_axis_scale: auto 99 | y_axis_combined: true 100 | ordering: none 101 | show_null_labels: false 102 | show_totals_labels: false 103 | show_silhouette: false 104 | totals_color: "#808080" 105 | y_axes: [{label: '', orientation: bottom, series: [{axisId: events.total_page_views, 106 | id: events.total_page_views, name: Total Page Views}, {axisId: events.total_unique_page_views, 107 | id: events.total_unique_page_views, name: Total Unique Page Views}], showLabels: false, 108 | showValues: false, unpinAxis: false, tickDensity: default, tickDensityCustom: 5, 109 | type: linear}] 110 | size_by_field: event_data.total_unique_page_views 111 | limit_displayed_rows_values: 112 | show_hide: show 113 | first_last: first 114 | num_rows: '10' 115 | series_types: 116 | events.total_unique_page_views: scatter 117 | series_colors: 118 | events.total_page_views: "#B31412" 119 | events.total_unique_page_views: "#BDC1C6" 120 | label_color: ["#B31412", transparent] 121 | custom_color_enabled: true 122 | show_single_value_title: true 123 | show_comparison: true 124 | comparison_type: value 125 | comparison_reverse_colors: false 126 | show_comparison_label: true 127 | enable_conditional_formatting: true 128 | conditional_formatting_include_totals: false 129 | conditional_formatting_include_nulls: false 130 | custom_color: "#FFF" 131 | comparison_label: Unique Page Views 132 | conditional_formatting: [{type: not null, value: !!null '', background_color: "#c73727", 133 | font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 134 | palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab}, bold: false, italic: false, 135 | strikethrough: false, fields: !!null ''}] 136 | defaults_version: 1 137 | hidden_fields: [] 138 | listen: 139 | Date: sessions.session_date 140 | Landing Page: sessions.landing_page 141 | row: 11 142 | col: 0 143 | width: 10 144 | height: 10 145 | - title: Top Page Detail 146 | name: Top Page Detail 147 | model: ga4 148 | explore: sessions 149 | type: looker_grid 150 | fields: [events.event_param_page, events.total_page_views, events.total_unique_page_views, 151 | events.average_time_to_next_page, events.entrance_rate, events.bounce_rate, 152 | events.exit_rate] 153 | filters: 154 | events.event_param_page: "-EMPTY" 155 | sorts: [events.total_page_views desc] 156 | limit: 500 157 | column_limit: 50 158 | show_view_names: false 159 | show_row_numbers: true 160 | transpose: false 161 | truncate_text: true 162 | hide_totals: false 163 | hide_row_totals: false 164 | size_to_fit: true 165 | table_theme: white 166 | limit_displayed_rows: false 167 | enable_conditional_formatting: true 168 | header_text_alignment: left 169 | header_font_size: '12' 170 | rows_font_size: '12' 171 | conditional_formatting_include_totals: false 172 | conditional_formatting_include_nulls: false 173 | show_sql_query_menu_options: false 174 | show_totals: true 175 | show_row_totals: true 176 | series_cell_visualizations: 177 | event_data.total_page_views: 178 | is_active: false 179 | event_data.total_unique_page_views: 180 | is_active: true 181 | limit_displayed_rows_values: 182 | show_hide: show 183 | first_last: first 184 | num_rows: '10' 185 | conditional_formatting: [{type: along a scale..., value: !!null '', background_color: "#c73727", 186 | font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 187 | custom: {id: 2c56dd64-603d-8884-bf2c-89e6eeba3863, label: Custom, type: continuous, 188 | stops: [{color: "#FFFFFF", offset: 0}, {color: "#EA4335", offset: 50}, 189 | {color: "#B31412", offset: 100}]}, options: {steps: 5, constraints: { 190 | min: {type: percentile, value: 10}, max: {type: percentile, value: 99}}}}, 191 | bold: false, italic: false, strikethrough: false, fields: [events.bounce_rate, 192 | events.exit_rate]}, {type: along a scale..., value: !!null '', background_color: "#1A73E8", 193 | font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 194 | custom: {id: 0f27b0fc-14e6-c15e-9c53-7b0f52ed85b4, label: Custom, type: continuous, 195 | stops: [{color: "#FFFFFF", offset: 0}, {color: "#34A853", offset: 50}, 196 | {color: "#137333", offset: 100}]}, options: {steps: 5, constraints: { 197 | min: {type: minimum}, mid: {type: middle}, max: {type: percentile, value: 99}}, 198 | mirror: false, reverse: false, stepped: false}}, bold: false, italic: false, 199 | strikethrough: false, fields: [events.entrance_rate]}, {type: along a scale..., 200 | value: !!null '', background_color: "#1A73E8", font_color: !!null '', color_application: { 201 | collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab, 202 | options: {steps: 5, constraints: {min: {type: percentile, value: 1}, mid: { 203 | type: middle}, max: {type: percentile, value: 99}}, mirror: false, 204 | reverse: false, stepped: false}}, bold: false, italic: false, strikethrough: false, 205 | fields: [events.average_time_to_next_page]}] 206 | x_axis_gridlines: false 207 | y_axis_gridlines: false 208 | show_y_axis_labels: true 209 | show_y_axis_ticks: true 210 | y_axis_tick_density: default 211 | y_axis_tick_density_custom: 5 212 | show_x_axis_label: false 213 | show_x_axis_ticks: true 214 | y_axis_scale_mode: linear 215 | x_axis_reversed: false 216 | y_axis_reversed: false 217 | plot_size_by_field: false 218 | trellis: '' 219 | stacking: '' 220 | legend_position: center 221 | point_style: circle 222 | show_value_labels: true 223 | label_density: 25 224 | x_axis_scale: auto 225 | y_axis_combined: true 226 | ordering: none 227 | show_null_labels: false 228 | show_totals_labels: false 229 | show_silhouette: false 230 | totals_color: "#808080" 231 | y_axes: [{label: '', orientation: bottom, series: [{axisId: events.total_page_views, 232 | id: events.total_page_views, name: Total Page Views}, {axisId: events.total_unique_page_views, 233 | id: events.total_unique_page_views, name: Total Unique Page Views}], showLabels: false, 234 | showValues: false, unpinAxis: false, tickDensity: default, tickDensityCustom: 5, 235 | type: linear}] 236 | size_by_field: event_data.total_unique_page_views 237 | series_types: {} 238 | series_colors: 239 | events.total_page_views: "#B31412" 240 | events.total_unique_page_views: "#BDC1C6" 241 | label_color: ["#B31412", transparent] 242 | custom_color_enabled: true 243 | show_single_value_title: true 244 | show_comparison: true 245 | comparison_type: value 246 | comparison_reverse_colors: false 247 | show_comparison_label: true 248 | custom_color: "#FFF" 249 | comparison_label: Unique Page Views 250 | defaults_version: 1 251 | hidden_fields: [] 252 | listen: 253 | Date: sessions.session_date 254 | Landing Page: sessions.landing_page 255 | row: 11 256 | col: 10 257 | width: 14 258 | height: 10 259 | - name: '' 260 | type: text 261 | title_text: '' 262 | subtitle_text: '' 263 | body_text: "---\n
\n\t
\n\t\t

Landing Pages

\n
" 265 | row: 21 266 | col: 0 267 | width: 24 268 | height: 3 269 | - title: Top Landing Page 270 | name: Top Landing Page 271 | model: ga4 272 | explore: sessions 273 | type: looker_bar 274 | fields: [sessions.total_sessions, sessions.landing_page, sessions.percentage_new_users] 275 | sorts: [sessions.total_sessions desc] 276 | limit: 500 277 | column_limit: 50 278 | filter_expression: ${sessions.landing_page} != "null" 279 | x_axis_gridlines: false 280 | y_axis_gridlines: false 281 | show_view_names: false 282 | show_y_axis_labels: true 283 | show_y_axis_ticks: true 284 | y_axis_tick_density: default 285 | y_axis_tick_density_custom: 5 286 | show_x_axis_label: false 287 | show_x_axis_ticks: true 288 | y_axis_scale_mode: linear 289 | x_axis_reversed: false 290 | y_axis_reversed: false 291 | plot_size_by_field: false 292 | trellis: '' 293 | stacking: '' 294 | limit_displayed_rows: true 295 | legend_position: center 296 | point_style: circle 297 | show_value_labels: true 298 | label_density: 25 299 | x_axis_scale: auto 300 | y_axis_combined: true 301 | ordering: none 302 | show_null_labels: false 303 | show_totals_labels: false 304 | show_silhouette: false 305 | totals_color: "#808080" 306 | y_axes: [{label: '', orientation: bottom, series: [{axisId: sessions.total_sessions, 307 | id: sessions.total_sessions, name: Total Sessions}], showLabels: false, 308 | showValues: false, unpinAxis: false, tickDensity: default, tickDensityCustom: 5, 309 | type: linear}, {label: !!null '', orientation: bottom, series: [{axisId: sessions.percentage_new_users, 310 | id: sessions.percentage_new_users, name: Total New Users - Percentage}], 311 | showLabels: false, showValues: false, unpinAxis: false, tickDensity: default, 312 | tickDensityCustom: 5, type: linear}] 313 | size_by_field: '' 314 | limit_displayed_rows_values: 315 | show_hide: show 316 | first_last: first 317 | num_rows: '10' 318 | hidden_series: [of_total] 319 | series_types: 320 | sessions.percentage_new_users: scatter 321 | series_colors: 322 | sessions.total_sessions: "#F9AB00" 323 | of_total: "#facb04" 324 | sessions.percentage_new_users: "#1A73E8" 325 | label_color: ["#FBBC04", transparent] 326 | defaults_version: 1 327 | hidden_fields: [] 328 | listen: 329 | Date: sessions.session_date 330 | Landing Page: sessions.landing_page 331 | row: 24 332 | col: 0 333 | width: 10 334 | height: 14 335 | - title: Landing Page Detail 336 | name: Landing Page Detail 337 | model: ga4 338 | explore: sessions 339 | type: looker_grid 340 | fields: [sessions.landing_page, sessions.total_sessions, events.total_purchase_revenue_usd, 341 | events.transaction_conversion_rate, sessions.total_bounced_sessions_percentage, 342 | sessions.total_first_visit_sessions_percentage, sessions.average_session_duration, 343 | sessions.average_page_views_per_session] 344 | filters: {} 345 | sorts: [sessions.total_sessions desc] 346 | limit: 500 347 | filter_expression: ${sessions.landing_page} != "null" 348 | show_view_names: false 349 | show_row_numbers: true 350 | transpose: false 351 | truncate_text: false 352 | hide_totals: false 353 | hide_row_totals: false 354 | size_to_fit: true 355 | table_theme: white 356 | limit_displayed_rows: true 357 | enable_conditional_formatting: true 358 | header_text_alignment: left 359 | header_font_size: '12' 360 | rows_font_size: '12' 361 | conditional_formatting_include_totals: false 362 | conditional_formatting_include_nulls: false 363 | show_sql_query_menu_options: false 364 | show_totals: true 365 | show_row_totals: true 366 | series_labels: 367 | sessions.total_sessions: Sessions 368 | sessions.total_first_visit_sessions_percentage: New Session % 369 | sessions.average_session_duration: Avg. Session Duration 370 | sessions.average_page_views_per_session: Avg. Pages/Session 371 | sessions.total_bounced_sessions_percentage: Bounce Rate 372 | events.total_purchase_revenue_usd: Total Transaction Revenue (USD) 373 | events.transaction_conversion_rate: Transaction Conversion Rate 374 | series_column_widths: 375 | page_entrance_exit.landing_page: 400 376 | series_cell_visualizations: 377 | sessions.total_sessions: 378 | is_active: false 379 | limit_displayed_rows_values: 380 | show_hide: show 381 | first_last: first 382 | num_rows: '20' 383 | conditional_formatting: [{type: along a scale..., value: !!null '', background_color: "#1A73E8", 384 | font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 385 | custom: {id: fa3c8c8a-897c-aa1c-b569-cd8ca8fb0929, label: Custom, type: continuous, 386 | stops: [{color: "#FFFFFF", offset: 0}, {color: "#EA4335", offset: 50}, 387 | {color: "#B31412", offset: 100}]}, options: {steps: 5, constraints: { 388 | min: {type: percentile, value: 10}, mid: {type: middle}, max: {type: percentile, 389 | value: 99}}, mirror: false, reverse: false, stepped: false}}, bold: false, 390 | italic: false, strikethrough: false, fields: [sessions.total_bounced_sessions_percentage]}, 391 | {type: along a scale..., value: !!null '', background_color: "#1A73E8", font_color: !!null '', 392 | color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, custom: { 393 | id: 75d8e36b-a316-d634-6acd-3178ba62b4e7, label: Custom, type: continuous, 394 | stops: [{color: "#FFFFFF", offset: 0}, {color: "#34A853", offset: 50}, 395 | {color: "#137333", offset: 100}]}, options: {steps: 5, constraints: { 396 | min: {type: minimum}, mid: {type: middle}, max: {type: percentile, value: 99}}, 397 | mirror: false, reverse: false, stepped: false}}, bold: false, italic: false, 398 | strikethrough: false, fields: [events.total_purchase_revenue_usd]}, {type: along 399 | a scale..., value: !!null '', background_color: "#1A73E8", font_color: !!null '', 400 | color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, custom: { 401 | id: 913646fc-3538-c9f1-92b6-326d34356927, label: Custom, type: continuous, 402 | stops: [{color: "#FFFFFF", offset: 0}, {color: "#34A853", offset: 50}, 403 | {color: "#137333", offset: 100}]}, options: {steps: 5, constraints: { 404 | min: {type: minimum}, mid: {type: middle}, max: {type: percentile, value: 99}}, 405 | mirror: false, reverse: false, stepped: false}}, bold: false, italic: false, 406 | strikethrough: false, fields: [events.transaction_conversion_rate]}, {type: along 407 | a scale..., value: !!null '', background_color: "#1A73E8", font_color: !!null '', 408 | color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab, 409 | options: {steps: 5, constraints: {min: {type: percentile, value: 1}, mid: { 410 | type: middle}, max: {type: percentile, value: 99}}, mirror: false, 411 | reverse: false, stepped: false}}, bold: false, italic: false, strikethrough: false, 412 | fields: [sessions.total_first_visit_sessions_percentage]}, {type: along a 413 | scale..., value: !!null '', background_color: "#1A73E8", font_color: !!null '', 414 | color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab, 415 | options: {steps: 5, constraints: {min: {type: percentile, value: 1}, mid: { 416 | type: middle}, max: {type: percentile, value: 99}}, mirror: false, 417 | reverse: false, stepped: false}}, bold: false, italic: false, strikethrough: false, 418 | fields: [sessions.average_session_duration]}, {type: along a scale..., value: !!null '', 419 | background_color: "#1A73E8", font_color: !!null '', color_application: {collection_id: 7c56cc21-66e4-41c9-81ce-a60e1c3967b2, 420 | palette_id: 56d0c358-10a0-4fd6-aa0b-b117bef527ab, options: {steps: 5, constraints: { 421 | min: {type: minimum}, mid: {type: middle}, max: {type: percentile, value: 99}}, 422 | mirror: false, reverse: false, stepped: false}}, bold: false, italic: false, 423 | strikethrough: false, fields: [sessions.average_page_views_per_session]}] 424 | x_axis_gridlines: false 425 | y_axis_gridlines: true 426 | show_y_axis_labels: true 427 | show_y_axis_ticks: true 428 | y_axis_tick_density: default 429 | y_axis_tick_density_custom: 5 430 | show_x_axis_label: true 431 | show_x_axis_ticks: true 432 | y_axis_scale_mode: linear 433 | x_axis_reversed: false 434 | y_axis_reversed: false 435 | plot_size_by_field: false 436 | trellis: '' 437 | stacking: '' 438 | legend_position: center 439 | point_style: none 440 | show_value_labels: false 441 | label_density: 25 442 | x_axis_scale: auto 443 | y_axis_combined: true 444 | ordering: none 445 | show_null_labels: false 446 | show_totals_labels: false 447 | show_silhouette: false 448 | totals_color: "#808080" 449 | defaults_version: 1 450 | series_types: {} 451 | hidden_fields: [] 452 | y_axes: [] 453 | listen: 454 | Date: sessions.session_date 455 | Landing Page: sessions.landing_page 456 | row: 24 457 | col: 10 458 | width: 14 459 | height: 14 460 | - title: Top Keyword Searches 461 | name: Top Keyword Searches 462 | model: ga4 463 | explore: sessions 464 | type: looker_bar 465 | fields: [sessions.total_sessions, events.event_param_term] 466 | filters: {} 467 | sorts: [sessions.total_sessions desc] 468 | limit: 500 469 | column_limit: 50 470 | filter_expression: ${events.event_param_term} != "null" 471 | x_axis_gridlines: false 472 | y_axis_gridlines: false 473 | show_view_names: false 474 | show_y_axis_labels: true 475 | show_y_axis_ticks: true 476 | y_axis_tick_density: default 477 | y_axis_tick_density_custom: 5 478 | show_x_axis_label: false 479 | show_x_axis_ticks: true 480 | y_axis_scale_mode: linear 481 | x_axis_reversed: false 482 | y_axis_reversed: false 483 | plot_size_by_field: false 484 | trellis: '' 485 | stacking: '' 486 | limit_displayed_rows: true 487 | legend_position: center 488 | point_style: circle 489 | show_value_labels: true 490 | label_density: 25 491 | x_axis_scale: auto 492 | y_axis_combined: true 493 | ordering: none 494 | show_null_labels: false 495 | show_totals_labels: false 496 | show_silhouette: false 497 | totals_color: "#808080" 498 | y_axes: [{label: '', orientation: bottom, series: [{axisId: sessions.total_sessions, 499 | id: sessions.total_sessions, name: Total Sessions}], showLabels: false, 500 | showValues: false, unpinAxis: false, tickDensity: default, tickDensityCustom: 5, 501 | type: linear}, {label: !!null '', orientation: bottom, series: [{axisId: sessions.percentage_new_users, 502 | id: sessions.percentage_new_users, name: Total New Users - Percentage}], 503 | showLabels: false, showValues: false, unpinAxis: false, tickDensity: default, 504 | tickDensityCustom: 5, type: linear}] 505 | size_by_field: '' 506 | limit_displayed_rows_values: 507 | show_hide: show 508 | first_last: first 509 | num_rows: '10' 510 | hidden_series: [of_total] 511 | series_types: 512 | sessions.percentage_new_users: scatter 513 | series_colors: 514 | sessions.total_sessions: "#F9AB00" 515 | of_total: "#facb04" 516 | sessions.percentage_new_users: "#1A73E8" 517 | label_color: ["#FBBC04", transparent] 518 | defaults_version: 1 519 | hidden_fields: [] 520 | listen: 521 | Date: sessions.session_date 522 | Landing Page: sessions.landing_page 523 | row: 42 524 | col: 0 525 | width: 12 526 | height: 10 527 | - title: Top Events 528 | name: Top Events 529 | model: ga4 530 | explore: sessions 531 | type: looker_bar 532 | fields: [events.total_events, events.total_unique_events, events.full_event] 533 | filters: {} 534 | sorts: [events.total_events desc] 535 | limit: 500 536 | column_limit: 50 537 | x_axis_gridlines: false 538 | y_axis_gridlines: true 539 | show_view_names: false 540 | show_y_axis_labels: true 541 | show_y_axis_ticks: true 542 | y_axis_tick_density: default 543 | y_axis_tick_density_custom: 5 544 | show_x_axis_label: false 545 | show_x_axis_ticks: true 546 | y_axis_scale_mode: linear 547 | x_axis_reversed: false 548 | y_axis_reversed: false 549 | plot_size_by_field: false 550 | trellis: '' 551 | stacking: '' 552 | limit_displayed_rows: true 553 | legend_position: center 554 | point_style: circle 555 | show_value_labels: true 556 | label_density: 25 557 | x_axis_scale: auto 558 | y_axis_combined: true 559 | ordering: none 560 | show_null_labels: false 561 | show_totals_labels: false 562 | show_silhouette: false 563 | totals_color: "#808080" 564 | y_axes: [{label: '', orientation: bottom, series: [{axisId: events.total_events, 565 | id: events.total_events, name: Total Events}], showLabels: false, showValues: false, 566 | unpinAxis: false, tickDensity: default, tickDensityCustom: 5, type: linear}, 567 | {label: !!null '', orientation: bottom, series: [{axisId: events.total_unique_events, 568 | id: events.total_unique_events, name: Total Unique Events}], showLabels: false, 569 | showValues: false, unpinAxis: false, tickDensity: default, tickDensityCustom: 5, 570 | type: linear}] 571 | limit_displayed_rows_values: 572 | show_hide: show 573 | first_last: first 574 | num_rows: '10' 575 | series_types: 576 | events.total_unique_events: scatter 577 | series_colors: 578 | events.total_events: "#F9AB00" 579 | events.total_unique_events: "#1A73E8" 580 | defaults_version: 1 581 | hidden_fields: [] 582 | listen: 583 | Date: sessions.session_date 584 | Landing Page: sessions.landing_page 585 | row: 42 586 | col: 12 587 | width: 12 588 | height: 10 589 | - name: " (2)" 590 | type: text 591 | title_text: '' 592 | subtitle_text: '' 593 | body_text: "\n
\n\t
\n\t\t

Events

Event Name + Event\ 595 | \ Page

\n
" 596 | row: 38 597 | col: 12 598 | width: 12 599 | height: 4 600 | - name: " (3)" 601 | type: text 602 | title_text: '' 603 | subtitle_text: '' 604 | body_text: "
\n\t
\n\t\t

Keywords

Keyword of the traffic\ 606 | \ source, usually set when the medium is “organic” or “cpc” (i.e. What phrase\ 607 | \ did they search to get to find the website?)

\n
" 608 | row: 38 609 | col: 0 610 | width: 12 611 | height: 4 612 | - name: " (4)" 613 | type: text 614 | title_text: '' 615 | subtitle_text: '' 616 | body_text: "
\n\t
\n\t\t\n\t

\n\n
" 649 | row: 0 650 | col: 0 651 | width: 24 652 | height: 4 653 | - name: " (5)" 654 | type: text 655 | title_text: '' 656 | subtitle_text: '' 657 | body_text: "---\n
\n\t
\n\t\t

Behavior

\n
" 659 | row: 4 660 | col: 0 661 | width: 24 662 | height: 3 663 | filters: 664 | - name: Date 665 | title: Date 666 | type: field_filter 667 | default_value: 7 day 668 | allow_multiple_values: true 669 | required: false 670 | ui_config: 671 | type: relative_timeframes 672 | display: inline 673 | options: [] 674 | model: ga4 675 | explore: sessions 676 | listens_to_filters: [] 677 | field: sessions.session_date 678 | - name: Landing Page 679 | title: Landing Page 680 | type: field_filter 681 | default_value: '' 682 | allow_multiple_values: true 683 | required: false 684 | ui_config: 685 | type: tag_list 686 | display: popover 687 | options: [] 688 | model: ga4 689 | explore: sessions 690 | listens_to_filters: [] 691 | field: sessions.landing_page --------------------------------------------------------------------------------