Customer360¶
The 360-degree view of the customer includes every interaction, from a website inquiry to a product purchase to a customer support ticket. A comprehensive 360-degree view of the customers has economic benefits like increased revenues with better cross-selling and up-selling opportunities. Organizations can also support better customer experience for more personalized marketing experiences - driving higher conversation rates and revenues.
Customer 360 allows businesses to target specific clusters of customers with communications that are much more relevant for their particular behavior - and thus generate much higher response rates, plus increased loyalty and customer lifetime value. Businesses today have extensive data on their existing customers - such as purchase history, browsing history, prior campaign response patterns, and demographics - that can be used to identify specific groups of customers that can be addressed.
The biggest challenges in implementing a customer 360 are the fragmentation and inconsistency of data. This data is often stored in various data stores and across disparate systems, lacking a standardized format, exact dimensions, or a consensus on definitions. The issue is multifaceted for teams designing the customer 360, as they must decide on a list of measures. Questions arise, such as whether these measures are understood across the organization, which set of records should be considered in measure calculations, what the roll-up strategy should be, and which dimensions should be considered for aggregations.
DataOS Lens can address the above challenges.
Customer360 Lens¶
Customer 360 Lens is a implementation of DataOS Lens following the activity-schema standard. At its core, an activity schema is a data modeling paradigm consisting of two major concepts - customer and their activity stream. It models an entity taking a sequence of activities over time. For example, a customer(entity) viewed a web page(activity), purchased a product(activity), raised a complaint(activity) etc. Each row in the activity stream represents a single activity taken by the entity at a time. Every activity has metadata associated with it beyond the customer, the activity, and the timestamp. A ‘purchased product’ activity will want to store the actual SKU id of the product, brand, supplier, and product price. One can extend this concept to create company 360, product 360, vendor 360, etc.
There are two core entities to the customer360 Lens - customer and activity stream. Then one can extend the activity stream entity to create complementary entities to support different use cases. Here we have three entities that are extensions of the activity stream
- order placed stream
- order rejected stream
- order invoiced stream
One can answer the following questions from the lens which can be analyzed across customer and product dimensions
- RFM measures
- Percentage of orders rejected or invoiced
- The average number of days taken to invoice an order
- Customers with the count of rejected orders last month greater than the annual average
- Many more.
Entity | Related To | Relationship | Fields and Dimensions | Measure |
---|---|---|---|---|
customer | order_placed , order_rejected , order_invoiced |
1:N , 1:N , 1:N |
customer_id , customer_name , email , phone_number , address , customer_no , state , county_name , zip , premise_code , license_classification , license_type , channel_code , selling_division_name , site , consent |
count_customers , percentage_email , percentage_phone , percentage_address |
order_placed | order_rejected , order_invoiced |
1:1 , 1:1 |
activity_uuid , entity_id , order_id , product_id , product_classification , cases , order_value , request_delivery_date , activity_occurence , activity_repeated_at , brand_name , supplier_name , product_category , order_no |
recency , frequency , monetary |
order_rejected | customer |
N:1 |
activity_uuid , entity_id , ref_order_id , activity_ts , product_id , order_reject_code , order_status_code , order_delivery_status , cases , bottles , order_value , request_delivery_date , activity_occurence , activity_repeated_at |
recency , frequency |
order_invoiced | customer |
N:1 |
activity_uuid , entity_id , ref_order_id , activity_ts , product_id , brand_name , supplier_name , product_category , product_classification , cases , bottles , order_value , request_delivery_date , activity_occurence , activity_repeated_at |
name: customer_360
description: Data Model to answer any questions around a customer.
contract: customer_360
owner: iamgroot
tags:
- c360
- activity_schema
- segment
entities:
- name: customer
sql:
query: >
SELECT * FROM icebase.audience.customers_large_data
columns:
- name: customer_id
- name: customer_name
- name: email
- name: phone_number
- name: address
- name: customer_no
- name: site
- name: state
- name: county_name
- name: zip
- name: premise_code
- name: status
- name: license_classification
- name: license_type
- name: channel_code
- name: channel_name
- name: selling_division_name
- name: consent
verified: true
tables:
- icebase.audience.customers_large_data
fields:
- name: customer_id
type: string
description: unique identifier of the customer
column: customer_id
primary: true
tags:
- customer_identifier
- name: customer_name
type: string
description: Business name the customer operates under
column: customer_name
tags:
- name_identifier
- name: email
type: string
description: email address of the customer
column: email
tags:
- email_identifier
- name: phone_number
type: string
description: contact number of the customer
column: phone_number
tags:
- phone_identifier
- name: address
type: string
description: postal address of the customer
column: address
tags:
- address_identifier
- name: customer_no
type: string
description: customer identifier only unique within the site
column: customer_no
- name: state
type: string
description: state code where the customer physical address is located
column: state
- name: county_name
type: string
description: name of the county
column: county_name
- name: zip
type: string
description: ZIP code associate with the customer physical address
column: zip
- name: premise_code
type: string
description: premise code - on prem, off prem
column: premise_code
- name: status
type: string
description: customer status - active, inactive, suspended
column: status
- name: license_classification
type: string
description: used to identify customer tier
column: license_classification
- name: license_type
type: string
description: type of license
column: license_type
- name: channel_code
type: string
description: indicates whether chain is a grocery, hotel etc
column: channel_code
- name: selling_division_name
type: string
description: internal division responsible for the order
column: selling_division_name
- name: site
type: string
description: site number
column: site
- name: channel_name
type: string
description: channel description
column: channel_name
- name: consent
type: string
description: consent to use data for recommendation
column: consent
measures:
- name: count_customers
sql_snippet: ${customer.customer_id}
type: count
description: count of total customers
hidden: true
tags:
- total_customers
- name: percentage_email
sql_snippet: round(100*count(${customer.email})/cast(count(*) as double),2)
type: number
description: percentage customers with email
hidden: true
tags:
- email_reachability
- name: percentage_phone
sql_snippet: round(100*count(${customer.phone_number})/cast(count(*) as double),2)
type: number
description: percentage customers with email
hidden: true
tags:
- phone_reachability
- name: percentage_address
sql_snippet: round(100*count(${customer.address})/cast(count(*) as double),2)
type: number
description: percentage customers with email
hidden: true
tags:
- address_reachability
relationships:
- type: 1:N
field: customer_id
target:
name: order_placed
field: entity_id
verified: true
- type: 1:N
field: customer_id
target:
name: order_rejected
field: entity_id
verified: true
- type: 1:N
field: customer_id
target:
name: order_invoiced
field: entity_id
verified: true
- name: order_placed
sql:
query: >
SELECT
activity_uuid,
entity_id,
trim(feature1) as order_id,
activity_ts,
trim(feature2) as product_id,
trim(feature3) as brand_name,
trim(feature4) as supplier_name,
trim(feature5) as product_category,
trim(feature6) as product_classification,
cast(feature7 as double) as cases,
cast(feature8 as double) as bottles,
cast(feature9 as double) as order_value,
feature10 as request_delivery_date,
activity_occurence,
activity_repeated_at
FROM icebase.audience.activity_streams_large_data where activity = 'order_placed'
columns:
- name: activity_uuid
- name: entity_id
- name: activity_ts
- name: order_id
- name: product_id
- name: brand_name
- name: supplier_name
- name: product_category
- name: product_classification
- name: cases
- name: bottles
- name: order_value
- name: request_delivery_date
- name: activity_occurence
- name: activity_repeated_at
verified: true
tables:
- icebase.audience.activity_streams_large_data
fields:
- name: activity_uuid
type: string
description: unique identifier of the activity event
column: activity_uuid
primary: true
- name: entity_id
type: string
description: customer identifier
column: entity_id
- name: order_id
type: string
description: order identifier
column: order_id
- name: activity_ts
type: date
description: timestamp of the moment when activity_occured
column: activity_ts
- name: product_id
type: string
description: product identifier
column: product_id
- name: product_classification
type: string
description: classification of the product
column: product_classification
- name: cases
type: number
description: count of cases the order was placed for
column: cases
- name: bottles
type: number
description: count of bottles the order was placed for
column: bottles
- name: order_value
type: number
description: value of the order placed
column: order_value
- name: request_delivery_date
type: date
description: requested delivery date
column: request_delivery_date
- name: activity_occurence
type: number
description: how many times this activity has happened to this customer
column: activity_occurence
- name: activity_repeated_at
type: date
description: The date of the next instance of this activity for this customer
column: activity_repeated_at
- name: brand_name
type: string
description: name of the brand
column: brand_name
- name: supplier_name
type: string
description: name of the supplier
column: supplier_name
- name: product_category
type: string
description: category of the product
column: product_category
dimensions:
- name: order_no
type: string
description: unique order_no for a customer
sql_snippet: concat(${order_placed.entity_id},'-',split_part(${order_placed.order_id},'-',1))
hidden: true
measures:
- name: recency
sql_snippet: day(current_date - ${order_placed.activity_ts})
type: min
description: days since last order was placed
- name: frequency
sql_snippet: ${order_placed.order_no}
type: count_distinct
description: count of total activities
- name: monetary
sql_snippet: ${order_placed.order_value}
type: sum
description: total order value
relationships:
- type: 1:1
field: order_id
target:
name: order_rejected
field: ref_order_id
- type: 1:1
field: order_id
target:
name: order_invoiced
field: ref_order_id
- name: order_rejected
sql:
query: >
SELECT
activity_uuid,
entity_id,
trim(feature1) as ref_order_id,
activity_ts,
trim(feature2) as product_id,
trim(feature3) as order_reject_code,
trim(feature4) as order_status_code,
trim(feature5) as order_delivery_status,
cast(feature7 as double) as cases,
cast(feature8 as double) as bottles,
cast(feature9 as double) as order_value,
feature10 as request_delivery_date,
activity_occurence,
activity_repeated_at
FROM icebase.audience.activity_streams_large_data where activity = 'order_rejected'
columns:
- name: activity_uuid
- name: entity_id
- name: ref_order_id
- name: activity_ts
- name: product_id
- name: order_reject_code
- name: order_status_code
- name: order_delivery_status
- name: cases
- name: bottles
- name: order_value
- name: request_delivery_date
- name: activity_occurence
- name: activity_repeated_at
verified: true
tables:
- icebase.audience.activity_streams_large_data
fields:
- name: activity_uuid
type: string
description: unique identifier of the activity event
column: activity_uuid
primary: true
- name: entity_id
type: string
description: customer identifier
column: entity_id
- name: ref_order_id
type: string
description: order identifier
column: ref_order_id
- name: activity_ts
type: date
description: timestamp of the moment when activity_occured
column: activity_ts
- name: product_id
type: string
description: product identifier
column: product_id
- name: cases
type: number
description: count of cases the order was placed for
column: cases
- name: bottles
type: number
description: count of bottles the order was placed for
column: bottles
- name: order_value
type: number
description: value of the order placed
column: order_value
- name: request_delivery_date
type: date
description: requested delivery date
column: request_delivery_date
- name: activity_occurence
type: number
description: how many times this activity has happened to this customer
column: activity_occurence
- name: activity_repeated_at
type: date
description: The date of the next instance of this activity for this customer
column: activity_repeated_at
- name: order_reject_code
type: string
description: code for rejection
column: order_reject_code
- name: order_status_code
type: string
description: code for order status
column: order_status_code
- name: order_delivery_status
type: string
description: status of order delivery
column: order_delivery_status
dimensions:
- name: order_no
type: string
description: unique order_no for a customer
sql_snippet: concat(${order_rejected.entity_id},'-',split_part(${order_rejected.ref_order_id},'-',1))
hidden: true
measures:
- name: recency
sql_snippet: day(current_date - ${order_rejected.activity_ts})
type: min
description: days since last order was cancelled
- name: frequency
sql_snippet: ${order_rejected.order_no}
type: count_distinct
description: count of total order cancelled
- name: order_invoiced
sql:
query: >
SELECT
activity_uuid,
entity_id,
trim(feature1) as ref_order_id,
activity_ts,
trim(feature2) as product_id,
trim(feature3) as brand_name,
trim(feature4) as supplier_name,
trim(feature5) as product_category,
trim(feature6) as product_classification,
cast(feature7 as double) as cases,
cast(feature8 as double) as bottles,
cast(feature9 as double) as order_value,
feature10 as request_delivery_date,
activity_occurence,
activity_repeated_at
FROM icebase.audience.activity_streams_large_data where activity = 'order_invoiced'
columns:
- name: activity_uuid
- name: entity_id
- name: ref_order_id
- name: activity_ts
- name: product_id
- name: brand_name
- name: supplier_name
- name: product_category
- name: product_classification
- name: cases
- name: bottles
- name: order_value
- name: request_delivery_date
- name: activity_occurence
- name: activity_repeated_at
verified: true
tables:
- icebase.audience.activity_streams_large_data
fields:
- name: activity_uuid
type: string
description: unique identifier of the activity event
column: activity_uuid
primary: true
- name: entity_id
type: string
description: customer identifier
column: entity_id
- name: ref_order_id
type: string
description: order identifier
column: ref_order_id
- name: activity_ts
type: date
description: timestamp of the moment when activity_occured
column: activity_ts
- name: product_id
type: string
description: product identifier
column: product_id
- name: product_classification
type: string
description: product classification
column: product_classification
- name: cases
type: number
description: case quantity
column: cases
- name: bottles
type: number
description: bottle quantity
column: bottles
- name: order_value
type: number
description: order value
column: order_value
- name: activity_occurence
type: number
description: how many times this activity has happened to this customer
column: activity_occurence
- name: activity_repeated_at
type: date
description: The date of the next instance of this activity for this customer
column: activity_repeated_at