Description:  Tools & Technologies; This project was developed using SQL Server, Python, Power BI, and Tableau, with a strong focus on Product Analytics, E-commerce Analytics, Customer Behavior, Funnel Analysis, and A/B Testing.  Throughout the project, I used the following tools and analytical techniques:

SQL Server

  • Database Design and Development
  • Database Schema
  • Relational Tables
  • Primary Keys and Foreign Keys
  • Relationships and Constraints
  • Database Normalization (3NF)
  • ER Diagram
  • Data Dictionary
  • AI-Generated Dataset
  • CSV Data Files
  • SQL Scripts
  • Data Cleaning and Transformation
  • Joins and Subqueries
  • Common Table Expressions (CTEs)
  • Window Functions
  • Views
  • Stored Procedures and Functions
  • KPI and Business Analysis
  • Funnel and Conversion Analysis

Python

  • Data Cleaning and Preparation
  • Exploratory Data Analysis (EDA)
  • Pandas and NumPy
  • Data Manipulation
  • Functions and Variables
  • Statistical Analysis
  • Customer and Session Segmentation
  • Funnel and Drop-off Analysis
  • Conversion Analysis
  • A/B Test Analysis
  • Statistical Significance Testing
  • Confidence Intervals
  • Data Visualization

Power BI

  • Data Modeling
  • Table Relationships
  • DAX Measures
  • KPI Development
  • Interactive Dashboards
  • Product and Customer Analytics
  • Funnel Analysis
  • Conversion and Revenue Analysis
  • Data Visualization
  • Business Insights and Reporting

Tableau

  • Data Preparation
  • Calculated Fields
  • KPIs
  • Interactive Dashboards
  • Data Visualization
  • Charts and Graphs
  • Search Performance Analysis
  • Customer Behavior Analysis
  • Product Performance Analysis
  • Funnel Visualization
  • A/B Test Result Visualization

A/B Testing & Experimentation

  • Experiment Design
  • Business Hypothesis Development
  • Control and Treatment Groups
  • Random Assignment
  • Primary and Guardrail Metrics
  • Sample Analysis
  • Conversion Rate Comparison
  • Absolute and Relative Uplift
  • Statistical Significance
  • Confidence Intervals
  • Experiment Result Interpretation
  • Product Recommendations

Product & E-commerce Analytics

  • Customer Journey Analysis
  • Search and Product Discovery Analysis
  • Search CTR
  • Zero-Result Search Rate
  • Search-to-Purchase Conversion
  • Product View Rate
  • Add-to-Cart Rate
  • Checkout Rate
  • Purchase Conversion Rate
  • Funnel Drop-off Analysis
  • Revenue per Session
  • Revenue per User
  • Average Order Value (AOV)
  • Customer and Session Segmentation
  • High-Engagement / Low-Conversion Segment Analysis
  • Product, Brand, and Category Performance

The project follows an end-to-end analytical workflow:

Database Design → Data Generation → SQL Analysis → Data Exploration → Product & Search Analytics → Funnel Analysis → Segmentation → A/B Testing → Dashboard Development → Business Recommendations

Title:

ShopSense, E-commerce Product & Customer Analytics

Project Overview:

Summery:

ShopSense is a fictional e-commerce analytics project designed to simulate a real-world product discovery and customer journey environment. The project focuses on understanding how users interact with an online store from their initial search through product discovery, product engagement, cart activity, checkout, and final purchase.

The primary objective of the project is to investigate an important product analytics question:

Why do some users demonstrate strong search and product engagement but fail to convert into customers?

To answer this question, ShopSense is structured as an end-to-end product analytics case study, combining database design, SQL analysis, Python analytics, business intelligence dashboards, customer segmentation, funnel analysis, and A/B testing.

Project Objectives

The project is designed to analyze the complete customer journey and identify behavioral patterns that influence conversion and revenue.

The main objectives are to:

Measure user engagement throughout the product discovery journey.

Analyze the Search → Product View → Add to Cart → Checkout → Purchase funnel.

Identify stages with the highest user drop-off.

Evaluate the effectiveness of product search and discovery.

Identify search queries or customer segments with high engagement but unexpectedly low conversion.

Analyze relationships between search behavior, product interaction, conversion, and revenue.

Measure key product and e-commerce metrics such as Search CTR, Add-to-Cart Rate, Checkout Rate, Conversion Rate, Search Exit Rate, Revenue per Session, and Revenue per User.

Segment users and sessions based on behavioral and commercial characteristics.

Design and analyze A/B experiments to determine whether changes to the product discovery experience generate statistically meaningful improvements.

Translate analytical findings into actionable product and business recommendations.

Database Design Approach

The ShopSense database is designed to reproduce the event-driven structure commonly found in modern e-commerce platforms.

Rather than storing only customers and transactions, the database captures the sequence of interactions that occur throughout a user’s shopping journey.

The data model follows the customer lifecycle:

User → Session → Search → Product Discovery → Product View → Cart → Checkout → Order

Each stage generates analytical data that can be connected through relational keys. This structure makes it possible to reconstruct individual customer journeys and analyze where users progress, abandon the funnel, or convert.

The database is organized around several major subject areas:

Customer & Session Data

Stores user profiles, acquisition information, devices, geographic attributes, and browsing sessions.

Product & Catalog Data

Contains products, categories, brands, pricing, inventory-related attributes, and other information required to analyze product performance.

Search & Product Discovery Data

Captures search queries, search results or impressions, result positions, clicks, and zero-result searches. This area enables analysis of search effectiveness and product discovery behavior.

Behavioral Event Data

Records important customer actions such as product views, add-to-cart events, cart removals, checkout initiation, and other funnel interactions.

Transaction Data

Stores orders, order items, quantities, prices, discounts, and revenue information, allowing behavioral activity to be connected directly with commercial outcomes.

Experimentation Data

Stores A/B test assignments and experiment-related information so that user behavior and business outcomes can be compared between Control and Treatment groups.

Analytical Structure

The database will support several connected layers of analysis.

At the descriptive level, SQL and BI tools will be used to calculate KPIs and understand overall product, search, customer, and revenue performance.

At the behavioral level, funnel and segmentation analysis will identify where different groups of users experience friction.

At the diagnostic level, SQL and Python will be used to investigate why highly engaged users sometimes fail to purchase and determine which search queries, products, devices, acquisition channels, or customer segments contribute most strongly to conversion loss.

At the experimental level, A/B testing will evaluate proposed improvements to the product discovery experience using statistical measures such as conversion uplift, confidence intervals, and statistical significance.

Finally, the findings will be transformed into business and product recommendations, connecting technical analysis directly to measurable outcomes such as improved conversion, reduced funnel abandonment, and increased revenue.

Project Workflow

The complete analytical workflow follows:

Database Design → Data Generation → SQL Analysis → Exploratory Analysis → Funnel Analysis → Customer Segmentation → A/B Testing → Dashboard Development → Business Recommendations

The project will use SQL Server, Python, Power BI, and Tableau, with GitHub serving as the final portfolio repository for database scripts, analytical queries, notebooks, dashboards, documentation, and project findings.

The final result will demonstrate not only how e-commerce data can be queried and visualized, but how product analytics can be used to move from a business problem to evidence-based decisions and measurable product improvements.

ShopSense Database Overview

The ShopSense Database is a relational e-commerce analytics database designed to simulate how users interact with an online shopping platform throughout the complete product discovery and purchasing journey.

The database captures customer activity from the moment a user enters the platform and starts a browsing session through search, product discovery, product views, cart interactions, checkout, and purchase.

Unlike a traditional transactional database that focuses primarily on customers, products, and orders, ShopSense also captures behavioral events and experimentation data. This enables deeper analysis of customer behavior, search effectiveness, funnel performance, conversion, revenue, and A/B testing.

The database is designed around the following analytical journey:

User → Session → Search → Search Results / Impressions → Product View → Cart → Checkout → Purchase

Additional product, marketing, and experimentation data are connected to this journey to provide the context required for advanced product analytics.

Database Subject Areas

The database is organized into seven logical subject areas.

1. Customer Management

Stores information about registered and guest users interacting with the ShopSense platform.

Main Table:

Users

Typical attributes include:

  • User ID
  • Registration Date
  • Customer Type
  • Age Group
  • Country
  • Region
  • Acquisition Source

This information allows customer behavior and conversion to be analyzed across different user segments.

2. Session & Traffic Management

Tracks individual visits to the ShopSense platform.

Main Table:

Sessions

Each session represents a user’s interaction with the platform during a specific visit.

Session data can include:

  • Session ID
  • User ID
  • Session Start
  • Session End
  • Device Type
  • Traffic Source
  • Campaign
  • Landing Page

Sessions provide the foundation for calculating metrics such as **Conversion Rate, Revenue per Session, Search Usage Rate, and Session Engagement.

3. Product & Catalog Management

Stores the products available through ShopSense and their organizational structure.

Main Tables:

Categories

Brands

Products

Product information can include:

  • Product ID
  • Product Name
  • Category
  • Brand
  • Price
  • Discount
  • Rating
  • Stock Status

These tables allow product performance to be analyzed across categories, brands, price ranges, and other commercial characteristics.

4. Search & Product Discovery

Captures how customers search for and discover products.

Main Tables:

Searches

SearchImpressions

SearchClicks

The search layer records:

  • Search Query
  • Search Timestamp
  • Number of Results
  • Product Impressions
  • Search Result Position
  • Product Clicks
  • Click Position

This structure enables analysis of important product discovery metrics including:

Search CTR

Zero-Result Search Rate

Search Exit Rate

Search-to-Product-View Rate

Search-to-Purchase Conversion Rate

It also allows us to investigate whether users are finding relevant products and whether high search engagement ultimately leads to purchases.

5. Customer Behavioral Events

Tracks important actions that occur after product discovery.

Main Tables:

ProductViews

CartEvents

CheckoutEvents

These events allow the customer journey to be reconstructed as:

Search → Product View → Add to Cart → Checkout → Purchase

Cart events can distinguish between actions such as:

  • Add to Cart
  • Remove from Cart
  • Quantity Change

This structure makes detailed funnel and drop-off analysis possible.

6. Orders & Revenue

Stores completed transactions and purchased products.

Main Tables:

Orders

OrderItems

Order-level information can include:

Order ID

User ID

Session ID

Order Date

Order Status

Total Amount

Discount Amount

Shipping Amount

OrderItems connect individual products to each transaction and enable analysis of:

Revenue

Average Order Value

Units Sold

Product Revenue

Category Revenue

Revenue per User

Revenue per Session

7. Experimentation & A/B Testing

Stores information required to simulate and analyze product experiments.

Main Tables:

Experiments

ExperimentVariants

ExperimentAssignments

An experiment can compare two or more versions of a product experience.

For example:

Control (A): Existing search ranking experience

Treatment (B): Improved personalized product ranking

Users or sessions are assigned to experiment variants and their subsequent behavior can be compared.

This enables analysis of:

Conversion Rate

Search CTR

Add-to-Cart Rate

Revenue per Session

Experiment Uplift

Confidence Intervals

Statistical Significance

The experimentation layer allows ShopSense to move beyond descriptive analytics and evaluate whether proposed product changes produce measurable improvements.

Proposed Database Structure

The initial ShopSense database will contain approximately 16 core relational tables:

1. Users

2. Sessions

3. Categories

4. Brands

5. Products

6. Searches

7. SearchImpressions

8. SearchClicks

9. ProductViews

10. CartEvents

11. CheckoutEvents

12. Orders

13. OrderItems

14. Experiments

15. ExperimentVariants

16. ExperimentAssignments

Additional supporting tables can be introduced later only when they provide meaningful analytical value.

Core Database Relationships

The central analytical structure of the database follows:

Users

↓

Sessions

↓

Searches

↓

SearchImpressions

↓

SearchClicks

↓

ProductViews

↓

CartEvents

↓

CheckoutEvents

↓

Orders

↓

OrderItems

At the same time:

Categories → Products

Brands → Products

and:

Experiments → ExperimentVariants → ExperimentAssignments → Users / Sessions

Together, these relationships make it possible to connect who the customer is, how they arrived, what they searched for, which products they discovered, how they interacted with those products, whether they entered the purchasing funnel, whether they converted, and how much revenue they generated.

Analytical Capabilities

The ShopSense database is designed to support:

Customer Analytics: user behavior, customer segmentation, new vs. returning users and acquisition analysis.

Search Analytics: search queries, zero-result searches, search CTR, ranking position, search engagement and search-to-purchase conversion.

Product Analytics: product views, clicks, cart activity, product conversion and product/category performance.

Funnel Analytics: Search → View → Cart → Checkout → Purchase conversion and drop-off analysis.

Revenue Analytics: revenue, AOV, revenue per user/session and product/category contribution.

Segmentation Analysis: behavioral, acquisition, device, product and search-based customer segments.

Experimentation Analytics: control vs. treatment comparison, uplift measurement and statistical testing.

The database therefore provides the foundation for an end-to-end analytics workflow using SQL Server, Python, Power BI, and Tableau.

ShopSense, Database Schema:

Database Design Strategy

The database is designed to maintain Third Normal Form (3NF) wherever it is practical, while avoiding unnecessary complexity for Product Analytics. This approach creates a clean, scalable, and analytics-friendly database that supports efficient querying, reporting, and dashboard development.

1. Users

The Users table stores the core information for each customer and serves as the primary entity for user-related analytics throughout the database. It contains the foundational user profile data that connects to orders, sessions, reviews, wishlists, and other customer activities.

| Column            | Data Type   | Key | Description                 |

| —————– | ———– | — | ————————— |

| UserID            | INT         | PK  | Unique user identifier      |

| RegistrationDate  | DATE        |     | Registration date           |

| CustomerType      | VARCHAR(20) |     | New / Returning             |

| AgeGroup          | VARCHAR(20) |     | Customer age segment        |

| Country           | VARCHAR(50) |     | Country                     |

| Region            | VARCHAR(50) |     | Region/state                |

| AcquisitionSource | VARCHAR(50) |     | Original acquisition source |

| IsRegistered      | BIT         |     | Registered vs guest         |

| IsActive          | BIT         |     | Active customer status      |

Note: Sensitive personal information such as Name, Email, and Phone Number is intentionally excluded, as this project focuses on user behavior and product analytics rather than personally identifiable information (PII).

2. Sessions

Records each user session and activity within the ShopSense platform.

| Column                 | Data Type    | Key | Description                          |

| ———————- | ———— | — | ———————————— |

| SessionID              | BIGINT       | PK  | Unique session                       |

| UserID                 | INT          | FK  | → Users.UserID                       |

| SessionStart           | DATETIME2    |     | Session start                        |

| SessionEnd             | DATETIME2    |     | Session end                          |

| DeviceType             | VARCHAR(20)  |     | Desktop / Mobile / Tablet            |

| TrafficSource          | VARCHAR(50)  |     | Organic, Paid, Direct, Social, Email |

| Campaign               | VARCHAR(100) |     | Marketing campaign                   |

| LandingPage            | VARCHAR(100) |     | First page                           |

| Browser                | VARCHAR(30)  |     | Browser                              |

| SessionDurationSeconds | INT          |     | Session duration                     |

Users 1 → N Sessions

3. Categories

Product Category Structure

| Column           | Data Type    | Key | Description             |

| —————- | ———— | — | ———————– |

| CategoryID       | INT          | PK  | Category identifier     |

| CategoryName     | VARCHAR(100) |     | Category name           |

| ParentCategoryID | INT          | FK  | → Categories.CategoryID |

| IsActive         | BIT          |     | Active status           |

The ParentCategoryID field allows us to create hierarchical category structures, such as:

Electronics → Headphones

4. Brands

| Column          | Data Type    | Key | Description      |

| ————— | ———— | — | —————- |

| BrandID         | INT          | PK  | Brand identifier |

| BrandName       | VARCHAR(100) |     | Brand            |

| CountryOfOrigin | VARCHAR(50)  |     | Origin           |

| IsActive        | BIT          |     | Active status    |

5. Products

One of the most important dimension tables in the project.

| Column          | Data Type     | Key | Description           |

| ————— | ————- | — | ——————— |

| ProductID       | INT           | PK  | Product identifier    |

| ProductName     | VARCHAR(150)  |     | Product name          |

| CategoryID      | INT           | FK  | → Categories          |

| BrandID         | INT           | FK  | → Brands              |

| ListPrice       | DECIMAL(10,2) |     | Standard price        |

| DiscountPercent | DECIMAL(5,2)  |     | Current discount      |

| Rating          | DECIMAL(3,2)  |     | Product rating        |

| ReviewCount     | INT           |     | Number of reviews     |

| StockQuantity   | INT           |     | Available inventory   |

| IsActive        | BIT           |     | Product availability  |

| CreatedDate     | DATE          |     | Product creation date |

Relationships:

Categories 1 → N Products

Brands 1 → N Products

Search & Product Discovery

Records each search query performed by a user.

| Column          | Data Type    | Key | Description                    |

| ————— | ———— | — | —————————— |

| SearchID        | BIGINT       | PK  | Unique search                  |

| SessionID       | BIGINT       | FK  | → Sessions                     |

| SearchQuery     | VARCHAR(255) |     | Query entered                  |

| SearchTimestamp | DATETIME2    |     | Search time                    |

| ResultsCount    | INT          |     | Number of results              |

| SearchType      | VARCHAR(30)  |     | Keyword / Category / Suggested |

| FiltersApplied  | BIT          |     | Whether filters were used      |

| SortOption      | VARCHAR(30)  |     | Relevance / Price / Rating     |

Relationship:

Sessions 1 → N Searches

ResultsCount = 0 will later be used directly to calculate the Zero-Result Rate.

7. SearchImpressions

Identifies which products were displayed to the user in the search results.

| Column              | Data Type | Key | Description       |

| ——————- | ——— | — | —————– |

| ImpressionID        | BIGINT    | PK  | Unique impression |

| SearchID            | BIGINT    | FK  | → Searches        |

| ProductID           | INT       | FK  | → Products        |

| ResultPosition      | INT       |     | Search ranking    |

| ImpressionTimestamp | DATETIME2 |     | Display time      |

| IsSponsored         | BIT       |     | Sponsored result  |

A single search query can display, for example, 20 products:

Search 1001 → Product A position 1

Search 1001 → Product B position 2

Search 1001 → Product C position 3

This table will be essential for analyzing the impact of Ranking Position.

8. SearchClicks

Records each click on a search result.

| Column         | Data Type | Key | Description      |

| ————– | ——— | — | —————- |

| SearchClickID  | BIGINT    | PK  | Click identifier |

| SearchID       | BIGINT    | FK  | → Searches       |

| ProductID      | INT       | FK  | → Products       |

| ClickTimestamp | DATETIME2 |     | Click time       |

| ClickPosition  | INT       |     | Position clicked |

Using these three tables:

Searches → SearchImpressions → SearchClicks

we can analyze Search CTR, Ranking Performance, and Product Discovery.

Behavioral Events

9. ProductViews

| Column              | Data Type   | Key       | Description                               |

| ——————- | ———– | ——— | —————————————– |

| ProductViewID       | BIGINT      | PK        | View identifier                           |

| SessionID           | BIGINT      | FK        | → Sessions                                |

| ProductID           | INT         | FK        | → Products                                |

| SearchID            | BIGINT      | FK / NULL | Source search                             |

| ViewTimestamp       | DATETIME2   |           | View time                                 |

| ViewDurationSeconds | INT         |           | Time on product page                      |

| SourcePage          | VARCHAR(50) |           | Search / Home / Category / Recommendation |

SearchID can be NULL because not every Product View necessarily originates from a search.

10. CartEvents

| Column         | Data Type     | Key | Description                   |

| ————– | ————- | — | —————————– |

| CartEventID    | BIGINT        | PK  | Event identifier              |

| SessionID      | BIGINT        | FK  | → Sessions                    |

| ProductID      | INT           | FK  | → Products                    |

| EventType      | VARCHAR(20)   |     | Add / Remove / QuantityChange |

| Quantity       | INT           |     | Quantity                      |

| UnitPrice      | DECIMAL(10,2) |     | Price at event                |

| EventTimestamp | DATETIME2     |     | Event time                    |

This design also enables analysis of the Add-to-Cart → Remove-from-Cart behavior.

11. CheckoutEvents

| Column          | Data Type   | Key | Description                              |

| ————— | ———– | — | —————————————- |

| CheckoutEventID | BIGINT      | PK  | Checkout event                           |

| SessionID       | BIGINT      | FK  | → Sessions                               |

| EventType       | VARCHAR(30) |     | Started / Shipping / Payment / Completed |

| EventTimestamp  | DATETIME2   |     | Event time                               |

| PaymentMethod   | VARCHAR(30) |     | Payment method                           |

| ShippingMethod  | VARCHAR(30) |     | Shipping option                          |

Transaction Layer

12. Orders

| Column         | Data Type     | Key | Description                      |

| ————– | ————- | — | ——————————– |

| OrderID        | BIGINT        | PK  | Order identifier                 |

| UserID         | INT           | FK  | → Users                          |

| SessionID      | BIGINT        | FK  | → Sessions                       |

| OrderDate      | DATETIME2     |     | Purchase time                    |

| OrderStatus    | VARCHAR(30)   |     | Completed / Cancelled / Refunded |

| Subtotal       | DECIMAL(12,2) |     | Before adjustments               |

| DiscountAmount | DECIMAL(10,2) |     | Discount                         |

| ShippingAmount | DECIMAL(10,2) |     | Shipping                         |

| TaxAmount      | DECIMAL(10,2) |     | Tax                              |

| TotalAmount    | DECIMAL(12,2) |     | Final amount                     |

13. OrderItems

| Column         | Data Type     | Key | Description        |

| ————– | ————- | — | —————— |

| OrderItemID    | BIGINT        | PK  | Item identifier    |

| OrderID        | BIGINT        | FK  | → Orders           |

| ProductID      | INT           | FK  | → Products         |

| Quantity       | INT           |     | Purchased quantity |

| UnitPrice      | DECIMAL(10,2) |     | Purchase price     |

| DiscountAmount | DECIMAL(10,2) |     | Item discount      |

| LineTotal      | DECIMAL(12,2) |     | Item revenue       |

Relationship:

Orders 1 → N OrderItems

This structure enables revenue analysis at the Product, Category, Brand, User, and Session levels.

Experimentation Layer

14. Experiments

| Column         | Data Type    | Key | Description                   |

| ————– | ———— | — | —————————– |

| ExperimentID   | INT          | PK  | Experiment identifier         |

| ExperimentName | VARCHAR(150) |     | Experiment name               |

| Description    | VARCHAR(500) |     | Business hypothesis           |

| StartDate      | DATE         |     | Start                         |

| EndDate        | DATE         |     | End                           |

| PrimaryMetric  | VARCHAR(100) |     | Main KPI                      |

| Status         | VARCHAR(20)  |     | Planned / Running / Completed |

For example:

Experiment: Personalized Search Ranking

Primary Metric: Search-to-Purchase Conversion Rate

15. ExperimentVariants

| Column             | Data Type    | Key | Description            |

| —————— | ———— | — | ———————- |

| VariantID          | INT          | PK  | Variant identifier     |

| ExperimentID       | INT          | FK  | → Experiments          |

| VariantName        | VARCHAR(50)  |     | Control / Treatment    |

| VariantDescription | VARCHAR(300) |     | Experience description |

| AllocationPercent  | DECIMAL(5,2) |     | Traffic allocation     |

Relationship:

Experiments 1 → N ExperimentVariants

16. ExperimentAssignments

This table identifies which experiment variant each User/Session has been assigned to.

| Column              | Data Type | Key       | Description           |

| ——————- | ——— | ——— | ——————— |

| AssignmentID        | BIGINT    | PK        | Assignment identifier |

| ExperimentID        | INT       | FK        | → Experiments         |

| VariantID           | INT       | FK        | → ExperimentVariants  |

| UserID              | INT       | FK / NULL | → Users               |

| SessionID           | BIGINT    | FK / NULL | → Sessions            |

| AssignmentTimestamp | DATETIME2 |           | Assignment time       |

Using this table, we can link Control vs. Treatment assignments to all subsequent user events and behaviors.

Final Schema Architecture

The core Customer Journey will be structured as follows:

Users → Sessions → Searches → SearchImpressions / SearchClicks → ProductViews → CartEvents → CheckoutEvents → Orders → OrderItems

Alongside the main customer journey, the Product Dimension Structure will be:

Categories → Products ← Brands

The Experimentation Layer will be structured as:

Experiments → ExperimentVariants → ExperimentAssignments → Users / Sessions

ShopSense – Relationships, Primary Keys & Foreign Keys

In the ShopSense database design, there are three main types of relationships:

  • 1:N (One-to-Many): the most common relationship type in the project
  • Optional Relationship: used when a Foreign Key (FK) can be NULL
  • Self-Relationship: used to create the hierarchical structure of Categories

1. Primary Keys

Each table will have a unique Primary Key (PK).

| Table                 | Primary Key       | Data Type |

| ——————— | —————– | ——— |

| Users                 | `UserID`          | INT       |

| Sessions              | `SessionID`       | BIGINT    |

| Categories            | `CategoryID`      | INT       |

| Brands                | `BrandID`         | INT       |

| Products              | `ProductID`       | INT       |

| Searches              | `SearchID`        | BIGINT    |

| SearchImpressions     | `ImpressionID`    | BIGINT    |

| SearchClicks          | `SearchClickID`   | BIGINT    |

| ProductViews          | `ProductViewID`   | BIGINT    |

| CartEvents            | `CartEventID`     | BIGINT    |

| CheckoutEvents        | `CheckoutEventID` | BIGINT    |

| Orders                | `OrderID`         | BIGINT    |

| OrderItems            | `OrderItemID`     | BIGINT    |

| Experiments           | `ExperimentID`    | INT       |

| ExperimentVariants    | `VariantID`       | INT       |

| ExperimentAssignments | `AssignmentID`    | BIGINT    |

The use of BIGINT for events, sessions, and transactions is intentional, as in a real-world system, the number of these records can grow significantly larger than dimension entities such as Brands and Categories.

2. Core Customer Relationships

Users → Sessions

Users

UserID PK

   │

   │ 1

   │

   └──────── N

          Sessions

          UserID FK

Relationship:

Users.UserID → Sessions.UserID

Cardinality: 1:N

3. Product Relationships

Categories → Products

PK: Categories.CategoryID

FK: Products.CategoryID

Cardinality: 1:N

Categories

    │

    │ 1

    ▼

    N

Products

Each Category can contain multiple Products.

Brands → Products

PK: Brands.BrandID

FK: Products.BrandID

Cardinality: 1:N

Each Brand can have multiple Products, while each Product is associated with a single Brand in the current design.

4. Category Self-Relationship

In the Categories table, we have a special type of relationship:

PK: CategoryID

FK: ParentCategoryID

Categories

CategoryID PK

     ▲

     │

ParentCategoryID FK

Cardinality: 1:N

For example:

Electronics

     │

     ├── Headphones

     ├── Laptops

     └── Smartphones

For a top-level category:

ParentCategoryID = NULL

For a subcategory such as Headphones:

ParentCategoryID = Electronics.CategoryID

This creates a Self-Referencing Relationship, allowing the Categories table to support a hierarchical category structure.

5. Sessions → Searches

PK: Sessions.SessionID

FK: Searches.SessionID

Cardinality: 1:N

A single Session may include multiple searches, for example:

Search 1: wireless headphones

Search 2: noise cancelling headphones

Search 3: bluetooth headphones

This relationship is important for calculating Searches per Session and analyzing Search Engagement.

6. Searches → SearchImpressions

PK: Searches.SearchID

FK: SearchImpressions.SearchID

Cardinality: 1:N

A single Search may generate, for example, 20 Product Impressions:

wireless headphones

SearchID 501

     │

     ├── Product 101 – Position 1

     ├── Product 237 – Position 2

     ├── Product 415 – Position 3

     └── …

7. Products → SearchImpressions

PK: Products.ProductID

FK: SearchImpressions.ProductID

Cardinality: 1:N

Therefore, SearchImpressions effectively connects Searches and Products:

Searches

    │

    │ 1

    ▼

    N

SearchImpressions

    N

    ▲

    │ 1

Products

This design allows us to determine:

Which Product was displayed for each Search and at which Ranking Position.

8. Searches → SearchClicks

PK: Searches.SearchID

FK: SearchClicks.SearchID

Cardinality: 1:N

Products.ProductID → SearchClicks.ProductID

Cardinality: 1:N

Therefore, we can compare Impressions with Clicks and later calculate:

Search CTR = Clicks / Impressions

9. Sessions → ProductViews

PK: Sessions.SessionID

FK: ProductViews.SessionID

Cardinality: 1:N

Products.ProductID → ProductViews.ProductID

Cardinality: 1:N

Each Product can be viewed thousands of times by different users.

10. Searches → ProductViews — Optional

PK: Searches.SearchID

FK: ProductViews.SearchID

ProductViews.SearchID = NULL

A user may access a Product Page directly from:

Homepage

Category Page

Recommendation

Promotion

Therefore, not every ProductView necessarily originates from a Search.

This is an optional relationship:

0..1 Search → ProductView

11. Sessions → CartEvents

PK: Sessions.SessionID

FK: CartEvents.SessionID

Cardinality: 1:N

Products.ProductID → CartEvents.ProductID

Cardinality: 1:N

For example:

Session 8001

Product 105 → Add

Product 220 → Add

Product 105 → Remove

Product 310 → Add

This event-based structure will later enable us to analyze Cart Abandonment and Remove-from-Cart Behavior.

12. Sessions → CheckoutEvents

PK: Sessions.SessionID

FK: CheckoutEvents.SessionID

Cardinality: 1:N

For example:

Started

   ↓

Shipping

   ↓

Payment

   ↓

Completed

If a user reaches the Payment stage but does not reach Completed, it indicates a Checkout Drop-off.

13. Users → Orders

PK: Users.UserID

FK: Orders.UserID

Cardinality: 1:N

A Customer can place multiple Orders over time.

14. Sessions → Orders

PK: Sessions.SessionID

FK: Orders.SessionID

Cardinality: 1:N

This relationship is particularly important for Product Analytics because it connects each Purchase to the Session in which the conversion occurred.

This allows us to answer analytical questions such as:

Do sessions with Search activity generate a higher Conversion Rate?

or:

What is the Revenue per Search Session?

15. Orders → OrderItems

PK: Orders.OrderID

FK: OrderItems.OrderID

Cardinality: 1:N

For example:

Order 70001

   │

   ├── Headphones × 1

   ├── Charger × 2

   └── Case × 1

16. Products → OrderItems

PK: Products.ProductID

FK: OrderItems.ProductID

Cardinality: 1:N

so:

Orders

   │

   │ 1

   ▼

   N

OrderItems

   N

   ▲

   │ 1

Products

This structure enables Revenue Analysis at the Product, Brand, and Category levels.

17. Experiments → ExperimentVariants

PK: Experiments.ExperimentID

FK: ExperimentVariants.ExperimentID

Cardinality: 1:N

For example:

Personalized Search Ranking

             │

        ┌────┴────┐

        │         │

     Control   Treatment

18. Experiments → ExperimentAssignments

PK: Experiments.ExperimentID

FK: ExperimentAssignments.ExperimentID

Cardinality: 1:N

Each Experiment can have multiple Assignments.

19. ExperimentVariants → ExperimentAssignments

PK: ExperimentVariants.VariantID

FK: ExperimentAssignments.VariantID

Cardinality: 1:N

For example:

Treatment

    │

    ├── User 120

    ├── User 341

    ├── User 527

    └── …

20. Users / Sessions → ExperimentAssignments

Here, we have an important design decision.

The ExperimentAssignments table includes:

UserID

SessionID

Both fields can be nullable, allowing an experiment to be conducted at either the User Level or the Session Level.

For example, for a User-Level Experiment:

UserID = 501

SessionID = NULL

For a Session-Level Experiment:

UserID = NULL

SessionID = 90051

This flexible design is particularly useful for practicing and analyzing different experimentation and A/B testing scenarios.

Final Relationship Map

Ultimately, the core database structure will be organized approximately as follows:

                         ┌──────────── Brands

                         │

                         ▼

Categories ───────────► Products

     ▲                   │ │ │ │

     │                   │ │ │ └──────────────┐

     └── ParentCategory  │ │ │                │

                         │ │ │                │

                         ▼ ▼ ▼                ▼

Users ──► Sessions ──► Searches ──► SearchImpressions

 │          │             │              ▲

 │          │             │              │

 │          │             └──► SearchClicks

 │          │

 │          ├────────────► ProductViews

 │          │

 │          ├────────────► CartEvents

 │          │

 │          ├────────────► CheckoutEvents

 │          │

 │          └────────────► Orders ──► OrderItems

 │                            ▲

 └────────────────────────────┘

Experiments

     │

     ├────► ExperimentVariants

     │              │

     │              ▼

     └────► ExperimentAssignments

                    ▲

                    │

              Users / Sessions

Summary of Key Constraints

In SQL Server, the main Foreign Key constraints will include the following:

Sessions.UserID

    → Users.UserID

Categories.ParentCategoryID

    → Categories.CategoryID

Products.CategoryID

    → Categories.CategoryID

Products.BrandID

    → Brands.BrandID

Searches.SessionID

    → Sessions.SessionID

SearchImpressions.SearchID

    → Searches.SearchID

SearchImpressions.ProductID

    → Products.ProductID

SearchClicks.SearchID

    → Searches.SearchID

SearchClicks.ProductID

    → Products.ProductID

ProductViews.SessionID

    → Sessions.SessionID

ProductViews.ProductID

    → Products.ProductID

ProductViews.SearchID

    → Searches.SearchID [NULL allowed]

CartEvents.SessionID

    → Sessions.SessionID

CartEvents.ProductID

    → Products.ProductID

CheckoutEvents.SessionID

    → Sessions.SessionID

Orders.UserID

    → Users.UserID

Orders.SessionID

    → Sessions.SessionID

OrderItems.OrderID

    → Orders.OrderID

OrderItems.ProductID

    → Products.ProductID

ExperimentVariants.ExperimentID

    → Experiments.ExperimentID

ExperimentAssignments.ExperimentID

    → Experiments.ExperimentID

ExperimentAssignments.VariantID

    → ExperimentVariants.VariantID

ExperimentAssignments.UserID

    → Users.UserID [NULL allowed]

ExperimentAssignments.SessionID

    → Sessions.SessionID [NULL allowed]

ER Diagram

The overall ERD structure will consist of three main sections:

Product Catalog:

Categories → Brands → Products

Customer Journey:

Users → Sessions → Searches → SearchImpressions / SearchClicks → ProductViews → CartEvents → CheckoutEvents → Orders → OrderItems

Experimentation:

Experiments → Experiment Variants → Experiment Assignments → Users / Sessions

Questions & Goals:

Business Goal

The primary goal of the ShopSense project is to understand how users move through the e-commerce customer journey, identify where friction or lost conversion occurs, and determine how improvements to product discovery and search experience can increase customer engagement, conversion, and revenue.

The project focuses on one central business question:

Why do some users demonstrate strong search and product engagement but fail to convert into customers?

To answer this question, the analysis connects customer, session, search, product interaction, cart, checkout, transaction, and experimentation data across the complete shopping journey.

1. Customer & Session Analysis

Questions:

How many users and sessions are generated over time?

What proportion of users are new versus returning customers?

Which acquisition sources generate the most users and sessions?

How does user behavior differ across Desktop, Mobile, and Tablet?

Which traffic sources generate the highest engagement?

How many sessions does an average user generate?

Which customer segments demonstrate the strongest engagement?

Do highly engaged users necessarily have higher conversion rates?

Which combinations of device, traffic source, and customer type are associated with unusually high or low conversion?

Goal:

Understand who the users are, how they reach ShopSense, and how their session behavior differs, creating the foundation for customer and behavioral segmentation.

2. Search & Product Discovery Analysis

Questions:

What percentage of sessions use search?

How many searches does an average search session contain?

Which search queries are most frequently used?

Which queries generate the highest and lowest engagement?

What percentage of searches return zero results?

Which queries have the highest Zero-Result Rate?

What is the overall Search Click-Through Rate (Search CTR)?

How does CTR change by search-result position?

Which products receive many impressions but relatively few clicks?

Do users who use filters behave differently from users who do not?

How do sorting options affect search engagement?

Which search queries generate strong engagement but weak purchasing outcomes?

Goal:

Evaluate the effectiveness of the ShopSense search and product discovery experience and identify situations where users show clear purchase intent but struggle to find or select suitable products.

3. Product Performance Analysis

Questions:

Which products receive the most impressions, clicks, and product views?

Which products generate the highest Add-to-Cart Rate?

Which products generate the highest conversion rate?

Which products receive high traffic but low conversion?

Which brands and categories generate the most revenue?

Does product rating appear to be associated with conversion?

How does product price or discount level relate to customer behavior?

Are some products frequently added to the cart but later removed?

Which categories have strong discovery performance but weak purchasing performance?

Goal:

Identify high-performing and underperforming products, brands, and categories and determine where product interest fails to translate into revenue.

4. Funnel & Drop-off Analysis

The core ShopSense funnel is:

Search → Product View → Add to Cart → Checkout → Purchase

Questions:

How many users or sessions reach each stage of the funnel?

What is the conversion rate between each stage?

At which stage does the largest drop-off occur?

How does funnel performance differ by device?

How does it differ between new and returning users?

How does funnel performance vary by acquisition source?

Which product categories experience the highest funnel abandonment?

How many users add products to their cart but never start checkout?

How many users start checkout but fail to complete a purchase?

At which checkout stage does the greatest abandonment occur?

Goal:

Identify the critical friction points in the customer journey and determine where ShopSense loses the greatest number of potential customers.

5. Conversion Analysis

Questions:

What is the overall purchase conversion rate?

What is the conversion rate for search sessions versus non-search sessions?

Do users who perform multiple searches convert differently from users who perform only one search?

Does higher Search CTR lead to higher purchase conversion?

Are there users with high search engagement but unexpectedly low conversion?

Which customer or session segments have the highest conversion loss?

Which devices, acquisition sources, categories, or search behaviors are associated with lower conversion?

Goal:

Determine which behaviors are most strongly associated with successful conversion and identify the segments responsible for significant lost purchase opportunities.

6. Revenue Analysis

Questions:

What is total revenue?

What is the Average Order Value (AOV)?

What is Revenue per User?

What is Revenue per Session?

What is Revenue per Search Session?

Which products, brands, and categories contribute the most revenue?

Which customer segments generate the highest revenue?

Which acquisition sources generate the strongest commercial outcomes?

Do high-engagement sessions generate proportionally higher revenue?

Which segments generate strong engagement but relatively weak revenue?

Goal:

Connect behavioral analytics with commercial outcomes so that recommendations are based not only on engagement but also on measurable business impact.

7. Customer & Behavioral Segmentation

Questions:

Can users or sessions be divided into meaningful behavioral groups such as:

High Engagement / High Conversion

High Engagement / Low Conversion

Low Engagement / High Conversion

Low Engagement / Low Conversion

Additional segmentation will examine:

Search Users vs. Non-Search Users

New vs. Returning Users

Device Type

Acquisition Source

Product Category

Purchase Behavior

Goal:

Identify customer segments with different behaviors and isolate the strategically important High-Engagement / Low-Conversion segment, where users demonstrate strong intent but encounter friction before purchase.

8. A/B Testing & Experimentation

Questions:

Does the Treatment experience improve Search CTR compared with Control?

Does it increase Add-to-Cart Rate?

Does it improve Search-to-Purchase Conversion Rate?

Does it increase Revenue per Session?

What is the absolute and relative uplift between Control and Treatment?

Are observed differences statistically significant?

What are the confidence intervals around the estimated effect?

Does the Treatment improve the primary metric without negatively affecting important guardrail metrics?

Does the experiment affect customer segments differently?

Are improvements in engagement accompanied by improvements in actual purchases and revenue?

Goal:

Determine whether proposed product-discovery improvements produce measurable and statistically supported changes in customer behavior and business outcomes.

9. Final Business Questions

At the end of the project, the analysis should provide evidence to answer five broader questions:

1. Where is ShopSense losing potential customers?

2. Which users demonstrate purchase intent but fail to convert?

3. What search, product, device, or customer characteristics are associated with that friction?

4. What product or customer-experience improvements could address the identified problems?

5. Do controlled experiments provide evidence that the proposed changes improve conversion and business outcomes?

Final Project Goal:

The final goal of ShopSense is not simply to create reports and dashboards, but to demonstrate an end-to-end product analytics process:

Business Question → Data Model → SQL Analysis → Behavioral Investigation → Funnel Analysis → Segmentation → Hypothesis → Experiment → Statistical Evaluation → Business Recommendation

The project should ultimately demonstrate how customer behavior data can be transformed into actionable product insights and evidence-based business decisions.

Steps:

The table creation order is important because of the Foreign Key dependencies:

Users, Categories, Brands, Experiments

Sessions, Products, ExperimentVariants

Searches, ProductViews, CartEvents, CheckoutEvents, Orders, ExperimentAssignments

SearchImpressions, SearchClicks, OrderItems

1. Create the Database

First, we create the database itself:

CREATE DATABASE ShopSense;

GO

USE ShopSense;

GO

Users Table:

CREATE TABLE Users

(

    UserID INT IDENTITY(1,1) PRIMARY KEY,

    RegistrationDate DATE NOT NULL,

    CustomerType VARCHAR(20) NOT NULL,

    AgeGroup VARCHAR(20) NULL,

    Country VARCHAR(50) NULL,

    Region VARCHAR(50) NULL,

    AcquisitionSource VARCHAR(50) NULL,

    IsRegistered BIT NOT NULL

        CONSTRAINT DF_Users_IsRegistered DEFAULT 1,

    IsActive BIT NOT NULL

        CONSTRAINT DF_Users_IsActive DEFAULT 1,

    CONSTRAINT CK_Users_CustomerType

        CHECK (CustomerType IN (‘New’, ‘Returning’))

);

GO

SELECT *

FROM Users;

EXEC sp_help ‘Users’;

USE ShopSense;

GO

Categories Table:

CREATE TABLE Categories

(

    CategoryID INT IDENTITY(1,1) NOT NULL,

    CategoryName VARCHAR(100) NOT NULL,

    ParentCategoryID INT NULL,

    IsActive BIT NOT NULL

        CONSTRAINT DF_Categories_IsActive DEFAULT 1,

    CONSTRAINT PK_Categories

        PRIMARY KEY (CategoryID),

    CONSTRAINT UQ_Categories_CategoryName

        UNIQUE (CategoryName),

    CONSTRAINT FK_Categories_ParentCategory

        FOREIGN KEY (ParentCategoryID)

        REFERENCES Categories(CategoryID)

);

GO

Brands Table:

CREATE TABLE Brands

(

    BrandID INT IDENTITY(1,1) NOT NULL,

    BrandName VARCHAR(100) NOT NULL,

    CountryOfOrigin VARCHAR(50) NULL,

    IsActive BIT NOT NULL

        CONSTRAINT DF_Brands_IsActive DEFAULT 1,

    CONSTRAINT PK_Brands

        PRIMARY KEY (BrandID),

    CONSTRAINT UQ_Brands_BrandName

        UNIQUE (BrandName)

);

GO

Experiments Table:

CREATE TABLE Experiments

(

    ExperimentID INT IDENTITY(1,1) NOT NULL,

    ExperimentName VARCHAR(150) NOT NULL,

    Description VARCHAR(500) NULL,

    StartDate DATE NOT NULL,

    EndDate DATE NULL,

    PrimaryMetric VARCHAR(100) NOT NULL,

    Status VARCHAR(20) NOT NULL,

    CONSTRAINT PK_Experiments

        PRIMARY KEY (ExperimentID),

    CONSTRAINT UQ_Experiments_ExperimentName

        UNIQUE (ExperimentName),

    CONSTRAINT CK_Experiments_Status

        CHECK (Status IN (‘Planned’, ‘Running’, ‘Completed’, ‘Cancelled’)),

    CONSTRAINT CK_Experiments_DateRange

        CHECK (EndDate IS NULL OR EndDate >= StartDate)

);

GO

Sessions Table

This table records each user visit to ShopSense and is directly connected to the Users table.

USE ShopSense;

GO

USE ShopSense;

GO

CREATE TABLE Sessions

(

    SessionID BIGINT IDENTITY(1,1) NOT NULL,

    UserID INT NOT NULL,

    SessionStart DATETIME2 NOT NULL,

    SessionEnd DATETIME2 NULL,

    DeviceType VARCHAR(20) NOT NULL,

    TrafficSource VARCHAR(50) NOT NULL,

    Campaign VARCHAR(100) NULL,

    LandingPage VARCHAR(100) NULL,

    Browser VARCHAR(30) NULL,

    SessionDurationSeconds INT NULL,

    CONSTRAINT PK_Sessions

        PRIMARY KEY (SessionID),

    CONSTRAINT FK_Sessions_Users

        FOREIGN KEY (UserID)

        REFERENCES Users(UserID),

    CONSTRAINT CK_Sessions_DeviceType

        CHECK (DeviceType IN (‘Desktop’, ‘Mobile’, ‘Tablet’)),

    CONSTRAINT CK_Sessions_TrafficSource

        CHECK (TrafficSource IN

        (‘Organic’, ‘Paid’, ‘Direct’, ‘Social’, ‘Email’)),

    CONSTRAINT CK_Sessions_Duration

        CHECK (SessionDurationSeconds IS NULL

               OR SessionDurationSeconds >= 0),

    CONSTRAINT CK_Sessions_TimeRange

        CHECK (SessionEnd IS NULL

               OR SessionEnd >= SessionStart)

);

GO

The relationship we created is:

Users

  1

  │

  │

  N

Sessions

Sessions.UserID

        ↓

Users.UserID

Two constraints are also used to prevent invalid data. For example, a Session cannot end before it starts, and its Duration cannot be negative.

Products Table

This table is connected to both parent tables: Categories and Brands.

CREATE TABLE Products

(

    ProductID INT IDENTITY(1,1) NOT NULL,

    ProductName VARCHAR(150) NOT NULL,

    CategoryID INT NOT NULL,

    BrandID INT NOT NULL,

    ListPrice DECIMAL(10,2) NOT NULL,

    DiscountPercent DECIMAL(5,2) NOT NULL

        CONSTRAINT DF_Products_DiscountPercent DEFAULT 0,

    Rating DECIMAL(3,2) NULL,

    ReviewCount INT NOT NULL

        CONSTRAINT DF_Products_ReviewCount DEFAULT 0,

    StockQuantity INT NOT NULL

        CONSTRAINT DF_Products_StockQuantity DEFAULT 0,

    IsActive BIT NOT NULL

        CONSTRAINT DF_Products_IsActive DEFAULT 1,

    CreatedDate DATE NOT NULL,

    CONSTRAINT PK_Products

        PRIMARY KEY (ProductID),

    CONSTRAINT FK_Products_Categories

        FOREIGN KEY (CategoryID)

        REFERENCES Categories(CategoryID),

    CONSTRAINT FK_Products_Brands

        FOREIGN KEY (BrandID)

        REFERENCES Brands(BrandID),

    CONSTRAINT CK_Products_ListPrice

        CHECK (ListPrice >= 0),

    CONSTRAINT CK_Products_DiscountPercent

        CHECK (DiscountPercent BETWEEN 0 AND 100),

    CONSTRAINT CK_Products_Rating

        CHECK (Rating IS NULL OR Rating BETWEEN 0 AND 5),

    CONSTRAINT CK_Products_ReviewCount

        CHECK (ReviewCount >= 0),

    CONSTRAINT CK_Products_StockQuantity

        CHECK (StockQuantity >= 0)

);

GO

Categories (1) ─────< Products

Brands     (1) ─────< Products

ExperimentVariants Table:

This table stores the different variants of each A/B test.

CREATE TABLE ExperimentVariants

(

    VariantID INT IDENTITY(1,1) NOT NULL,

    ExperimentID INT NOT NULL,

    VariantName VARCHAR(50) NOT NULL,

    VariantDescription VARCHAR(300) NULL,

    AllocationPercent DECIMAL(5,2) NOT NULL,

    CONSTRAINT PK_ExperimentVariants

        PRIMARY KEY (VariantID),

    CONSTRAINT FK_ExperimentVariants_Experiments

        FOREIGN KEY (ExperimentID)

        REFERENCES Experiments(ExperimentID),

    CONSTRAINT CK_ExperimentVariants_AllocationPercent

        CHECK (AllocationPercent > 0

               AND AllocationPercent <= 100),

    CONSTRAINT UQ_ExperimentVariants_Experiment_Variant

        UNIQUE (ExperimentID, VariantName)

);

GO

Experiments

     1

     │

     │

     N

ExperimentVariants

Verify Table Creation

SELECT

    TABLE_NAME

FROM INFORMATION_SCHEMA.TABLES

WHERE TABLE_TYPE = ‘BASE TABLE’

ORDER BY TABLE_NAME;

GO

Verify Foreign Key

SELECT

    fk.name AS ForeignKey,

    OBJECT_NAME(fk.parent_object_id) AS ChildTable,

    COL_NAME(fkc.parent_object_id,

             fkc.parent_column_id) AS ChildColumn,

    OBJECT_NAME(fk.referenced_object_id) AS ParentTable,

    COL_NAME(fkc.referenced_object_id,

             fkc.referenced_column_id) AS ParentColumn

FROM sys.foreign_keys fk

INNER JOIN sys.foreign_key_columns fkc

    ON fk.object_id = fkc.constraint_object_id

ORDER BY ChildTable, ForeignKey;

Searches Table

This table stores each search query performed by a user during a Session.

USE ShopSense;

GO

CREATE TABLE Searches

(

    SearchID BIGINT IDENTITY(1,1) NOT NULL,

    SessionID BIGINT NOT NULL,

    SearchQuery VARCHAR(255) NOT NULL,

    SearchTimestamp DATETIME2 NOT NULL,

    ResultsCount INT NOT NULL,

    SearchType VARCHAR(30) NOT NULL,

    FiltersApplied BIT NOT NULL

        CONSTRAINT DF_Searches_FiltersApplied DEFAULT 0,

    SortOption VARCHAR(30) NULL,

    CONSTRAINT PK_Searches

        PRIMARY KEY (SearchID),

    CONSTRAINT FK_Searches_Sessions

        FOREIGN KEY (SessionID)

        REFERENCES Sessions(SessionID),

    CONSTRAINT CK_Searches_ResultsCount

        CHECK (ResultsCount >= 0),

    CONSTRAINT CK_Searches_SearchType

        CHECK (SearchType IN

        (‘Keyword’, ‘Category’, ‘Suggested’)),

    CONSTRAINT CK_Searches_SortOption

        CHECK (

            SortOption IS NULL

            OR SortOption IN

            (‘Relevance’, ‘PriceLowHigh’,

             ‘PriceHighLow’, ‘Rating’)

        )

);

GO

Relationship:

Sessions (1) ─────< Searches (N)

ProductViews Table

This table records each Product Page View.

CREATE TABLE ProductViews

(

    ProductViewID BIGINT IDENTITY(1,1) NOT NULL,

    SessionID BIGINT NOT NULL,

    ProductID INT NOT NULL,

    SearchID BIGINT NULL,

    ViewTimestamp DATETIME2 NOT NULL,

    ViewDurationSeconds INT NULL,

    SourcePage VARCHAR(50) NOT NULL,

    CONSTRAINT PK_ProductViews

        PRIMARY KEY (ProductViewID),

    CONSTRAINT FK_ProductViews_Sessions

        FOREIGN KEY (SessionID)

        REFERENCES Sessions(SessionID),

    CONSTRAINT FK_ProductViews_Products

        FOREIGN KEY (ProductID)

        REFERENCES Products(ProductID),

    CONSTRAINT FK_ProductViews_Searches

        FOREIGN KEY (SearchID)

        REFERENCES Searches(SearchID),

    CONSTRAINT CK_ProductViews_Duration

        CHECK (

            ViewDurationSeconds IS NULL

            OR ViewDurationSeconds >= 0

        ),

    CONSTRAINT CK_ProductViews_SourcePage

        CHECK (

            SourcePage IN

            (‘Search’, ‘Home’, ‘Category’,

             ‘Recommendation’, ‘Promotion’)

        )

);

GO

Relationship:

Sessions ─────< ProductViews

Products ─────< ProductViews

Searches ─────< ProductViews

CartEvents Table

In ShopSense, the shopping cart is designed using an Event-Based approach.

CREATE TABLE CartEvents

(

    CartEventID BIGINT IDENTITY(1,1) NOT NULL,

    SessionID BIGINT NOT NULL,

    ProductID INT NOT NULL,

    EventType VARCHAR(20) NOT NULL,

    Quantity INT NOT NULL,

    UnitPrice DECIMAL(10,2) NOT NULL,

    EventTimestamp DATETIME2 NOT NULL,

    CONSTRAINT PK_CartEvents

        PRIMARY KEY (CartEventID),

    CONSTRAINT FK_CartEvents_Sessions

        FOREIGN KEY (SessionID)

        REFERENCES Sessions(SessionID),

    CONSTRAINT FK_CartEvents_Products

        FOREIGN KEY (ProductID)

        REFERENCES Products(ProductID),

    CONSTRAINT CK_CartEvents_EventType

        CHECK (

            EventType IN

            (‘Add’, ‘Remove’, ‘QuantityChange’)

        ),

    CONSTRAINT CK_CartEvents_Quantity

        CHECK (Quantity > 0),

    CONSTRAINT CK_CartEvents_UnitPrice

        CHECK (UnitPrice >= 0)

);

GO

CheckoutEvents Table

CREATE TABLE CheckoutEvents

(

    CheckoutEventID BIGINT IDENTITY(1,1) NOT NULL,

    SessionID BIGINT NOT NULL,

    EventType VARCHAR(30) NOT NULL,

    EventTimestamp DATETIME2 NOT NULL,

    PaymentMethod VARCHAR(30) NULL,

    ShippingMethod VARCHAR(30) NULL,

    CONSTRAINT PK_CheckoutEvents

        PRIMARY KEY (CheckoutEventID),

    CONSTRAINT FK_CheckoutEvents_Sessions

        FOREIGN KEY (SessionID)

        REFERENCES Sessions(SessionID),

    CONSTRAINT CK_CheckoutEvents_EventType

        CHECK (

            EventType IN

            (‘Started’, ‘Shipping’,

             ‘Payment’, ‘Completed’)

        ),

    CONSTRAINT CK_CheckoutEvents_PaymentMethod

        CHECK (

            PaymentMethod IS NULL

            OR PaymentMethod IN

            (‘CreditCard’, ‘DebitCard’,

             ‘PayPal’, ‘DigitalWallet’)

        ),

    CONSTRAINT CK_CheckoutEvents_ShippingMethod

        CHECK (

            ShippingMethod IS NULL

            OR ShippingMethod IN

            (‘Standard’, ‘Express’, ‘Pickup’)

        )

);

GO

Therefore, we can also analyze the internal Checkout Funnel:

Started

   ↓

Shipping

   ↓

Payment

   ↓

Completed

For example, if a Session reaches the Payment stage but does not reach Completed, it indicates a Checkout Drop-off.

Orders Table

CREATE TABLE Orders

(

    OrderID BIGINT IDENTITY(1,1) NOT NULL,

    UserID INT NOT NULL,

    SessionID BIGINT NOT NULL,

    OrderDate DATETIME2 NOT NULL,

    OrderStatus VARCHAR(30) NOT NULL,

    Subtotal DECIMAL(12,2) NOT NULL,

    DiscountAmount DECIMAL(10,2) NOT NULL

        CONSTRAINT DF_Orders_DiscountAmount DEFAULT 0,

    ShippingAmount DECIMAL(10,2) NOT NULL

        CONSTRAINT DF_Orders_ShippingAmount DEFAULT 0,

    TaxAmount DECIMAL(10,2) NOT NULL

        CONSTRAINT DF_Orders_TaxAmount DEFAULT 0,

    TotalAmount DECIMAL(12,2) NOT NULL,

    CONSTRAINT PK_Orders

        PRIMARY KEY (OrderID),

    CONSTRAINT FK_Orders_Users

        FOREIGN KEY (UserID)

        REFERENCES Users(UserID),

    CONSTRAINT FK_Orders_Sessions

        FOREIGN KEY (SessionID)

        REFERENCES Sessions(SessionID),

    CONSTRAINT CK_Orders_Status

        CHECK (

            OrderStatus IN

            (‘Completed’, ‘Cancelled’, ‘Refunded’)

        ),

    CONSTRAINT CK_Orders_Subtotal

        CHECK (Subtotal >= 0),

    CONSTRAINT CK_Orders_DiscountAmount

        CHECK (DiscountAmount >= 0),

    CONSTRAINT CK_Orders_ShippingAmount

        CHECK (ShippingAmount >= 0),

    CONSTRAINT CK_Orders_TaxAmount

        CHECK (TaxAmount >= 0),

    CONSTRAINT CK_Orders_TotalAmount

        CHECK (TotalAmount >= 0)

);

GO

This table has two important relationships:

Users    (1) ─────< Orders

Sessions (1) ─────< Orders

This structure allows us to analyze Revenue and Conversion at both the Customer and Session levels.

ExperimentAssignments Table

This is one of the most important tables in ShopSense, as it connects user behavior to A/B Tests.

CREATE TABLE ExperimentAssignments

(

    AssignmentID BIGINT IDENTITY(1,1) NOT NULL,

    ExperimentID INT NOT NULL,

    VariantID INT NOT NULL,

    UserID INT NULL,

    SessionID BIGINT NULL,

    AssignmentTimestamp DATETIME2 NOT NULL,

    CONSTRAINT PK_ExperimentAssignments

        PRIMARY KEY (AssignmentID),

    CONSTRAINT FK_ExperimentAssignments_Experiments

        FOREIGN KEY (ExperimentID)

        REFERENCES Experiments(ExperimentID),

    CONSTRAINT FK_ExperimentAssignments_Variants

        FOREIGN KEY (VariantID)

        REFERENCES ExperimentVariants(VariantID),

    CONSTRAINT FK_ExperimentAssignments_Users

        FOREIGN KEY (UserID)

        REFERENCES Users(UserID),

    CONSTRAINT FK_ExperimentAssignments_Sessions

        FOREIGN KEY (SessionID)

        REFERENCES Sessions(SessionID),

    CONSTRAINT CK_ExperimentAssignments_Target

        CHECK (

            (UserID IS NOT NULL AND SessionID IS NULL)

            OR

            (UserID IS NULL AND SessionID IS NOT NULL)

        )

);

GO

Verify Table Creation

USE ShopSense;

GO

SELECT

    TABLE_NAME

FROM INFORMATION_SCHEMA.TABLES

WHERE TABLE_TYPE = ‘BASE TABLE’

ORDER BY TABLE_NAME;

GO

SearchImpressions Table

Each time a product is displayed to a user in the search results, we create a Product Impression.

CREATE TABLE SearchImpressions

(

    ImpressionID BIGINT IDENTITY(1,1) NOT NULL,

    SearchID BIGINT NOT NULL,

    ProductID INT NOT NULL,

    ResultPosition INT NOT NULL,

    ImpressionTimestamp DATETIME2 NOT NULL,

    CONSTRAINT PK_SearchImpressions

        PRIMARY KEY (ImpressionID),

    CONSTRAINT FK_SearchImpressions_Searches

        FOREIGN KEY (SearchID)

        REFERENCES Searches(SearchID),

    CONSTRAINT FK_SearchImpressions_Products

        FOREIGN KEY (ProductID)

        REFERENCES Products(ProductID),

    CONSTRAINT CK_SearchImpressions_ResultPosition

        CHECK (ResultPosition > 0)

);

GO

Realationships:

Searches  (1) ─────< SearchImpressions >───── (1) Products

SearchClicks Table

Now, we record each click on a Search Impression.

CREATE TABLE SearchClicks

(

    ClickID BIGINT IDENTITY(1,1) NOT NULL,

    ImpressionID BIGINT NOT NULL,

    ClickTimestamp DATETIME2 NOT NULL,

    CONSTRAINT PK_SearchClicks

        PRIMARY KEY (ClickID),

    CONSTRAINT FK_SearchClicks_Impressions

        FOREIGN KEY (ImpressionID)

        REFERENCES SearchImpressions(ImpressionID)

);

GO

Realationships:

SearchImpressions (1) ─────< SearchClicks (N)

In the current design, each Impression can have at most one Click. Therefore, it is better to enforce this rule at the database level as well.

To achieve this, we will add a Unique Constraint:

ALTER TABLE SearchClicks

ADD CONSTRAINT UQ_SearchClicks_Impression

UNIQUE (ImpressionID);

GO

OrderItems Table

Now we come to the very important Revenue section.

An Order can contain multiple Products, so Products and Orders have a conceptual Many-to-Many relationship, which is resolved through OrderItems:

Realationships:

Orders  (1) ─────< OrderItems >───── (1) Products

CREATE TABLE OrderItems

(

    OrderItemID BIGINT IDENTITY(1,1) NOT NULL,

    OrderID BIGINT NOT NULL,

    ProductID INT NOT NULL,

    Quantity INT NOT NULL,

    UnitPrice DECIMAL(10,2) NOT NULL,

    DiscountAmount DECIMAL(10,2) NOT NULL

        CONSTRAINT DF_OrderItems_DiscountAmount DEFAULT 0,

    LineTotal AS

    (

        (Quantity * UnitPrice) – DiscountAmount

    ) PERSISTED,

    CONSTRAINT PK_OrderItems

        PRIMARY KEY (OrderItemID),

    CONSTRAINT FK_OrderItems_Orders

        FOREIGN KEY (OrderID)

        REFERENCES Orders(OrderID),

    CONSTRAINT FK_OrderItems_Products

        FOREIGN KEY (ProductID)

        REFERENCES Products(ProductID),

    CONSTRAINT CK_OrderItems_Quantity

        CHECK (Quantity > 0),

    CONSTRAINT CK_OrderItems_UnitPrice

        CHECK (UnitPrice >= 0),

    CONSTRAINT CK_OrderItems_DiscountAmount

        CHECK (

            DiscountAmount >= 0

            AND DiscountAmount <= (Quantity * UnitPrice)

        )

);

GO

Search Structure

Searches

   │

   │ 1:N

   ▼

SearchImpressions

   │

   │ 1:N

   ▼

SearchClicks

SearchImpressions

        │

        │ N:1

        ▼

     Products

Revenue Structure

Orders

   │

   │ 1:N

   ▼

OrderItems

   │

   │ N:1

   ▼

Products

Database Validation

USE ShopSense;

GO

SELECT

    TABLE_NAME

FROM INFORMATION_SCHEMA.TABLES

WHERE TABLE_TYPE = ‘BASE TABLE’

ORDER BY TABLE_NAME;

GO

USE ShopSense;

GO

SELECT DB_NAME() AS CurrentDatabase;

GO

SELECT COUNT(*) AS TotalTables

FROM INFORMATION_SCHEMA.TABLES

WHERE TABLE_TYPE = ‘BASE TABLE’;

GO

Primary Key

SELECT

    t.name AS TableName,

    kc.name AS PrimaryKeyName,

    c.name AS PrimaryKeyColumn

FROM sys.tables t

INNER JOIN sys.key_constraints kc

    ON t.object_id = kc.parent_object_id

INNER JOIN sys.index_columns ic

    ON kc.parent_object_id = ic.object_id

    AND kc.unique_index_id = ic.index_id

INNER JOIN sys.columns c

    ON ic.object_id = c.object_id

    AND ic.column_id = c.column_id

WHERE kc.type = ‘PK’

ORDER BY t.name;

Foreign Key

SELECT

    fk.name AS ForeignKeyName,

    OBJECT_NAME(fk.parent_object_id) AS ChildTable,

    COL_NAME(

        fkc.parent_object_id,

        fkc.parent_column_id

    ) AS ChildColumn,

    OBJECT_NAME(fk.referenced_object_id) AS ParentTable,

    COL_NAME(

        fkc.referenced_object_id,

        fkc.referenced_column_id

    ) AS ParentColumn

FROM sys.foreign_keys fk

INNER JOIN sys.foreign_key_columns fkc

    ON fk.object_id = fkc.constraint_object_id

ORDER BY ChildTable, ForeignKeyName;

CHECK Constraints

SELECT

    OBJECT_NAME(parent_object_id) AS TableName,

    name AS ConstraintName,

    definition AS ConstraintDefinition

FROM sys.check_constraints

ORDER BY TableName, ConstraintName;

Unique Constraints

SELECT

    OBJECT_NAME(i.object_id) AS TableName,

    i.name AS ConstraintName,

    COL_NAME(ic.object_id, ic.column_id) AS ColumnName

FROM sys.indexes i

INNER JOIN sys.index_columns ic

    ON i.object_id = ic.object_id

    AND i.index_id = ic.index_id

WHERE i.is_unique = 1

  AND i.is_primary_key = 0

ORDER BY TableName, ConstraintName;

Verify the Number of Columns in Each Table

SELECT

    t.name AS TableName,

    COUNT(c.column_id) AS NumberOfColumns

FROM sys.tables t

INNER JOIN sys.columns c

    ON t.object_id = c.object_id

GROUP BY t.name

ORDER BY t.name;

However, we omitted it when creating the final table.

From an analytical perspective, this field is valuable because Sponsored Results can influence CTR and Search Ranking Performance.

USE ShopSense;

GO

ALTER TABLE SearchImpressions

ADD IsSponsored BIT NOT NULL

    CONSTRAINT DF_SearchImpressions_IsSponsored DEFAULT 0;

GO

EXEC sp_help ‘SearchImpressions’;

GO

In the initial design, the SearchClicks table was intended to include the following fields:

SearchClickID

SearchID

ProductID

ClickTimestamp

ClickPosition

However, in the SQL implementation, we adopted a more normalized structure:

ClickID

ImpressionID

ClickTimestamp

Relationship:

SearchClicks

     │

ImpressionID

     ↓

SearchImpressions

     ├── SearchID

     ├── ProductID

     └── ResultPosition

Business Problems

Mobile Friction: Mobile users may show high levels of Search activity and Product Views, but experience greater drop-off at the Product View → Cart or Checkout → Purchase stages. This represents the type of High Engagement / Low Conversion behavior that directly supports ShopSense’s central analytical question.

Search Ranking Problem: Some products may receive a high number of Impressions, particularly in favorable ranking positions, but still generate a relatively low CTR. At the same time, higher-ranked search results are generally expected to achieve better CTR. This creates an opportunity to analyze Search Ranking Performance and identify products that underperform despite strong visibility.

Zero-Result Problem: Several Search Queries will intentionally generate a higher number of Zero-Result Searches. While the overall site-level Zero-Result Rate should remain realistic, certain queries will show unusually high rates, allowing us to identify problematic search terms.

Category/Product Friction: One or two Categories may demonstrate strong CTR and Product View activity but relatively low Add-to-Cart or Purchase rates. The analysis can then investigate whether factors such as Price, Rating, Discount, or other product characteristics are associated with this behavior.

Cart & Checkout Drop-off: Not every Add-to-Cart event will progress to Checkout, and not every Checkout will result in an Order. We will also create a more noticeable drop-off at one stage of the Checkout process so that the Funnel Analysis produces meaningful and interpretable results.

Search vs. Non-Search: Users who engage with Search will generally demonstrate higher Purchase Intent. However, one specific segment of Search Users will exhibit high engagement but relatively weak conversion. This directly connects to the central analytical question of the ShopSense project:

Why do some highly engaged search users fail to convert?

Data Dictionary

1. Users — Customer master data

| Column            | Data Type   | Key | Null | Description                          |

| —————– | ———– | — | —- | ———————————— |

| UserID            | INT         | PK  | No   | Unique customer identifier           |

| RegistrationDate  | DATE        | —   | No   | Customer registration date           |

| CustomerType      | VARCHAR(20) | —   | No   | New or Returning customer            |

| AgeGroup          | VARCHAR(20) | —   | Yes  | Customer age segment                 |

| Country           | VARCHAR(50) | —   | Yes  | Customer country                     |

| Region            | VARCHAR(50) | —   | Yes  | Geographic region                    |

| AcquisitionSource | VARCHAR(50) | —   | Yes  | Original customer acquisition source |

| IsRegistered      | BIT         | —   | No   | Indicates registered customer        |

| IsActive          | BIT         | —   | No   | Current customer status              |

2. Sessions — Website/app visits

| Column                 | Data Type    | Key | Null | Description                   |

| ———————- | ———— | — | —- | —————————– |

| SessionID              | BIGINT       | PK  | No   | Unique session identifier     |

| UserID                 | INT          | FK  | No   | User associated with session  |

| SessionStart           | DATETIME2    | —   | No   | Session start timestamp       |

| SessionEnd             | DATETIME2    | —   | Yes  | Session end timestamp         |

| DeviceType             | VARCHAR(20)  | —   | No   | Desktop, Mobile or Tablet     |

| TrafficSource          | VARCHAR(50)  | —   | No   | Source generating the session |

| Campaign               | VARCHAR(100) | —   | Yes  | Marketing campaign            |

| LandingPage            | VARCHAR(100) | —   | Yes  | First page of session         |

| Browser                | VARCHAR(30)  | —   | Yes  | Browser used                  |

| SessionDurationSeconds | INT          | —   | Yes  | Session duration              |

3. Categories — Product hierarchy

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| CategoryID | INT | PK | No | Unique category |

| CategoryName | VARCHAR(100) | Unique | No | Category name |

| ParentCategoryID | INT | FK | Yes | Parent category |

| IsActive | BIT | — | No | Category status |

ParentCategoryID → Categories.CategoryID creates the self-referencing hierarchy.

4. Brands

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| BrandID | INT | PK | No | Unique brand |

| BrandName | VARCHAR(100) | Unique | No | Brand name |

| CountryOfOrigin | VARCHAR(50) | — | Yes | Brand origin |

| IsActive | BIT | — | No | Brand status |

5. Products

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| ProductID | INT | PK | No | Unique product |

| ProductName | VARCHAR(150) | — | No | Product name |

| CategoryID | INT | FK | No | Product category |

| BrandID | INT | FK | No | Product brand |

| ListPrice | DECIMAL(10,2) | — | No | Base product price |

| DiscountPercent | DECIMAL(5,2) | — | No | Current discount percentage |

| Rating | DECIMAL(3,2) | — | Yes | Average product rating |

| ReviewCount | INT | — | No | Number of reviews |

| StockQuantity | INT | — | No | Available inventory |

| IsActive | BIT | — | No | Product availability |

| CreatedDate | DATE | — | No | Product creation/listing date |

6. Searches

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| SearchID | BIGINT | PK | No | Unique search |

| SessionID | BIGINT | FK | No | Session performing search |

| SearchQuery | VARCHAR(255) | — | No | Search term |

| SearchTimestamp | DATETIME2 | — | No | Search time |

| ResultsCount | INT | — | No | Number of returned results |

| SearchType | VARCHAR(30) | — | No | Keyword, Category or Suggested |

| FiltersApplied | BIT | — | No | Whether filters were used |

| SortOption | VARCHAR(30) | — | Yes | Selected sorting method |

7. SearchImpressions

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| ImpressionID | BIGINT | PK | No | Unique search-result impression |

| SearchID | BIGINT | FK | No | Associated search |

| ProductID | INT | FK | No | Displayed product |

| ResultPosition | INT | — | No | Product ranking position |

| ImpressionTimestamp | DATETIME2 | — | No | Impression timestamp |

8. SearchClicks

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| ClickID | BIGINT | PK | No | Unique search click |

| ImpressionID | BIGINT | FK / Unique | No | Impression clicked |

| ClickTimestamp | DATETIME2 | — | No | Click timestamp |

9. ProductViews

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| ProductViewID | BIGINT | PK | No | Unique product view |

| SessionID | BIGINT | FK | No | Associated session |

| ProductID | INT | FK | No | Viewed product |

| SearchID | BIGINT | FK | Yes | Search leading to view |

| ViewTimestamp | DATETIME2 | — | No | View timestamp |

| ViewDurationSeconds | INT | — | Yes | Time spent viewing |

| SourcePage | VARCHAR(50) | — | No | Search, Home, Category, Recommendation or

Promotion |Nullable SearchID allows us to distinguish search-driven and non-search product discovery.

10. CartEvents

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| CartEventID | BIGINT | PK | No | Unique cart event |

| SessionID | BIGINT | FK | No | Associated session |

| ProductID | INT | FK | No | Product affected |

| EventType | VARCHAR(20) | — | No | Add, Remove or QuantityChange |

| Quantity | INT | — | No | Product quantity |

| UnitPrice | DECIMAL(10,2) | — | No | Price at event time |

| EventTimestamp | DATETIME2 | — | No | Event timestamp |

11. CheckoutEvents

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| CheckoutEventID | BIGINT | PK | No | Unique checkout event |

| SessionID | BIGINT | FK | No | Associated session |

| EventType | VARCHAR(30) | — | No | Started, Shipping, Payment or Completed |

| EventTimestamp | DATETIME2 | — | No | Event timestamp |

| PaymentMethod | VARCHAR(30) | — | Yes | Payment method |

| ShippingMethod | VARCHAR(30) | — | Yes | Shipping option |

This allows analysis of:

Started → Shipping → Payment → Completed

12. Orders

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| OrderID | BIGINT | PK | No | Unique order |

| UserID | INT | FK | No | Purchasing customer |

| SessionID | BIGINT | FK | No | Converting session |

| OrderDate | DATETIME2 | — | No | Purchase timestamp |

| OrderStatus | VARCHAR(30) | — | No | Completed, Cancelled or Refunded |

| Subtotal | DECIMAL(12,2) | — | No | Pre-discount/order subtotal |

| DiscountAmount | DECIMAL(10,2) | — | No | Order discount |

| ShippingAmount | DECIMAL(10,2) | — | No | Shipping charge |

| TaxAmount | DECIMAL(10,2) | — | No | Tax |

| TotalAmount | DECIMAL(12,2) | — | No | Final order value |

13. OrderItems

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| OrderItemID | BIGINT | PK | No | Unique order line |

| OrderID | BIGINT | FK | No | Associated order |

| ProductID | INT | FK | No | Purchased product |

| Quantity | INT | — | No | Quantity purchased |

| UnitPrice | DECIMAL(10,2) | — | No | Purchase-time unit price |

| DiscountAmount | DECIMAL(10,2) | — | No | Line-level discount |

| LineTotal | Computed | — | No | `(Quantity × UnitPrice) − DiscountAmount` |

LineTotal is calculated by SQL Server rather than supplied by our CSV.

14. Experiments

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| ExperimentID | INT | PK | No | Unique experiment |

| ExperimentName | VARCHAR(150) | Unique | No | Experiment name |

| Description | VARCHAR(500) | — | Yes | Experiment description |

| StartDate | DATE | — | No | Experiment start |

| EndDate | DATE | — | Yes | Experiment end |

| PrimaryMetric | VARCHAR(100) | — | No | Primary success metric |

| Status | VARCHAR(20) | — | No | Planned, Running, Completed or Cancelled |

15. ExperimentVariants

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| VariantID | INT | PK | No | Unique variant |

| ExperimentID | INT | FK | No | Parent experiment |

| VariantName | VARCHAR(50) | — | No | Control/Treatment |

| VariantDescription | VARCHAR(300) | — | Yes | Variant description |

| AllocationPercent | DECIMAL(5,2) | — | No | Intended traffic allocation |

16. ExperimentAssignments

| Column | Data Type | Key | Null | Description |

|—|—|—|—|—|

| AssignmentID | BIGINT | PK | No | Unique assignment |

| ExperimentID | INT | FK | No | Experiment |

| VariantID | INT | FK | No | Assigned variant |

| UserID | INT | FK | Yes | User-level assignment |

| SessionID | BIGINT | FK | Yes | Session-level assignment |

| AssignmentTimestamp | DATETIME2 | — | No | Assignment time |

Our CHECK constraint requires exactly one of UserID or SessionID to be populated.

ShopSense — Dataset Generation Specification

E-commerce Product Analytics & Experimentation

Now we move on to one of the most important stages of the ShopSense project: developing a detailed Synthetic Data Generation Specification before generating the CSV files.

At this stage, we will define the number of records, user distribution, search behavior, conversion rates, hidden business problems, and A/B testing scenario.

The goal is to create data that is not merely random but realistically simulates the behavior of an e-commerce platform, incorporates meaningful behavioral patterns, and enables the discovery of underlying business problems through data analysis.

Core tables                                          Target records

16                                                        ~700K

Customers                                           Time period

10,000                                                 12 months

January 1 – December 31, 2025

All records are fictional and will be generated using Python with reproducible random seeds.

1. Number of Records per Table

In this version, we define the target record counts for each table as follows. The numbers specified for event tables are generation targets and may vary slightly in the final output.

Table                                                                                                  Target records

Users                                                                                                   10,000

Sessions                                                                                              40,000

Categories                                                                                           25

Brands                                                                                                 40

Products                                                                                              1,000

Searches                                                                                              45,000

SearchImpressions                                                                              400,000

SearchClicks                                                                                       80,000

ProductViews                                                                                     100,000

CartEvents                                                                                          30,000

CheckoutEvents                                                                                  18,000

Orders                                                                                                 6,000

OrderItems                                                                                          12,000

Experiments                                                                                        3

ExperimentVariants                                                                           6

ExperimentAssignments                                                                    15,000

Target Record Counts for the Main Tables: Small reference tables are excluded from the chart.

The total target dataset size is approximately 757,000 records. To maintain data integrity, event counts must be derived from simulated user behavior rather than adding invalid records simply to reach predetermined targets.

2-User and Session Specifications

Proposed Distribution of 40,000 Sessions, Not 10,000 Users

Traffic source distribution

Organic           35%

Paid     25%

Direct  20%

Social  12%

Email  8%

Users will not have the same number of Sessions. Some users will visit only once, while loyal customers will have multiple Sessions throughout the year. In addition, Returning Users will have a higher average purchase probability.

To avoid temporal inconsistencies, we will generate CustomerType as a synthetic profile attribute, consistent with the current definition in the Users table. For a more accurate analysis of New vs. Returning Customers, we will determine customer status based on the chronological order of Sessions and purchase history.

3. Search and Product Discovery Design

Search behavior targets

Sessions using search                                                               Average searches per search session

65%                                                                                         ~1.7

Overall search CTR                                                                Zero-result rate

~20%                                                                                       ~7%

For Search Ranking, the probability of a click will depend on the product’s Ranking Position. The following table presents the target distribution for synthetic data generation, not actual analytical results.

Result position                                                           Target CTR

1                                                                                  35%

2                                                                                  28%

3                                                                                  23%

4–5                                                                              18%

6–10                                                                            11%

11+                                                                              5%

Click probability will also be influenced by product relevance to the search query, Rating, Price, and Sponsored status. This ensures that Ranking Position is not the sole factor determining whether a user clicks on a product.

Business problem 1

High impressions / Low CTR

Approximately 5–10% of products will be designated as having low attractiveness or poor search relevance. Despite appearing in favorable ranking positions, these products will exhibit a lower CTR.

This pattern can later be investigated through Ranking Performance Analysis.

4-Conversion Funnel Design

The project’s main Conversion Funnel will be measured at the Session level. Since not all users perform a search, we will define two distinct paths: the Search Funnel and the Overall Shopping Funnel.

Business problem 2

Mobile friction

The probability of converting a Product View into an Add-to-Cart event will be designed to be lower for Mobile users than for Desktop users. Additionally, a segment of Mobile users will abandon Checkout at the Payment stage.

At the same time, Mobile users may exhibit higher levels of Search activity and Product Views. Therefore, this conversion problem cannot be identified through Engagement metrics alone.

5. Product, Category, and Revenue Design

We will distribute 1,000 products across 25 categories and 40 brands. Categories will follow a hierarchical structure, while Price, Discount, Rating, and Stock Availability will influence purchasing behavior.

For Revenue, the initial target is 6,000 orders, with an average of two items per order. Each order’s total amount must be consistent with the sum of its OrderItems, order-level discounts, taxes, and shipping costs.

Business problem 3

Category friction

In one or two Categories, Product Views and Add-to-Cart rates will be relatively high, while Purchase Conversion will be lower. This discrepancy may be associated with Price, Discounts, Stock Availability, or Checkout Abandonment.

During the analysis, we will examine the statistical relationships between these factors. However, correlation alone does not establish causation.

6. A/B Testing Design

We will define three Experiments. The project’s primary experiment will focus on Personalized Search Ranking.

Personalized Search Ranking

User-level randomized experiment

Control                                                                       Treatment

Existing ranking                                                         Personalized ranking

Display products using the current ranking algorithm.                   Rank products based on user behavior and preferences.

Allocation: 50%                                                          Allocation: 50%

Primary metric: Search-to-Purchase Conversion Rate

Secondary metrics: Search CTR، Add-to-Cart Rate و Revenue per Session

Guardrails: Zero-Result Rate و Checkout Abandonment

For synthetic data generation, we will design the Treatment effect on CTR to be more pronounced than its effect on Purchase Conversion. However, we will not predetermine the outcome of the statistical test; the results must emerge from the generated data and the subsequent statistical analysis.

The other two experiments will be Product Recommendation Layout and Checkout Simplification. Each experiment will have its own independent Control and Treatment groups.

Technical Consideration: In the primary experiment, each user will be assigned to only one Variant, and all their eligible Sessions will retain that same Variant. During data generation, we must ensure random assignment, respect the experiment start date, and prevent cross-group contamination.

7. Data Integrity and Quality Rules

This section is essential to ensuring the reliability of the generated dataset.

All Foreign Keys (FKs) must reference valid records, and every Event must occur within the time range of its associated Session.

SearchClicks must reference a valid, previously recorded Impression. Each Impression can have at most one Click.

For Product Views originating from Search, ProductViews.SearchID must reference a Search belonging to the same Session.

Orders.UserID must match the User who owns the Session referenced by Orders.SessionID.

Each assigned Variant must belong to its corresponding Experiment, and no User or Session may receive duplicate assignments within the same Experiment.

LineTotal in OrderItems is a computed column and must not be included in the input CSV file.

Two additional validation measures are required before data generation: adding a composite Unique Key to ExperimentVariants to ensure consistency between Experiments and Variants, and validating the relationships between Sessions, Searches, and Orders, since the existing Foreign Key constraints alone do not enforce all these business rules.

8. Expected Outputs from the Data Generation Stage

-Dataset deliverables

-16 CSV files, one per table

-Python data-generation script with fixed random seed

-Data validation and integrity report

-Dataset statistics and actual funnel metrics

-SQL Server import instructions

-Documented synthetic business scenarios

0 of 6 deliverables completed

-Complete the SearchImpressions Table

USE ShopSense;

GO

IF COL_LENGTH(‘dbo.SearchImpressions’, ‘IsSponsored’) IS NULL

BEGIN

    ALTER TABLE dbo.SearchImpressions

    ADD IsSponsored BIT NOT NULL

        CONSTRAINT DF_SearchImpressions_IsSponsored

        DEFAULT 0;

END;

GO

Ensuring Experiment–Variant Consistency

Important Improvement for A/B Testing

In the initial design, ExperimentID and VariantID each have a separate Foreign Key. However, these two Foreign Keys alone do not guarantee that the assigned Variant actually belongs to the specified Experiment.

For example, an Assignment associated with Experiment 1 must not be allowed to receive a Variant belonging to Experiment 3.

First, we create a Composite Unique Constraint on the ExperimentVariants table:

USE ShopSense;

GO

IF NOT EXISTS (

    SELECT 1

    FROM sys.key_constraints

    WHERE name = ‘UQ_ExperimentVariants_ExperimentVariant’

      AND parent_object_id = OBJECT_ID(‘dbo.ExperimentVariants’)

)

BEGIN

    ALTER TABLE dbo.ExperimentVariants

    ADD CONSTRAINT UQ_ExperimentVariants_ExperimentVariant

        UNIQUE (ExperimentID, VariantID);

END;

GO

Next, we create a Composite Foreign Key in the ExperimentAssignments table:

IF NOT EXISTS (

    SELECT 1

    FROM sys.foreign_keys

    WHERE name = ‘FK_Assignments_ExperimentVariant’

      AND parent_object_id = OBJECT_ID(‘dbo.ExperimentAssignments’)

)

BEGIN

    ALTER TABLE dbo.ExperimentAssignments

    WITH CHECK

    ADD CONSTRAINT FK_Assignments_ExperimentVariant

        FOREIGN KEY (ExperimentID, VariantID)

        REFERENCES dbo.ExperimentVariants

            (ExperimentID, VariantID);

END;

GO

-Ensuring User–Session Consistency in Orders

Each Order is associated with a User and a Session. We must ensure that the User recorded in the Order is the same User who owns the associated Session.

To enforce this rule, we will first create a Composite Unique Constraint in the Sessions table, followed by a Composite Foreign Key in the Orders table

IF NOT EXISTS (

    SELECT 1

    FROM sys.key_constraints

    WHERE name = ‘UQ_Sessions_SessionUser’

      AND parent_object_id = OBJECT_ID(‘dbo.Sessions’)

)

BEGIN

    ALTER TABLE dbo.Sessions

    ADD CONSTRAINT UQ_Sessions_SessionUser

        UNIQUE (SessionID, UserID);

END;

GO

IF NOT EXISTS (

    SELECT 1

    FROM sys.foreign_keys

    WHERE name = ‘FK_Orders_SessionUser’

      AND parent_object_id = OBJECT_ID(‘dbo.Orders’)

)

BEGIN

    ALTER TABLE dbo.Orders

    WITH CHECK

    ADD CONSTRAINT FK_Orders_SessionUser

        FOREIGN KEY (SessionID, UserID)

        REFERENCES dbo.Sessions(SessionID, UserID);

END;

GO

This Constraint prevents an Order from being associated with a Session belonging to another User.

4. Ensuring ProductViews Reference a Search Within the Same Session

In the ProductViews table, the SearchID field is optional. However, when it contains a value, it must reference a Search belonging to the same Session.

First, we add a Composite Unique Constraint to the Searches table:

IF NOT EXISTS (

    SELECT 1

    FROM sys.key_constraints

    WHERE name = ‘UQ_Searches_SearchSession’

      AND parent_object_id = OBJECT_ID(‘dbo.Searches’)

)

BEGIN

    ALTER TABLE dbo.Searches

    ADD CONSTRAINT UQ_Searches_SearchSession

        UNIQUE (SearchID, SessionID);

END;

GO

IF NOT EXISTS (

    SELECT 1

    FROM sys.foreign_keys

    WHERE name = ‘FK_ProductViews_SearchSession’

      AND parent_object_id = OBJECT_ID(‘dbo.ProductViews’)

)

BEGIN

    ALTER TABLE dbo.ProductViews

    WITH CHECK

    ADD CONSTRAINT FK_ProductViews_SearchSession

        FOREIGN KEY (SearchID, SessionID)

        REFERENCES dbo.Searches(SearchID, SessionID);

END;

GO

This relationship is essential for analyzing the Search → Product View journey. If SearchID is NULL, the product may have been viewed through another entry point, such as the Homepage, Category Page, or Product Recommendations.

5. Preventing Duplicate Assignments in A/B Testing

In the current design, each Assignment contains exactly one of UserID or SessionID. Therefore, we will create two Filtered Unique Indexes to prevent duplicate assignments.

IF NOT EXISTS (

    SELECT 1

    FROM sys.indexes

    WHERE name = ‘UX_Assignments_ExperimentUser’

      AND object_id = OBJECT_ID(‘dbo.ExperimentAssignments’)

)

BEGIN

    CREATE UNIQUE INDEX UX_Assignments_ExperimentUser

    ON dbo.ExperimentAssignments(ExperimentID, UserID)

    WHERE UserID IS NOT NULL;

END;

GO

IF NOT EXISTS (

    SELECT 1

    FROM sys.indexes

    WHERE name = ‘UX_Assignments_ExperimentSession’

      AND object_id = OBJECT_ID(‘dbo.ExperimentAssignments’)

)

BEGIN

    CREATE UNIQUE INDEX UX_Assignments_ExperimentSession

    ON dbo.ExperimentAssignments(ExperimentID, SessionID)

    WHERE SessionID IS NOT NULL;

END;

GO

This ensures that a User cannot be assigned more than once within the same Experiment, while still allowing them to participate in multiple experiments.

Dataset Generation Consideration

These indexes prevent duplicate assignments. However, random assignment, experiment start dates, and consistent Variant assignment across subsequent Sessions must be controlled in the Python data generation script.

6. Final Constraint Validation

USE ShopSense;

GO

SELECT

    t.name AS TableName,

    fk.name AS ForeignKeyName,

    fk.is_disabled AS IsDisabled,

    fk.is_not_trusted AS IsNotTrusted

FROM sys.foreign_keys fk

JOIN sys.tables t

    ON fk.parent_object_id = t.object_id

ORDER BY t.name, fk.name;

GO

Final Schema Checklist

IsSponsored exists in the SearchImpressions table.

ExperimentID and VariantID are consistent.

The UserID associated with each Order matches the owner of its Session.

ProductViews references a Search belonging to the same Session.

Duplicate User or Session assignments within the same Experiment are prohibited.

All new Foreign Keys are enabled and trusted.

0 of 6 checks verified.

File Preparation

USE ShopSense;

GO

SELECT

    t.name AS TableName,

    SUM(p.rows) AS [RowCount]

FROM sys.tables AS t

INNER JOIN sys.partitions AS p

    ON t.object_id = p.object_id

WHERE p.index_id IN (0, 1)

GROUP BY t.name

ORDER BY t.name;

GO

Import

We will import the files in the following order:

1. Parent tables

Users.csv

Categories.csv

Brands.csv

Experiments.csv

2. First-level child tables

Products.csv

Sessions.csv

ExperimentVariants.csv

3. Search and experimentation

Searches.csv

ExperimentAssignments.csv

4. Customer journey

SearchImpressions.csv

SearchClicks.csv

ProductViews.csv

CartEvents.csv

CheckoutEvents.csv

5. Transactions

Orders.csv

OrderItems.csv

0 of 16 tables imported

To import the CSV files into the 16 database tables, I will run Python from Command Prompt and execute the following commands:

cd /d C:\ShopSense

python import_shopsense_to_sqlserver.py

USE ShopSense;

GO

SELECT

    t.name AS TableName,

    SUM(p.rows) AS TotalRows

FROM sys.tables AS t

JOIN sys.partitions AS p

    ON t.object_id = p.object_id

WHERE p.index_id IN (0, 1)

GROUP BY t.name

ORDER BY t.name;

Final Dataset Validation

1-Verify the Record Count of Each Table

USE ShopSense;

GO

SELECT

    t.name AS TableName,

    SUM(p.rows) AS TotalRows

FROM sys.tables AS t

JOIN sys.partitions AS p

    ON t.object_id = p.object_id

WHERE p.index_id IN (0, 1)

GROUP BY t.name

ORDER BY t.name;

2. Verify the Record Counts of All Tables

USE ShopSense;

GO

WITH ExpectedCounts AS

(

    SELECT *

    FROM (VALUES

        (‘Users’, 10000),

        (‘Categories’, 25),

        (‘Brands’, 40),

        (‘Experiments’, 3),

        (‘Products’, 1000),

        (‘Sessions’, 40000),

        (‘ExperimentVariants’, 6),

        (‘Searches’, 45000),

        (‘ExperimentAssignments’, 15000),

        (‘SearchImpressions’, 400000),

        (‘SearchClicks’, 80000),

        (‘ProductViews’, 100000),

        (‘CartEvents’, 30000),

        (‘CheckoutEvents’, 27950),

        (‘Orders’, 6000),

        (‘OrderItems’, 12000)

    ) AS v(TableName, ExpectedRows)

),

ActualCounts AS

(

    SELECT

        t.name AS TableName,

        SUM(p.rows) AS ActualRows

    FROM sys.tables AS t

    JOIN sys.partitions AS p

        ON t.object_id = p.object_id

    WHERE p.index_id IN (0, 1)

    GROUP BY t.name

)

SELECT

    e.TableName,

    e.ExpectedRows,

    ISNULL(a.ActualRows, 0) AS ActualRows,

    CASE

        WHEN e.ExpectedRows = a.ActualRows

        THEN ‘PASS’

        ELSE ‘FAIL’

    END AS ValidationStatus

FROM ExpectedCounts AS e

LEFT JOIN ActualCounts AS a

    ON e.TableName = a.TableName

ORDER BY e.TableName;

3. Verify Foreign Keys & Constraints

USE ShopSense;

GO

DBCC CHECKCONSTRAINTS WITH ALL_CONSTRAINTS;

We now move on to the next stage: SQL Exploratory Data Analysis (EDA). The objective is to understand the actual dataset structure, user behavior, and initial business patterns before conducting Sales Funnel Analysis and A/B Testing.

Phase 1: Initial Data Exploration Using SQL

We will begin with five fundamental analyses:

1. User Distribution: Analyze users by Customer Type, Country, and Acquisition Source.

2. Session Analysis: Examine the number of Sessions, average Session Duration, and Device Distribution.

3. Search Behavior: Analyze the number of Searches, Zero-Result Rate, and Filter Usage Patterns.

4. Order and Revenue Analysis: Calculate the total number of Orders, Total Revenue, and Average Order Value (AOV).

5. Data Time Range Validation: Examine the dataset’s date and time ranges to ensure consistency across events.

1- Customer Overview

USE ShopSense;

GO

— 1. Customer distribution

SELECT

    CustomerType,

    COUNT(*) AS TotalUsers,

    CAST(

        100.0 * COUNT(*) / SUM(COUNT(*)) OVER ()

        AS DECIMAL(5,2)

    ) AS UserPercentage

FROM dbo.Users

GROUP BY CustomerType

ORDER BY TotalUsers DESC;

— 2. Users by country

SELECT

    Country,

    COUNT(*) AS TotalUsers

FROM dbo.Users

GROUP BY Country

ORDER BY TotalUsers DESC;

— 3. Acquisition channels

SELECT

    AcquisitionSource,

    COUNT(*) AS TotalUsers,

    CAST(

        100.0 * COUNT(*) / SUM(COUNT(*)) OVER ()

        AS DECIMAL(5,2)

    ) AS UserPercentage

FROM dbo.Users

GROUP BY AcquisitionSource

ORDER BY TotalUsers DESC;

2 Session Overview

USE ShopSense;

GO

SELECT

    DeviceType,

    COUNT(*) AS TotalSessions,

    CAST(

        AVG(CAST(SessionDurationSeconds AS FLOAT))

        AS DECIMAL(10,2)

    ) AS AvgDurationSeconds,

    CAST(

        100.0 * COUNT(*) / SUM(COUNT(*)) OVER ()

        AS DECIMAL(5,2)

    ) AS SessionPercentage

FROM dbo.Sessions

GROUP BY DeviceType

ORDER BY TotalSessions DESC;

This analysis is essential to ShopSense’s central research question: Do Mobile users exhibit different engagement patterns compared to Desktop users?

3 Search Overview

USE ShopSense;

GO

SELECT

    COUNT(*) AS TotalSearches,

    SUM(CASE WHEN ResultsCount = 0 THEN 1 ELSE 0 END)

        AS ZeroResultSearches,

    CAST(

        100.0 * SUM(CASE WHEN ResultsCount = 0 THEN 1 ELSE 0 END)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(5,2)

    ) AS ZeroResultRate,

    SUM(CASE WHEN FiltersApplied = 1 THEN 1 ELSE 0 END)

        AS FilteredSearches

FROM dbo.Searches;

This query calculates the first Search Performance KPI: the Zero-Result Rate.

4. Revenue Overview

USE ShopSense;

GO

SELECT

    COUNT(*) AS TotalOrders,

    CAST(SUM(TotalAmount) AS DECIMAL(18,2))

        AS TotalOrderValue,

    CAST(AVG(TotalAmount) AS DECIMAL(18,2))

        AS AverageOrderValue

FROM dbo.Orders;

At this stage, we examine the total value of all orders. To calculate actual revenue, we will later exclude or separately account for canceled and refunded orders based on OrderStatus.

5. Verify the Data Time Range

USE ShopSense;

GO

SELECT

    MIN(SessionStart) AS FirstSession,

    MAX(SessionStart) AS LastSession

FROM dbo.Sessions;

SELECT

    MIN(OrderDate) AS FirstOrder,

    MAX(OrderDate) AS LastOrder

FROM dbo.Orders;

At this stage, an interesting pattern emerges: approximately 55% of Sessions originate from Mobile users, yet their average Session Duration is not significantly different from that of Desktop users.

To determine whether Mobile users encounter friction in the later stages of the Conversion Funnel, we need to compare their behavior across the Search, Product View, and Purchase stages.

Analysis:

Step 1-Results of SQL Exploratory Data Analysis

1.1 Customer Overview

Approximately 62% of users are classified as Returning Customers. This variable provides a valuable opportunity to analyze behavioral differences between New and Returning Customers. However, to calculate the actual Customer Return Rate, we must also examine users’ Session and Order histories.

1.2 Session Overview

The average Session Duration is very similar across all three device types. Therefore, at this stage, there is no evidence of a substantial difference in time spent on the platform. However, Session Duration alone is not a sufficient indicator of engagement quality or purchase likelihood.

1.3. Search Overview

Seven out of every 100 searches return no results, indicating an overall Zero-Result Rate of 7%. In the next stages, we will investigate which Search Queries, Categories, and Device Types contribute most to these unsuccessful searches and whether they are associated with lower Purchase Conversion Rates.

1.4 Revenue Overview

These figures represent the total recorded value of all orders, not necessarily realized revenue. To calculate the final Revenue and Average Order Value (AOV), we must examine the status of canceled and refunded orders.

1.5 Data Time Range

Both datasets cover the 2025 calendar year. However, this check only confirms the overall data time range; the chronological sequence of each Order relative to its associated Session must be validated separately.

Step 2— Analyzing Behavioral Differences Between Mobile and Desktop Users

We now examine the first major analytical question of the project: Does the high share of Mobile users in Sessions translate into a similar share of Purchases?

The following query calculates the number of Sessions, Sessions with Search activity, Sessions with Orders, and Conversion Rate for each device type.

We use COUNT(DISTINCT …) to ensure that multiple Searches or multiple Orders within the same Session do not result in duplicate counting.

USE ShopSense;

GO

WITH SearchSessions AS

(

    SELECT DISTINCT SessionID

    FROM dbo.Searches

),

OrderSessions AS

(

    SELECT DISTINCT SessionID

    FROM dbo.Orders

)

SELECT

    s.DeviceType,

    COUNT(*) AS TotalSessions,

    COUNT(ss.SessionID) AS SearchSessions,

    COUNT(os.SessionID) AS PurchasingSessions,

    CAST(

        100.0 * COUNT(ss.SessionID)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS SearchSessionRate,

    CAST(

        100.0 * COUNT(os.SessionID)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS PurchaseConversionRate

FROM dbo.Sessions AS s

LEFT JOIN SearchSessions AS ss

    ON s.SessionID = ss.SessionID

LEFT JOIN OrderSessions AS os

    ON s.SessionID = os.SessionID

GROUP BY s.DeviceType

ORDER BY TotalSessions DESC;

| Device | Total Sessions | Search Sessions | Search Rate | Purchasing Sessions | Purchase Conversion |

| Mobile | 21,991 | 14,273 | 64.90% | 3,352 | 15.24% |

| Desktop | 14,030 | 9,166 | 65.33% | 2,041 | 14.55% |

| Tablet | 3,979 | 2,561 | 64.36% | 607 | 15.26% |

The Search Session Rates are nearly identical across the three device types, while the difference between the highest and lowest Purchase Conversion Rates is only about 0.71 percentage points. Therefore, at the overall Session level, there is no clear indication of a Mobile-specific conversion problem. In fact, Mobile accounts for 54.98% of all Sessions and has a 15.24% Conversion Rate.

However, ShopSense’s central question focuses on highly engaged Search users who fail to convert. A device-level comparison across all Sessions may therefore hide the underlying issue.

The appropriate next step is to calculate Conversion Rate specifically for Sessions with Search activity and directly connect Search behavior and Purchase outcomes within the same Session.

USE ShopSense;

GO

WITH SearchSessions AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

OrderSessions AS

(

    SELECT DISTINCT SessionID

    FROM dbo.Orders

)

SELECT

    s.DeviceType,

    COUNT(*) AS SearchSessions,

    SUM(CASE

        WHEN os.SessionID IS NOT NULL THEN 1

        ELSE 0

    END) AS SearchSessionsWithPurchase,

    SUM(CASE

        WHEN os.SessionID IS NULL THEN 1

        ELSE 0

    END) AS SearchSessionsWithoutPurchase,

    CAST(

        100.0 *

        SUM(CASE WHEN os.SessionID IS NOT NULL THEN 1 ELSE 0 END)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS SearchToPurchaseRate,

    CAST(

        AVG(CAST(ss.SearchCount AS DECIMAL(10,2)))

        AS DECIMAL(10,2)

    ) AS AvgSearchesPerSearchSession

FROM SearchSessions AS ss

JOIN dbo.Sessions AS s

    ON ss.SessionID = s.SessionID

LEFT JOIN OrderSessions AS os

    ON ss.SessionID = os.SessionID

GROUP BY s.DeviceType

ORDER BY SearchToPurchaseRate DESC;

| Device | Search Sessions | With Purchase | Without Purchase | Search → Purchase |

| Tablet | 2,561 | 400 | 2,161 | 15.62% |

| Mobile | 14,273 | 2,151 | 12,122 | 15.07% |

| Desktop | 9,166 | 1,329 | 7,837 | 14.50% |

The difference between the highest and lowest Conversion Rates is only 1.12 percentage points. Therefore, we still cannot conclude that Device Type is the primary factor behind non-conversion.

A more important finding is that, out of 26,000 Search Sessions, 22,120 did not result in a Purchase. This means approximately 85.1% of Search Sessions ended without a Purchase. This is precisely the population we need to investigate further.

Step 2.1 — High Search Engagement

We now arrive at the central analytical question of the ShopSense project:

Do highly engaged search sessions convert better or are some users repeatedly searching without purchasing?

USE ShopSense;

GO

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

)

SELECT

    SearchCount,

    COUNT(*) AS NumberOfSessions,

    CAST(

        100.0 * COUNT(*)

        / SUM(COUNT(*)) OVER ()

        AS DECIMAL(6,2)

    ) AS SessionPercentage

FROM SearchActivity

GROUP BY SearchCount

ORDER BY SearchCount;

| Search Count | Sessions | Percentage |

| 1 | 12,509 | 48.11% |

| 2 | 9,166 | 35.25% |

| 3 | 3,336 | 12.83% |

| 4 | 820 | 3.15% |

| 5 | 146 | 0.56% |

| 6 | 20 | 0.08% |

| 7 | 3 | 0.01% |

his means that 83.36% of Search Sessions contain only one or two Searches, while only about 3.8% contain four or more Searches. Based on the actual data distribution, it is therefore reasonable to define the Search Engagement segments as follows:

Low Engagement = 1 Search, Medium Engagement = 2–3 Searches, and High Engagement = 4+ Searches.

We now need to determine whether this small but highly engaged group is actually more likely to purchase, or whether repeated searching may instead indicate Search Friction.

Step 2.2 — Conversion Rate by Search Engagement

USE ShopSense;

GO

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

SearchSegments AS

(

    SELECT

        SessionID,

        SearchCount,

        CASE

            WHEN SearchCount = 1 THEN ‘Low’

            WHEN SearchCount BETWEEN 2 AND 3 THEN ‘Medium’

            ELSE ‘High’

        END AS EngagementLevel

    FROM SearchActivity

),

PurchaseSessions AS

(

    SELECT DISTINCT SessionID

    FROM dbo.Orders

)

SELECT

    ss.EngagementLevel,

    COUNT(*) AS SearchSessions,

    SUM(

        CASE

            WHEN ps.SessionID IS NOT NULL THEN 1

            ELSE 0

        END

    ) AS PurchasingSessions,

    COUNT(*) –

    SUM(

        CASE

            WHEN ps.SessionID IS NOT NULL THEN 1

            ELSE 0

        END

    ) AS NonPurchasingSessions,

    CAST(

        100.0 *

        SUM(

            CASE

                WHEN ps.SessionID IS NOT NULL THEN 1

                ELSE 0

            END

        )

        / COUNT(*)

        AS DECIMAL(6,2)

    ) AS PurchaseConversionRate,

    CAST(

        AVG(CAST(ss.SearchCount AS DECIMAL(10,2)))

        AS DECIMAL(10,2)

    ) AS AvgSearchesPerSession

FROM SearchSegments ss

LEFT JOIN PurchaseSessions ps

    ON ss.SessionID = ps.SessionID

GROUP BY ss.EngagementLevel

ORDER BY

    CASE ss.EngagementLevel

        WHEN ‘Low’ THEN 1

        WHEN ‘Medium’ THEN 2

        WHEN ‘High’ THEN 3

    END;

If the results follow a pattern such as Low > Medium > High, we would have evidence that a higher number of Searches does not necessarily indicate positive engagement and may instead signal Search Friction.

However, if the High Engagement group shows a higher Conversion Rate, our initial hypothesis would not be supported, and we would need to investigate the next stage of the Conversion Funnel.

USE ShopSense;

GO

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

SearchSegments AS

(

    SELECT

        SessionID,

        SearchCount,

        CASE

            WHEN SearchCount = 1 THEN ‘Low’

            WHEN SearchCount BETWEEN 2 AND 3 THEN ‘Medium’

            ELSE ‘High’

        END AS EngagementLevel

    FROM SearchActivity

),

PurchaseSessions AS

(

    SELECT DISTINCT SessionID

    FROM dbo.Orders

)

SELECT

    ss.EngagementLevel,

    COUNT(*) AS SearchSessions,

    SUM(

        CASE

            WHEN ps.SessionID IS NOT NULL THEN 1

            ELSE 0

        END

    ) AS PurchasingSessions,

    COUNT(*) –

    SUM(

        CASE

            WHEN ps.SessionID IS NOT NULL THEN 1

            ELSE 0

        END

    ) AS NonPurchasingSessions,

    CAST(

        100.0 *

        SUM(

            CASE

                WHEN ps.SessionID IS NOT NULL THEN 1

                ELSE 0

            END

        )

        / COUNT(*)

        AS DECIMAL(6,2)

    ) AS PurchaseConversionRate,

    CAST(

        AVG(CAST(ss.SearchCount AS DECIMAL(10,2)))

        AS DECIMAL(10,2)

    ) AS AvgSearchesPerSession

FROM SearchSegments ss

LEFT JOIN PurchaseSessions ps

    ON ss.SessionID = ps.SessionID

GROUP BY ss.EngagementLevel

ORDER BY

    CASE ss.EngagementLevel

        WHEN ‘Low’ THEN 1

        WHEN ‘Medium’ THEN 2

        WHEN ‘High’ THEN 3

    END;

So, Our initial hypothesis was not supported by the data.

| Engagement Level | Search Sessions | Purchasing Sessions | Non-Purchasing | Conversion Rate |

| Low — 1 search | 12,509 | 1,849 | 10,660 | 14.78% |

| Medium — 2–3 searches | 12,502 | 1,874 | 10,628 | 14.99% |

| High — 4+ searches | 989 | 157 | 832 | 15.87% |

The Conversion Rate increases from 14.78% → 14.99% → 15.87%. Therefore, at the overall dataset level, a higher number of Searches does not provide clear evidence of Search Friction. In fact, the High Engagement group has the highest Conversion Rate.

However, this result does not invalidate ShopSense’s central analytical question:

Why are some highly engaged search users failing to convert?

Within the High Engagement group, 832 out of 989 Sessions still did not result in a Purchase. This means that 84.13% of High Engagement Sessions ended without a Purchase.

Therefore, rather than simply comparing Conversion Rates, the next step is to investigate where these 832 non-converting High Engagement Sessions drop off within the Conversion Funnel.

Step 2.3 — High-Engagement Search Funnel Analysis

The objective of this stage is to answer the following question:

Why are some highly engaged search users failing to convert?

Step 2.3.1 — Create Analysis View

USE ShopSense;

GO

CREATE OR ALTER VIEW dbo.vw_HighEngagementSessionAnalysis

AS

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount,

        SUM(CASE WHEN ResultsCount = 0 THEN 1 ELSE 0 END) AS ZeroResultSearches,

        AVG(CAST(ResultsCount AS DECIMAL(10,2))) AS AvgResultsPerSearch

    FROM dbo.Searches

    GROUP BY SessionID

),

ProductViewActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS ProductViewCount,

        COUNT(DISTINCT ProductID) AS UniqueProductsViewed

    FROM dbo.ProductViews

    GROUP BY SessionID

),

CartActivity AS

(

    SELECT

        SessionID,

        SUM(CASE WHEN EventType = ‘Add’ THEN 1 ELSE 0 END) AS AddToCartCount

    FROM dbo.CartEvents

    GROUP BY SessionID

),

CheckoutActivity AS

(

    SELECT

        SessionID,

        SUM(CASE WHEN EventType = ‘Started’ THEN 1 ELSE 0 END)

            AS CheckoutStartedCount

    FROM dbo.CheckoutEvents

    GROUP BY SessionID

),

OrderActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS OrderCount,

        SUM(TotalAmount) AS Revenue

    FROM dbo.Orders

    GROUP BY SessionID

)

SELECT

    s.SessionID,

    s.UserID,

    s.DeviceType,

    s.TrafficSource,

    s.SessionStart,

    s.SessionDurationSeconds,

    sa.SearchCount,

    sa.ZeroResultSearches,

    sa.AvgResultsPerSearch,

    ISNULL(pv.ProductViewCount, 0) AS ProductViewCount,

    ISNULL(pv.UniqueProductsViewed, 0) AS UniqueProductsViewed,

    ISNULL(ca.AddToCartCount, 0) AS AddToCartCount,

    ISNULL(ch.CheckoutStartedCount, 0) AS CheckoutStartedCount,

    ISNULL(oa.OrderCount, 0) AS OrderCount,

    ISNULL(oa.Revenue, 0) AS Revenue,

    CASE

        WHEN ISNULL(pv.ProductViewCount, 0) > 0 THEN 1

        ELSE 0

    END AS ReachedProductView,

    CASE

        WHEN ISNULL(ca.AddToCartCount, 0) > 0 THEN 1

        ELSE 0

    END AS ReachedCart,

    CASE

        WHEN ISNULL(ch.CheckoutStartedCount, 0) > 0 THEN 1

        ELSE 0

    END AS ReachedCheckout,

    CASE

        WHEN ISNULL(oa.OrderCount, 0) > 0 THEN 1

        ELSE 0

    END AS Purchased,

    CASE

        WHEN ISNULL(oa.OrderCount, 0) > 0

            THEN ‘Purchased’

        ELSE ‘No Purchase’

    END AS PurchaseStatus

FROM dbo.Sessions s

INNER JOIN SearchActivity sa

    ON s.SessionID = sa.SessionID

LEFT JOIN ProductViewActivity pv

    ON s.SessionID = pv.SessionID

LEFT JOIN CartActivity ca

    ON s.SessionID = ca.SessionID

LEFT JOIN CheckoutActivity ch

    ON s.SessionID = ch.SessionID

LEFT JOIN OrderActivity oa

    ON s.SessionID = oa.SessionID

WHERE sa.SearchCount >= 4;

GO

Step 2.3.2 — Validation1

SELECT

    PurchaseStatus,

    COUNT(*) AS Sessions,

    CAST(

        100.0 * COUNT(*) /

        SUM(COUNT(*)) OVER ()

        AS DECIMAL(6,2)

    ) AS Percentage

FROM dbo.vw_HighEngagementSessionAnalysis

GROUP BY PurchaseStatus;

SELECT

    COUNT(*) AS HighEngagementSessions,

    SUM(Purchased) AS PurchasedSessions,

    COUNT(*) – SUM(Purchased) AS NonPurchasingSessions

FROM dbo.vw_HighEngagementSessionAnalysis;

Results:

High Engagement Sessions = 989 → Purchased = 157 (15.87%) → No Purchase = 832 (84.13%)

Step 2.3.3 — Funnel Comparison Between the Two Groups

USE ShopSense;

GO

SELECT

    PurchaseStatus,

    COUNT(*) AS TotalSessions,

    SUM(ReachedProductView) AS ReachedProductView,

    CAST(

        100.0 * SUM(ReachedProductView) / COUNT(*)

        AS DECIMAL(6,2)

    ) AS ProductViewRate,

    SUM(ReachedCart) AS ReachedCart,

    CAST(

        100.0 * SUM(ReachedCart) / COUNT(*)

        AS DECIMAL(6,2)

    ) AS CartRate,

    SUM(ReachedCheckout) AS ReachedCheckout,

    CAST(

        100.0 * SUM(ReachedCheckout) / COUNT(*)

        AS DECIMAL(6,2)

    ) AS CheckoutRate,

    SUM(Purchased) AS PurchasedSessions,

    CAST(

        100.0 * SUM(Purchased) / COUNT(*)

        AS DECIMAL(6,2)

    ) AS PurchaseRate

FROM dbo.vw_HighEngagementSessionAnalysis

GROUP BY PurchaseStatus

ORDER BY

    CASE

        WHEN PurchaseStatus = ‘Purchased’ THEN 1

        ELSE 2

    END;

For the High Engagement + Purchased group, all 157 Sessions reached the Product View, Cart, and Checkout stages. In contrast, within the High Engagement + No Purchase group, all 832 Sessions reached Product View, while only 144 Sessions (17.31%) reached Cart, and only 55 Sessions (6.61%) reached Checkout.

Therefore, the first major ShopSense finding is:

The primary issue does not appear to be at the Search → Product View stage. High-engagement users are viewing products, but a large proportion of non-purchasers drop off after Product View and before Add to Cart.

This is exactly the type of insight that adds value to a Product Analytics project. High Search activity alone did not indicate friction, but once we examined the user journey in greater detail, we identified potential Post-Search / Product-Consideration Friction.

ReachedCheckout for the No Purchase group is 55, while the CheckoutRate is not visible. Based on the data, the rate is:

55/832 * 100 = 6.61%

Therefore, the current funnel for the High Engagement + No Purchase group is:

832 Product Views (100%) → 144 Cart (17.31%) → 55 Checkout (6.61%) → 0 Purchase

Step 2.3.4 — Identifying the Causes of Drop-off Between Product View → Cart

At this point, we know that the High Engagement + No Purchase group contains 832 Sessions. All 832 Sessions reached the Product View stage, but only 144 Sessions reached Cart. Therefore, 688 Sessions dropped off specifically after Product View and before Add to Cart.

The first step is to extract these 688 Sessions as a separate analytical segment and verify that the count is correct.

USE ShopSense;

GO

— 2.3.4

— High Engagement + No Purchase

— Sessions that reached Product View but never reached Cart

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.UserID,

        s.DeviceType,

        s.TrafficSource,

        s.SessionDurationSeconds,

        sa.SearchCount

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

ProductViewNoCart AS

(

    SELECT

        h.SessionID,

        h.UserID,

        h.DeviceType,

        h.TrafficSource,

        h.SessionDurationSeconds,

        h.SearchCount

    FROM HighEngagementNoPurchase h

    WHERE EXISTS

    (

        SELECT 1

        FROM dbo.ProductViews pv

        WHERE pv.SessionID = h.SessionID

    )

    AND NOT EXISTS

    (

        SELECT 1

        FROM dbo.CartEvents ce

        WHERE ce.SessionID = h.SessionID

          AND ce.EventType = ‘Add’

    )

)

SELECT

    COUNT(*) AS ProductViewNoCartSessions

FROM ProductViewNoCart;

832 High Engagement + No Purchase → 688 No Cart + 144 Reached Cart

This means that 82.69% of High-Engagement Non-Purchasers do not even reach the Add-to-Cart stage after viewing products. The next step is to determine what differentiates these 688 Sessions from the 144 Sessions that did reach Cart.

Step 2.3.4.1 — Comparing Product View Behavior

First, we examine whether Sessions that did not reach Cart differ in terms of the number of Product Views and the amount of time spent viewing products.

USE ShopSense;

GO

— 2.3.4.1

— Product View behavior:

— Reached Cart vs No Cart

— within High Engagement + No Purchase sessions

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        sa.SearchCount

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

SessionProductViews AS

(

    SELECT

        h.SessionID,

        COUNT(pv.ProductViewID) AS ProductViewCount,

        AVG(CAST(pv.ViewDurationSeconds AS DECIMAL(10,2)))

            AS AvgProductViewDuration

    FROM HighEngagementNoPurchase h

    INNER JOIN dbo.ProductViews pv

        ON h.SessionID = pv.SessionID

    GROUP BY h.SessionID

),

SessionBehavior AS

(

    SELECT

        spv.SessionID,

        CASE

            WHEN EXISTS

            (

                SELECT 1

                FROM dbo.CartEvents ce

                WHERE ce.SessionID = spv.SessionID

                  AND ce.EventType = ‘Add’

            )

            THEN ‘Reached Cart’

            ELSE ‘No Cart’

        END AS CartStatus,

        spv.ProductViewCount,

        spv.AvgProductViewDuration

    FROM SessionProductViews spv

)

SELECT

    CartStatus,

    COUNT(*) AS Sessions,

    CAST(

        AVG(CAST(ProductViewCount AS DECIMAL(10,2)))

        AS DECIMAL(10,2)

    ) AS AvgProductViewsPerSession,

    CAST(

        AVG(AvgProductViewDuration)

        AS DECIMAL(10,2)

    ) AS AvgViewDurationSeconds

FROM SessionBehavior

GROUP BY CartStatus

ORDER BY CartStatus;

The differences are very small. No Cart Sessions have, on average, only 0.11 more Product Views and approximately 2.06 seconds more product viewing time.

Therefore, at this stage, there is no evidence that the drop-off is caused by fewer Product Views or less time spent on Product Pages. In fact, No Cart users show nearly the same level of product engagement, yet they do not proceed to Add to Cart.

This is important to the ShopSense analytical narrative: Engagement is present, but that engagement is not translating into the next stage of purchase intent. However, we still cannot determine the underlying cause; we have only weakened one possible explanation.

Step 2.3.4.2 — Does Search Click Behavior Make a Difference?

Next, we examine whether the No Cart group actually clicks on search results after performing a Search.

| Metric | No Cart | Reached Cart | Difference |

| Sessions | 688 | 144 | — |

| Avg Searches / Session | 4.20 | 4.15 | +0.05 |

| Avg Search Clicks / Session | 7.51 | 7.41 | +0.10 |

| Sessions with Search Click | 688 | 144 | — |

| Search Click Session Rate | 100% | 100% | 0 pp |

The No Cart group does not perform fewer Searches; in fact, their average number of Searches and Search Clicks is slightly higher. In addition, 100% of both groups recorded at least one Search Click.

So far, two hypotheses have been weakened. In Step 2.3.4.1, we found that Product View Count and View Duration were nearly identical between the groups. In Step 2.3.4.2, Search activity and Search Click behavior were also very similar.

Therefore, the current data story is:

High-engagement non-purchasers are actively searching, clicking search results, and viewing products, but most fail to progress from product consideration to Add to Cart.

This is an important finding for the ShopSense case study, but we still cannot say why this behavior occurs. At this stage, we have only narrowed down where the potential friction occurs.

Step 2.3.4.3 — Are the Viewed Products Different?

The next logical step is to investigate whether the No Cart group views products with different characteristics in terms of Price, Discount, Rating, or Stock Availability.

USE ShopSense;

GO

— 2.3.4.3

— Product characteristics

— Reached Cart vs No Cart

— High Engagement + No Purchase

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

SessionCartStatus AS

(

    SELECT

        h.SessionID,

        CASE

            WHEN EXISTS

            (

                SELECT 1

                FROM dbo.CartEvents ce

                WHERE ce.SessionID = h.SessionID

                  AND ce.EventType = ‘Add’

            )

            THEN ‘Reached Cart’

            ELSE ‘No Cart’

        END AS CartStatus

    FROM HighEngagementNoPurchase h

),

SessionProductMetrics AS

(

    SELECT

        cs.SessionID,

        cs.CartStatus,

        AVG(CAST(p.ListPrice AS DECIMAL(18,2)))

            AS AvgViewedPrice,

        AVG(CAST(p.DiscountPercent AS DECIMAL(18,2)))

            AS AvgViewedDiscount,

        AVG(CAST(p.Rating AS DECIMAL(18,2)))

            AS AvgViewedRating,

        AVG(CAST(p.StockQuantity AS DECIMAL(18,2)))

            AS AvgViewedStock

    FROM SessionCartStatus cs

    INNER JOIN dbo.ProductViews pv

        ON cs.SessionID = pv.SessionID

    INNER JOIN dbo.Products p

        ON pv.ProductID = p.ProductID

    GROUP BY

        cs.SessionID,

        cs.CartStatus

)

SELECT

    CartStatus,

    COUNT(*) AS Sessions,

    CAST(AVG(AvgViewedPrice)

        AS DECIMAL(10,2)) AS AvgViewedPrice,

    CAST(AVG(AvgViewedDiscount)

        AS DECIMAL(10,2)) AS AvgViewedDiscountPercent,

    CAST(AVG(AvgViewedRating)

        AS DECIMAL(10,2)) AS AvgViewedRating,

    CAST(AVG(AvgViewedStock)

        AS DECIMAL(10,2)) AS AvgViewedStock

FROM SessionProductMetrics

GROUP BY CartStatus

ORDER BY CartStatus;

These differences are small. More importantly, the direction of Price and Stock Availability is not consistent with the simple hypothesis that No Cart users are viewing more expensive products or products with lower stock availability. Therefore, at this stage, Price, Discount, Rating, and Stock do not provide a clear explanation for the failure to Add to Cart.

So far, we have weakened three straightforward explanations: Product View behavior is nearly identical, Search/Click behavior is nearly identical, and general product characteristics are also very similar. This is exactly what moves the analysis beyond simple KPI reporting toward diagnostic product analysis.

Step 2.3.4.4 — Is the Problem Related to Category Mix?

We now need to go one level deeper. Although average Price and Rating may be similar between the groups, the No Cart group may be viewing a different mix of product Categories.

USE ShopSense;

GO

— 2.3.4.4

— Category-level Cart Progression

— High Engagement + No Purchase only

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

SessionCartStatus AS

(

    SELECT

        h.SessionID,

        CASE

            WHEN EXISTS

            (

                SELECT 1

                FROM dbo.CartEvents ce

                WHERE ce.SessionID = h.SessionID

                  AND ce.EventType = ‘Add’

            )

            THEN 1

            ELSE 0

        END AS ReachedCart

    FROM HighEngagementNoPurchase h

),

SessionCategories AS

(

    SELECT DISTINCT

        cs.SessionID,

        cs.ReachedCart,

        p.CategoryID

    FROM SessionCartStatus cs

    INNER JOIN dbo.ProductViews pv

        ON cs.SessionID = pv.SessionID

    INNER JOIN dbo.Products p

        ON pv.ProductID = p.ProductID

)

SELECT

    c.CategoryID,

    c.CategoryName,

    COUNT(*) AS SessionsViewingCategory,

    SUM(sc.ReachedCart) AS ReachedCartSessions,

    COUNT(*) – SUM(sc.ReachedCart) AS NoCartSessions,

    CAST(

        100.0 * SUM(sc.ReachedCart)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS CartProgressionRate

FROM SessionCategories sc

INNER JOIN dbo.Categories c

    ON sc.CategoryID = c.CategoryID

GROUP BY

    c.CategoryID,

    c.CategoryName

ORDER BY

    CartProgressionRate ASC,

    SessionsViewingCategory DESC;

The lowest Cart Progression Rate is observed for Furniture at 13.88%, while the highest is Travel at 19.71%, representing a range of approximately 5.83 percentage points. Other Categories at the higher end of the table include Shoes = 18.15%, Accessories = 18.73%, Skincare = 18.75%, Fiction = 19.03%, and Smart Home = 19.46%.

This indicates that Category is associated with some variation in Cart Progression, but no individual Category shows an exceptionally severe or unusual drop-off. Therefore, we will retain Category as a potential secondary factor, but there is currently insufficient evidence to consider it the primary explanation for the 688 No Cart Sessions.

So far, our diagnostic path has developed systematically:

Product Views are nearly identical → Search/Clicks are nearly identical → Product Characteristics are nearly identical → Category shows only limited variation.

The next logical step is:

Step 2.3.4.5 — Device × Cart Progression

This analysis is important because we now want to determine whether the substantial pre-Cart drop-off is concentrated among Mobile, Desktop, or Tablet Sessions.

USE ShopSense;

GO

— 2.3.4.5

— Device × Cart Progression

— High Engagement + No Purchase only

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.DeviceType

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

SessionCartStatus AS

(

    SELECT

        h.SessionID,

        h.DeviceType,

        CASE

            WHEN EXISTS

            (

                SELECT 1

                FROM dbo.CartEvents ce

                WHERE ce.SessionID = h.SessionID

                  AND ce.EventType = ‘Add’

            )

            THEN 1

            ELSE 0

        END AS ReachedCart

    FROM HighEngagementNoPurchase h

)

SELECT

    DeviceType,

    COUNT(*) AS TotalSessions,

    SUM(ReachedCart) AS ReachedCartSessions,

    COUNT(*) – SUM(ReachedCart) AS NoCartSessions,

    CAST(

        100.0 * SUM(ReachedCart)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS CartProgressionRate

FROM SessionCartStatus

GROUP BY DeviceType

ORDER BY CartProgressionRate ASC;

Key Finding

Contrary to our initial hypothesis about Mobile users, Mobile is not the weakest-performing device. The lowest Cart Progression Rate is observed on Desktop at 14.59%, compared with 18.05% for Mobile and 22.50% for Tablet.

The gap between Desktop and Tablet is 7.91 percentage points, while the difference between Desktop and Mobile is 3.46 percentage points. These differences are more pronounced than many of the variations observed in the previous diagnostic steps.

However, we should not yet conclude that Desktop is the cause of the problem. Desktop Sessions may simply have a different mix of Traffic Sources, Categories, or User segments.

Step 2.3.4.6 — Traffic Source × Cart Progression

Next, we examine whether the Session Traffic Source provides a stronger explanation for the observed differences in Cart Progression.

USE ShopSense;

GO

— 2.3.4.6

— Traffic Source × Cart Progression

— High Engagement + No Purchase only

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

SessionCartStatus AS

(

    SELECT

        h.SessionID,

        h.TrafficSource,

        CASE

            WHEN EXISTS

            (

                SELECT 1

                FROM dbo.CartEvents ce

                WHERE ce.SessionID = h.SessionID

                  AND ce.EventType = ‘Add’

            )

            THEN 1

            ELSE 0

        END AS ReachedCart

    FROM HighEngagementNoPurchase h

)

SELECT

    TrafficSource,

    COUNT(*) AS TotalSessions,

    SUM(ReachedCart) AS ReachedCartSessions,

    COUNT(*) – SUM(ReachedCart) AS NoCartSessions,

    CAST(

        100.0 * SUM(ReachedCart)

        / NULLIF(COUNT(*),0)

        AS DECIMAL(6,2)

    ) AS CartProgressionRate

FROM SessionCartStatus

GROUP BY TrafficSource

ORDER BY CartProgressionRate ASC;

This result shows a stronger signal than either Category or Device, and the totals are internally consistent: 832 Sessions, including 144 Reached Cart Sessions and 688 No Cart Sessions.

Across Traffic Sources, the Cart Progression Rate ranges from 8.20% for Email to 20.45% for Organic, representing a difference of 12.25 percentage points. Email has only 5 Reached Cart Sessions out of 61, while Social is also relatively low at 14.53%. In contrast, Organic reaches 20.45% across 308 Sessions.

Therefore, Traffic Source is currently the strongest segmentation signal identified in our diagnostic analysis. However, this association still does not establish the underlying cause of the drop-off.

As planned, the next step is to examine the interaction between Device and Traffic Source to determine whether combining these two dimensions reveals a more concentrated pattern.

2.3.4.7 — Device × Traffic Source × Cart Progression

USE ShopSense;

GO

— 2.3.4.7

— Device × Traffic Source × Cart Progression

— High Engagement + No Purchase only

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.DeviceType,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

SessionCartStatus AS

(

    SELECT

        h.SessionID,

        h.DeviceType,

        h.TrafficSource,

        CASE

            WHEN EXISTS

            (

                SELECT 1

                FROM dbo.CartEvents ce

                WHERE ce.SessionID = h.SessionID

                  AND ce.EventType = ‘Add’

            )

            THEN 1

            ELSE 0

        END AS ReachedCart

    FROM HighEngagementNoPurchase h

)

SELECT

    DeviceType,

    TrafficSource,

    COUNT(*) AS TotalSessions,

    SUM(ReachedCart) AS ReachedCartSessions,

    COUNT(*) – SUM(ReachedCart) AS NoCartSessions,

    CAST(

        100.0 * SUM(ReachedCart)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS CartProgressionRate

FROM SessionCartStatus

GROUP BY

    DeviceType,

    TrafficSource

ORDER BY

    CartProgressionRate ASC,

    TotalSessions DESC;

This output reveals an important pattern: Traffic Source appears to be a stronger signal than Device, and the cross-analysis further supports this observation.

Among the segments with a reasonable number of Sessions, Email performs poorly across both major device types: Mobile + Email = 8.70% and Desktop + Email = 9.09%. Similarly, Social shows an 11.11% Cart Progression Rate for both Mobile and Desktop. This suggests that the weaker performance associated with Email is not limited to either Desktop or Mobile.

Although Tablet + Email = 0% appears notable, this segment contains only 5 Sessions, so it is too small to support a reliable conclusion. Likewise, Tablet + Direct = 5.26% is based on only 19 Sessions and should be interpreted cautiously.

In the second part of the analysis, Desktop + Organic = 18.48% and Mobile + Organic = 19.90%, indicating that Organic performs relatively strongly and consistently across the two main device types. In contrast, as observed previously, Email performs poorly on both Mobile (8.70%) and Desktop (9.09%). This consistency across devices provides further evidence that the observed variation is more strongly associated with Traffic Source than with Device itself.

Mobile + Direct = 22.89% is also noteworthy because it is based on a relatively meaningful sample of 83 Sessions. However, Tablet + Organic = 32.00% and Tablet + Social = 33.33% should be interpreted cautiously, as they are based on only 25 and 18 Sessions, respectively. This illustrates exactly why the next statistical validation step is necessary.

Therefore, the preliminary conclusion from Step 2.3.4.7 is that, within the High Engagement + No Purchase segment, Traffic Source shows a stronger signal for Cart Progression than Device. In particular, Email consistently shows lower Cart Progression, while Organic performs relatively strongly.

However, we still should not interpret Traffic Source as the cause of the observed differences; at this stage, the results indicate an association rather than causation.

2.3.5 – Statistical Validation

So far, our SQL analysis has shown that within the High Engagement + No Purchase group, Cart Progression Rates vary across Traffic Sources. The next step is to determine whether these differences are statistically reliable or could simply be the result of sampling variation.

The most appropriate comparison to begin with is Organic vs. Email.

Organic: 63 out of 308 Sessions → 20.45%

Email: 5 out of 61 Sessions → 8.20%

Observed Difference: 12.25 percentage points

2.3.5.1 — Organic vs. Email: Statistical Significance

We define the hypotheses as follows:

H₀ (Null Hypothesis): The Cart Progression Rates for Organic and Email are equal.

H₁ (Alternative Hypothesis): The Cart Progression Rates for Organic and Email are different.

Because our outcome variable is binary a Session either reaches Cart or does not the appropriate statistical test is a Two-Proportion Z-Test.

USE ShopSense;

GO

— 2.3.5.1

— Statistical Validation Dataset

— Organic vs Email

— High Engagement + No Purchase only

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

      AND s.TrafficSource IN (‘Organic’, ‘Email’)

),

SessionCart AS

(

    SELECT

        h.SessionID,

        h.TrafficSource,

        CASE

            WHEN EXISTS

            (

                SELECT 1

                FROM dbo.CartEvents ce

                WHERE ce.SessionID = h.SessionID

                  AND ce.EventType = ‘Add’

            )

            THEN 1

            ELSE 0

        END AS ReachedCart

    FROM HighEngagementNoPurchase h

)

SELECT

    TrafficSource,

    COUNT(*) AS TotalSessions,

    SUM(ReachedCart) AS ReachedCartSessions,

    COUNT(*) – SUM(ReachedCart) AS NoCartSessions,

    CAST(

        100.0 * SUM(ReachedCart)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS CartProgressionRate

FROM SessionCart

GROUP BY TrafficSource

ORDER BY TrafficSource;

2.3.5.2 — Two-Proportion Z-Test

We now move into the Python environment:

import numpy as np

from statsmodels.stats.proportion import proportions_ztest

# Organic

organic_success = 63

organic_total = 308

# Email

email_success = 5

email_total = 61

successes = np.array([organic_success, email_success])

observations = np.array([organic_total, email_total])

z_stat, p_value = proportions_ztest(

    count=successes,

    nobs=observations,

    alternative=’two-sided’

)

organic_rate = organic_success / organic_total

email_rate = email_success / email_total

difference = organic_rate – email_rate

print(f”Organic Cart Progression Rate: {organic_rate:.2%}”)

print(f”Email Cart Progression Rate:   {email_rate:.2%}”)

print(f”Absolute Difference:           {difference:.2%}”)

print(f”Z-statistic:                   {z_stat:.4f}”)

print(f”P-value:                       {p_value:.4f}”)

H₀:  Organic Cart Progression Rate = Email Cart Progression Rate

H₁:  Organic Cart Progression Rate ≠ Email Cart Progression Rate

α = 0.05

| Metric                        |                      Result |

| Organic Cart Progression Rate |                  20.45% |

| Email Cart Progression Rate   |                   8.20% |

| Absolute Difference           | 12.26 percentage points |

| Z-statistic                   |                  2.2559 |

| P-value                       |                  0.0241 |

p = 0.0241 < α = 0.05

At the 5% significance level, we reject the null hypothesis (H₀). This indicates that, within the ShopSense dataset, there is statistically significant evidence of a difference in Cart Progression Rates between Organic and Email for the High Engagement + No Purchase group.

Among High Engagement + No Purchase sessions, Organic traffic showed a significantly higher Cart Progression Rate than Email traffic (20.45% vs. 8.20%; two-proportion z-test, z = 2.256, p = 0.024).

2.3.5.3 — 95% Confidence Interval + Effect Size

Now we need to answer a more important question: How large is this difference, and what is its plausible range?

import numpy as np

from statsmodels.stats.proportion import (

    proportions_ztest,

    confint_proportions_2indep,

    proportion_effectsize

)

# ————————————————–

# ShopSense

# 2.3.5 Statistical Validation

# Organic vs Email Cart Progression

# High Engagement + No Purchase

# ————————————————–

# Organic

organic_success = 63

organic_total = 308

# Email

email_success = 5

email_total = 61

# ————————————————–

# 1. Cart Progression Rates

# ————————————————–

organic_rate = organic_success / organic_total

email_rate = email_success / email_total

difference = organic_rate – email_rate

# ————————————————–

# 2. Two-Proportion Z-Test

# ————————————————–

successes = np.array([

    organic_success,

    email_success

])

observations = np.array([

    organic_total,

    email_total

])

z_stat, p_value = proportions_ztest(

    count=successes,

    nobs=observations,

    alternative=’two-sided’

)

# ————————————————–

# 3. 95% Confidence Interval

# ————————————————–

ci_low, ci_high = confint_proportions_2indep(

    count1=organic_success,

    nobs1=organic_total,

    count2=email_success,

    nobs2=email_total,

    method=’wald’,

    compare=’diff’,

    alpha=0.05

)

# ————————————————–

# 4. Effect Size – Cohen’s h

# ————————————————–

cohens_h = proportion_effectsize(

    organic_rate,

    email_rate

)

# ————————————————–

# 5. Results

# ————————————————–

print(“SHOPSense Statistical Validation”)

print(“——————————–“)

print(f”Organic Cart Progression Rate: {organic_rate:.2%}”)

print(f”Email Cart Progression Rate:   {email_rate:.2%}”)

print(f”Absolute Difference:           {difference:.2%}”)

print(“\nTwo-Proportion Z-Test”)

print(f”Z-statistic:                   {z_stat:.4f}”)

print(f”P-value:                       {p_value:.4f}”)

print(“\nEffect & Uncertainty”)

print(f”95% Confidence Interval:       [{ci_low:.2%}, {ci_high:.2%}]”)

print(f”Cohen’s h:                     {cohens_h:.4f}”)

print(“\nDecision”)

if p_value < 0.05:

    print(“Reject H0: The difference is statistically significant.”)

else:

    print(“Fail to reject H0: The difference is not statistically significant.”)

| Metric                        |                      Result |

| Organic Cart Progression Rate |                  20.45% |

| Email Cart Progression Rate   |                   8.20% |

| Absolute Difference           | 12.26 percentage points |

| Z-statistic                   |                  2.2559 |

| P-value                       |                  0.0241 |

| 95% CI for Difference         |         [4.03%, 20.48%] |

| Cohen’s h                     |                  0.3579 |

Organic vs Email: Statistical Significance

Among High Engagement + No Purchase sessions, Organic traffic showed a 20.45% Cart Progression Rate (63/308) compared with 8.20% (5/61) for Email traffic, representing an observed difference of approximately 12.26 percentage points.

A two-proportion z-test found this difference to be statistically significant (z = 2.256, p = 0.024). The 95% confidence interval for the difference was 4.03 to 20.48 percentage points, which does not include zero and therefore supports the statistical-test result.

The standardized effect size was Cohen’s h = 0.358, indicating a difference between a small and medium effect under conventional benchmarks.

These results provide evidence that Cart Progression differs between Organic and Email sessions within this segment. However, because this is observational traffic-source data rather than a randomized experiment, the result should be interpreted as an association rather than a causal effect of traffic source.

2.3.6 — Email Traffic Deep Dive

Within the High Engagement + No Purchase group, the Cart Progression Rate is 20.45% (63/308) for Organic and 8.20% (5/61) for Email. The observed difference is 12.26 percentage points and is statistically significant (p = 0.0241).

The key question for Step 2.3.6 is:

Why does Email traffic show substantially lower Cart Progression than Organic traffic among High Engagement + No Purchase sessions?

2.3.6.1 — Email vs Organic by Device

First, we need to determine whether the lower Cart Progression Rate for Email is simply explained by its Device mix. For example, if a large proportion of Email Sessions comes from a device type with a lower Cart Progression Rate, then Traffic Source itself may not be the primary factor associated with the difference.

USE ShopSense;

GO

— 2.3.6.1

— Email vs Organic by Device

— High Engagement + No Purchase only

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.DeviceType,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Organic’, ‘Email’)

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

SessionCart AS

(

    SELECT

        h.SessionID,

        h.TrafficSource,

        h.DeviceType,

        CASE

            WHEN EXISTS

            (

                SELECT 1

                FROM dbo.CartEvents ce

                WHERE ce.SessionID = h.SessionID

                  AND ce.EventType = ‘Add’

            )

            THEN 1

            ELSE 0

        END AS ReachedCart

    FROM HighEngagementNoPurchase h

)

SELECT

    TrafficSource,

    DeviceType,

    COUNT(*) AS TotalSessions,

    SUM(ReachedCart) AS ReachedCartSessions,

    COUNT(*) – SUM(ReachedCart) AS NoCartSessions,

    CAST(

        100.0 * SUM(ReachedCart)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS CartProgressionRate

FROM SessionCart

GROUP BY

    TrafficSource,

    DeviceType

ORDER BY

    DeviceType,

    TrafficSource;

Device Mix Finding:

The lower Cart Progression Rate observed for Email traffic does not appear to be explained solely by device composition. Organic sessions showed higher Cart Progression than Email on both Desktop (18.48% vs. 9.09%) and Mobile (19.90% vs. 8.70%). Tablet showed an even larger difference (32.00% vs. 0.00%), although the Email sample contained only five Tablet sessions and should therefore be interpreted cautiously.

2.3.6.2 — Does Search Behavior Differ for Email?

The next question is:

Despite being classified as High Engagement, do Email users behave differently from Organic users in terms of the number of Searches, Search Clicks, and Product Views?

USE ShopSense;

GO

— 2.3.6.2

— Search & Product Discovery Behavior

— Email vs Organic

— High Engagement + No Purchase only

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.TrafficSource,

        sa.SearchCount

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Organic’, ‘Email’)

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

SearchClickActivity AS

(

    SELECT

        se.SessionID,

        COUNT(sc.ClickID) AS SearchClickCount

    FROM dbo.Searches se

    LEFT JOIN dbo.SearchImpressions si

        ON se.SearchID = si.SearchID

    LEFT JOIN dbo.SearchClicks sc

        ON si.ImpressionID = sc.ImpressionID

    GROUP BY se.SessionID

),

ProductViewActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS ProductViewCount,

        AVG(CAST(ViewDurationSeconds AS DECIMAL(10,2)))

            AS AvgViewDurationSeconds

    FROM dbo.ProductViews

    GROUP BY SessionID

),

SessionMetrics AS

(

    SELECT

        h.SessionID,

        h.TrafficSource,

        h.SearchCount,

        ISNULL(sc.SearchClickCount, 0) AS SearchClickCount,

        ISNULL(pv.ProductViewCount, 0) AS ProductViewCount,

        ISNULL(pv.AvgViewDurationSeconds, 0) AS AvgViewDurationSeconds

    FROM HighEngagementNoPurchase h

    LEFT JOIN SearchClickActivity sc

        ON h.SessionID = sc.SessionID

    LEFT JOIN ProductViewActivity pv

        ON h.SessionID = pv.SessionID

)

SELECT

    TrafficSource,

    COUNT(*) AS TotalSessions,

    CAST(

        AVG(CAST(SearchCount AS DECIMAL(10,2)))

        AS DECIMAL(10,2)

    ) AS AvgSearchesPerSession,

    CAST(

        AVG(CAST(SearchClickCount AS DECIMAL(10,2)))

        AS DECIMAL(10,2)

    ) AS AvgSearchClicksPerSession,

    CAST(

        AVG(CAST(ProductViewCount AS DECIMAL(10,2)))

        AS DECIMAL(10,2)

    ) AS AvgProductViewsPerSession,

    CAST(

        AVG(AvgViewDurationSeconds)

        AS DECIMAL(10,2)

    ) AS AvgProductViewDurationSeconds

FROM SessionMetrics

GROUP BY TrafficSource

ORDER BY TrafficSource;

Search & Product Discovery Behavior

Within the High Engagement + No Purchase segment, Email and Organic sessions showed broadly similar search and product-discovery behavior. Email sessions averaged 4.11 searches, 7.90 search clicks, and 8.39 product views per session, compared with 4.18, 7.39, and 7.92 for Organic sessions. Average product-view duration was slightly lower for Email (243.02 vs. 254.81 seconds). These results suggest that the substantially lower Email Cart Progression Rate (8.20% vs. 20.45%) is unlikely to be explained simply by weaker search or browsing engagement.

2.3.6.3 — Product / Category Mix

2.3.6.3.1 — Category Mix by Traffic Source

Are Email users being directed toward Products or Categories that inherently have lower Cart Progression Rates?

This step is important because the issue may not be related to Email itself. For example, Email campaigns may direct users disproportionately toward Furniture, Laptops, or other Categories that already exhibit lower Cart Progression Rates.

USE ShopSense;

GO

— 2.3.6.3.1

— Category Mix: Email vs Organic

— High Engagement + No Purchase only

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

TargetSessions AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE

        sa.SearchCount >= 4

        AND s.TrafficSource IN (‘Email’, ‘Organic’)

        AND NOT EXISTS

        (

            SELECT 1

            FROM dbo.Orders o

            WHERE o.SessionID = s.SessionID

        )

),

SessionCategories AS

(

    SELECT DISTINCT

        ts.SessionID,

        ts.TrafficSource,

        c.CategoryID,

        c.CategoryName

    FROM TargetSessions ts

    INNER JOIN dbo.ProductViews pv

        ON pv.SessionID = ts.SessionID

    INNER JOIN dbo.Products p

        ON p.ProductID = pv.ProductID

    INNER JOIN dbo.Categories c

        ON c.CategoryID = p.CategoryID

),

CategoryCounts AS

(

    SELECT

        TrafficSource,

        CategoryID,

        CategoryName,

        COUNT(*) AS SessionsViewingCategory

    FROM SessionCategories

    GROUP BY

        TrafficSource,

        CategoryID,

        CategoryName

),

SourceTotals AS

(

    SELECT

        TrafficSource,

        COUNT(*) AS TotalSessions

    FROM TargetSessions

    GROUP BY TrafficSource

)

SELECT

    cc.TrafficSource,

    cc.CategoryID,

    cc.CategoryName,

    cc.SessionsViewingCategory,

    st.TotalSessions,

    CAST(

        100.0 * cc.SessionsViewingCategory

        / NULLIF(st.TotalSessions, 0)

        AS DECIMAL(6,2)

    ) AS CategoryReachPercent

FROM CategoryCounts cc

INNER JOIN SourceTotals st

    ON st.TrafficSource = cc.TrafficSource

ORDER BY

    cc.CategoryName,

    cc.TrafficSource;

The difference in Category Mix does not appear particularly large at this stage. For example, Accessories accounts for 32.79% of Email views versus 28.90% of Organic views, Audio accounts for 44.26% versus 43.51%, and Decor accounts for 26.23% versus 28.57%.

However, to draw a reliable conclusion, we need to compare the distribution across all 19 Categories, rather than relying on a few individual examples.

2.3.6.3.2 — Calculating the Difference in Category Mix

USE ShopSense;

GO

— 2.3.6.3.2

— Category Mix Difference: Email vs Organic

— High Engagement + No Purchase only

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

TargetSessions AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE

        sa.SearchCount >= 4

        AND s.TrafficSource IN (‘Email’, ‘Organic’)

        AND NOT EXISTS

        (

            SELECT 1

            FROM dbo.Orders o

            WHERE o.SessionID = s.SessionID

        )

),

SessionCategories AS

(

    SELECT DISTINCT

        ts.SessionID,

        ts.TrafficSource,

        c.CategoryID,

        c.CategoryName

    FROM TargetSessions ts

    INNER JOIN dbo.ProductViews pv

        ON pv.SessionID = ts.SessionID

    INNER JOIN dbo.Products p

        ON p.ProductID = pv.ProductID

    INNER JOIN dbo.Categories c

        ON c.CategoryID = p.CategoryID

),

CategoryCounts AS

(

    SELECT

        TrafficSource,

        CategoryID,

        CategoryName,

        COUNT(*) AS SessionsViewingCategory

    FROM SessionCategories

    GROUP BY

        TrafficSource,

        CategoryID,

        CategoryName

),

SourceTotals AS

(

    SELECT

        TrafficSource,

        COUNT(*) AS TotalSessions

    FROM TargetSessions

    GROUP BY TrafficSource

),

CategoryRates AS

(

    SELECT

        cc.CategoryID,

        cc.CategoryName,

        cc.TrafficSource,

        100.0 * cc.SessionsViewingCategory

            / NULLIF(st.TotalSessions, 0) AS CategoryReachPercent

    FROM CategoryCounts cc

    INNER JOIN SourceTotals st

        ON cc.TrafficSource = st.TrafficSource

),

Comparison AS

(

    SELECT

        CategoryID,

        CategoryName,

        MAX(CASE

            WHEN TrafficSource = ‘Email’

            THEN CategoryReachPercent

        END) AS EmailReachPercent,

        MAX(CASE

            WHEN TrafficSource = ‘Organic’

            THEN CategoryReachPercent

        END) AS OrganicReachPercent

    FROM CategoryRates

    GROUP BY

        CategoryID,

        CategoryName

)

SELECT

    CategoryID,

    CategoryName,

    CAST(EmailReachPercent AS DECIMAL(6,2))

        AS EmailReachPercent,

    CAST(OrganicReachPercent AS DECIMAL(6,2))

        AS OrganicReachPercent,

    CAST(

        EmailReachPercent – OrganicReachPercent

        AS DECIMAL(6,2)

    ) AS DifferencePP

FROM Comparison

ORDER BY

    DifferencePP DESC;

From the visible portion of the output, an important pattern has emerged: unlike the first three Categories, which showed only small differences, some Categories are substantially more represented in Email than in Organic. The largest visible positive differences are Furniture +10.14pp, Gaming +8.50pp, Menswear +7.90pp, Womenswear +6.23pp, Laptops +6.20pp, Nonfiction +5.98pp, and Fitness +5.87pp.

However, we still cannot conclude that these differences explain the lower Cart Progression Rate for Email. The key question is:

Do the Categories that are more heavily represented in Email than in Organic have lower Cart Progression Rates themselves?

2.3.6.3.3 — Cart Progression Rate by Category.

USE ShopSense;

GO

— 2.3.6.3.3

— Cart Progression Rate by Category

— High Engagement + No Purchase only

— Email + Organic

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

TargetSessions AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE

        sa.SearchCount >= 4

        AND s.TrafficSource IN (‘Email’, ‘Organic’)

        AND NOT EXISTS

        (

            SELECT 1

            FROM dbo.Orders o

            WHERE o.SessionID = s.SessionID

        )

),

SessionCategories AS

(

    SELECT DISTINCT

        ts.SessionID,

        c.CategoryID,

        c.CategoryName

    FROM TargetSessions ts

    INNER JOIN dbo.ProductViews pv

        ON pv.SessionID = ts.SessionID

    INNER JOIN dbo.Products p

        ON p.ProductID = pv.ProductID

    INNER JOIN dbo.Categories c

        ON c.CategoryID = p.CategoryID

),

CartSessions AS

(

    SELECT DISTINCT

        SessionID

    FROM dbo.CartEvents

    WHERE EventType = ‘Add’

)

SELECT

    sc.CategoryID,

    sc.CategoryName,

    COUNT(*) AS SessionsViewingCategory,

    SUM(

        CASE

            WHEN cs.SessionID IS NOT NULL THEN 1

            ELSE 0

        END

    ) AS ReachedCartSessions,

    COUNT(*) –

    SUM(

        CASE

            WHEN cs.SessionID IS NOT NULL THEN 1

            ELSE 0

        END

    ) AS NoCartSessions,

    CAST(

        100.0 *

        SUM(

            CASE

                WHEN cs.SessionID IS NOT NULL THEN 1

                ELSE 0

            END

        )

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS CartProgressionRate

FROM SessionCategories sc

LEFT JOIN CartSessions cs

    ON sc.SessionID = cs.SessionID

GROUP BY

    sc.CategoryID,

    sc.CategoryName

ORDER BY

    CartProgressionRate ASC;

The overall difference between Email and Organic is much larger — Email = 8.20% versus Organic = 20.45%. The fact that Email users are somewhat more concentrated in lower-performing Categories does not necessarily explain the full 12.26 percentage-point gap in Cart Progression.

2.3.6.3.4 — Email vs Organic Cart Progression within the same Category

USE ShopSense;

GO

— 2.3.6.3.4

— Cart Progression by Category × Traffic Source

— High Engagement + No Purchase only

— Email vs Organic

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

TargetSessions AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE

        sa.SearchCount >= 4

        AND s.TrafficSource IN (‘Email’, ‘Organic’)

        AND NOT EXISTS

        (

            SELECT 1

            FROM dbo.Orders o

            WHERE o.SessionID = s.SessionID

        )

),

SessionCategories AS

(

    SELECT DISTINCT

        ts.SessionID,

        ts.TrafficSource,

        c.CategoryID,

        c.CategoryName

    FROM TargetSessions ts

    INNER JOIN dbo.ProductViews pv

        ON pv.SessionID = ts.SessionID

    INNER JOIN dbo.Products p

        ON p.ProductID = pv.ProductID

    INNER JOIN dbo.Categories c

        ON c.CategoryID = p.CategoryID

),

CartSessions AS

(

    SELECT DISTINCT

        SessionID

    FROM dbo.CartEvents

    WHERE EventType = ‘Add’

),

CategoryRates AS

(

    SELECT

        sc.CategoryID,

        sc.CategoryName,

        sc.TrafficSource,

        COUNT(*) AS SessionsViewingCategory,

        SUM(

            CASE

                WHEN cs.SessionID IS NOT NULL THEN 1

                ELSE 0

            END

        ) AS ReachedCartSessions,

        CAST(

            100.0 *

            SUM(

                CASE

                    WHEN cs.SessionID IS NOT NULL THEN 1

                    ELSE 0

                END

            )

            / NULLIF(COUNT(*), 0)

            AS DECIMAL(6,2)

        ) AS CartProgressionRate

    FROM SessionCategories sc

    LEFT JOIN CartSessions cs

        ON sc.SessionID = cs.SessionID

    GROUP BY

        sc.CategoryID,

        sc.CategoryName,

        sc.TrafficSource

)

SELECT

    CategoryID,

    CategoryName,

    MAX(CASE

        WHEN TrafficSource = ‘Email’

        THEN SessionsViewingCategory

    END) AS EmailSessions,

    MAX(CASE

        WHEN TrafficSource = ‘Organic’

        THEN SessionsViewingCategory

    END) AS OrganicSessions,

    MAX(CASE

        WHEN TrafficSource = ‘Email’

        THEN CartProgressionRate

    END) AS EmailCartProgression,

    MAX(CASE

        WHEN TrafficSource = ‘Organic’

        THEN CartProgressionRate

    END) AS OrganicCartProgression,

    CAST(

        MAX(CASE

            WHEN TrafficSource = ‘Email’

            THEN CartProgressionRate

        END)

        –

        MAX(CASE

            WHEN TrafficSource = ‘Organic’

            THEN CartProgressionRate

        END)

        AS DECIMAL(6,2)

    ) AS DifferencePP

FROM CategoryRates

GROUP BY

    CategoryID,

    CategoryName

ORDER BY

    DifferencePP ASC;

Category Mix does not appear to be the primary driver of Email’s lower Cart Progression. Although Email traffic is more concentrated in several categories with relatively weaker cart progression, the Email–Organic gap persists within the same product categories. Across all 19 categories, Email sessions show lower Cart Progression than Organic sessions. This indicates that the overall 12.26 percentage-point gap is not explained simply by differences in the categories users browse. The evidence points toward a broader Email-specific post-discovery friction or traffic-quality effect.

Device Mix → Does not appear to be the primary explanation

Search/Product Discovery Engagement → Email users are not less engaged

Category Mix → Does not explain the observed difference

2.3.6.4 —Funnel Drop-off Diagnosis

Where Does Email Actually Drop Off?

So far, we have established that the difference between Email and Organic cannot be explained by Device Mix, Search/Product Discovery Engagement, or Category Mix. Therefore, the next step is to determine exactly where in the user journey Email begins to diverge from Organic.

2.3.6.4.1 — Product View → Cart

Among highly engaged non-purchasing users who actually viewed products, are Email users less likely than Organic users to add a product to cart?

USE ShopSense;

GO

— 2.3.6.4.1

— Product View -> Cart Progression

— Email vs Organic

— High Engagement + No Purchase only

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

ProductViewSessions AS

(

    SELECT DISTINCT

        h.SessionID,

        h.TrafficSource

    FROM HighEngagementNoPurchase h

    INNER JOIN dbo.ProductViews pv

        ON h.SessionID = pv.SessionID

),

CartSessions AS

(

    SELECT DISTINCT

        pvs.SessionID,

        pvs.TrafficSource

    FROM ProductViewSessions pvs

    INNER JOIN dbo.CartEvents ce

        ON pvs.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Add’

)

SELECT

    pvs.TrafficSource,

    COUNT(*) AS ProductViewSessions,

    COUNT(cs.SessionID) AS ReachedCartSessions,

    COUNT(*) – COUNT(cs.SessionID) AS DroppedBeforeCart,

    CAST(

        100.0 * COUNT(cs.SessionID)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS ProductViewToCartRate

FROM ProductViewSessions pvs

LEFT JOIN CartSessions cs

    ON pvs.SessionID = cs.SessionID

   AND pvs.TrafficSource = cs.TrafficSource

GROUP BY

    pvs.TrafficSource

ORDER BY

    pvs.TrafficSource;

The strongest divergence appears at the Product View → Cart transition. Among high-engagement, non-purchasing sessions that reached a product page, only 8.20% of Email sessions progressed to cart, compared with 20.45% of Organic sessions—a 12.25 percentage-point gap. Since Email users showed comparable or slightly higher search, click, and product-view activity earlier in the journey, the evidence suggests that the primary friction emerges after product discovery, when users must translate browsing engagement into purchase intent.

2.3.6.4.2 — Cart → Checkout Started

Among users who actually Added to Cart, does Email still show a higher drop-off rate than Organic?

USE ShopSense;

GO

— 2.3.6.4.2

— Cart -> Checkout Started

— Email vs Organic

— High Engagement + No Purchase only

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

CartSessions AS

(

    SELECT DISTINCT

        h.SessionID,

        h.TrafficSource

    FROM HighEngagementNoPurchase h

    INNER JOIN dbo.CartEvents ce

        ON h.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Add’

),

CheckoutStartedSessions AS

(

    SELECT DISTINCT

        cs.SessionID,

        cs.TrafficSource

    FROM CartSessions cs

    INNER JOIN dbo.CheckoutEvents che

        ON cs.SessionID = che.SessionID

    WHERE che.EventType = ‘Started’

)

SELECT

    cs.TrafficSource,

    COUNT(*) AS CartSessions,

    COUNT(chs.SessionID) AS CheckoutStartedSessions,

    COUNT(*) – COUNT(chs.SessionID)

        AS DroppedBeforeCheckout,

    CAST(

        100.0 * COUNT(chs.SessionID)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS CartToCheckoutRate

FROM CartSessions cs

LEFT JOIN CheckoutStartedSessions chs

    ON cs.SessionID = chs.SessionID

   AND cs.TrafficSource = chs.TrafficSource

GROUP BY

    cs.TrafficSource

ORDER BY

    cs.TrafficSource;

The main Email friction appears before the cart, rather than after it. Email users are highly engaged with search and product discovery, but only 8.20% progress from Product View to Cart compared with 20.45% of Organic users. Among the small subset that does reach the cart, Email does not show an additional deterioration in progression to checkout (60.00% vs. 38.10%). Because only five Email sessions reached the cart, the post-cart comparison should be treated as descriptive rather than conclusive.

2.3.6.4.3 — Checkout Started → Payment

USE ShopSense;

GO

— 2.3.6.4.3

— Checkout Started -> Payment

— Email vs Organic

— High Engagement + No Purchase only

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementNoPurchase AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

      AND NOT EXISTS

      (

          SELECT 1

          FROM dbo.Orders o

          WHERE o.SessionID = s.SessionID

      )

),

CheckoutStartedSessions AS

(

    SELECT DISTINCT

        h.SessionID,

        h.TrafficSource

    FROM HighEngagementNoPurchase h

    INNER JOIN dbo.CheckoutEvents ce

        ON h.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Started’

),

PaymentSessions AS

(

    SELECT DISTINCT

        cs.SessionID,

        cs.TrafficSource

    FROM CheckoutStartedSessions cs

    INNER JOIN dbo.CheckoutEvents ce

        ON cs.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Payment’

)

SELECT

    cs.TrafficSource,

    COUNT(*) AS CheckoutStartedSessions,

    COUNT(ps.SessionID) AS PaymentSessions,

    COUNT(*) – COUNT(ps.SessionID)

        AS DroppedBeforePayment,

    CAST(

        100.0 * COUNT(ps.SessionID)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS CheckoutToPaymentRate

FROM CheckoutStartedSessions cs

LEFT JOIN PaymentSessions ps

    ON cs.SessionID = ps.SessionID

   AND cs.TrafficSource = ps.TrafficSource

GROUP BY

    cs.TrafficSource

ORDER BY

    cs.TrafficSource;

At first glance, this output suggests that Email also experiences a drop-off at the Checkout → Payment stage. However, Email has only 3 observations at this stage. Therefore, we cannot infer from 0/3 that there is a general and statistically established Payment problem for Email. In the report, it is more appropriate to describe this as a secondary signal requiring more data.

At this point, we have identified two areas: stronger evidence of a gap at Product View → Cart (8.20% vs. 20.45%), and a secondary signal at Checkout → Payment (0% vs. 29.17%), which remains highly uncertain due to the very small Email sample size (n = 3).

2.3.6.4.4 — Payment → Completed

USE ShopSense;

GO

— 2.3.6.4.4

— Payment -> Completed

— Email vs Organic

— ALL High-Engagement Sessions

— IMPORTANT: No Purchase filter removed

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

HighEngagementSessions AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

PaymentSessions AS

(

    SELECT DISTINCT

        h.SessionID,

        h.TrafficSource

    FROM HighEngagementSessions h

    INNER JOIN dbo.CheckoutEvents ce

        ON h.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Payment’

),

CompletedSessions AS

(

    SELECT DISTINCT

        ps.SessionID,

        ps.TrafficSource

    FROM PaymentSessions ps

    INNER JOIN dbo.CheckoutEvents ce

        ON ps.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Completed’

)

SELECT

    ps.TrafficSource,

    COUNT(*) AS PaymentSessions,

    COUNT(cs.SessionID) AS CompletedSessions,

    COUNT(*) – COUNT(cs.SessionID)

        AS DroppedAfterPayment,

    CAST(

        100.0 * COUNT(cs.SessionID)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS PaymentToCompletedRate

FROM PaymentSessions ps

LEFT JOIN CompletedSessions cs

    ON ps.SessionID = cs.SessionID

   AND ps.TrafficSource = cs.TrafficSource

GROUP BY

    ps.TrafficSource

ORDER BY

    ps.TrafficSource;

Once Email users actually reach the Payment stage, there is no evidence of further Journey friction: all 9 Sessions progressed to Completed. Therefore, the current evidence points more strongly to a problem higher in the Funnel, particularly at the Product View → Cart stage, rather than at the final Payment stage.

It is also important not to interpret this result as contradictory to the earlier 0/3 finding. Those 3 observations belonged specifically to the High Engagement + No Purchase group, whereas this analysis examines the entire High-Engagement cohort.

2.3.6.4.5 — Full Funnel Comparison

USE ShopSense;

GO

— 2.3.6.4.5

— Full Funnel Comparison

— Email vs Organic

— ALL High-Engagement Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionStages AS

(

    SELECT

        c.SessionID,

        c.TrafficSource,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.ProductViews pv

            WHERE pv.SessionID = c.SessionID

        ) THEN 1 ELSE 0 END AS ReachedProductView,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.CartEvents ca

            WHERE ca.SessionID = c.SessionID

              AND ca.EventType = ‘Add’

        ) THEN 1 ELSE 0 END AS ReachedCart,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.CheckoutEvents ce

            WHERE ce.SessionID = c.SessionID

              AND ce.EventType = ‘Started’

        ) THEN 1 ELSE 0 END AS ReachedCheckout,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.CheckoutEvents ce

            WHERE ce.SessionID = c.SessionID

              AND ce.EventType = ‘Payment’

        ) THEN 1 ELSE 0 END AS ReachedPayment,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.CheckoutEvents ce

            WHERE ce.SessionID = c.SessionID

              AND ce.EventType = ‘Completed’

        ) THEN 1 ELSE 0 END AS ReachedCompleted

    FROM Cohort c

),

FunnelCounts AS

(

    SELECT

        TrafficSource,

        COUNT(*) AS HighEngagementSessions,

        SUM(ReachedProductView) AS ProductViewSessions,

        SUM(ReachedCart) AS CartSessions,

        SUM(ReachedCheckout) AS CheckoutSessions,

        SUM(ReachedPayment) AS PaymentSessions,

        SUM(ReachedCompleted) AS CompletedSessions

    FROM SessionStages

    GROUP BY TrafficSource

)

SELECT

    TrafficSource,

    HighEngagementSessions,

    ProductViewSessions,

    CartSessions,

    CheckoutSessions,

    PaymentSessions,

    CompletedSessions,

    CAST(

        100.0 * CartSessions /

        NULLIF(ProductViewSessions, 0)

        AS DECIMAL(6,2)

    ) AS ProductViewToCartRate,

    CAST(

        100.0 * CheckoutSessions /

        NULLIF(CartSessions, 0)

        AS DECIMAL(6,2)

    ) AS CartToCheckoutRate,

    CAST(

        100.0 * PaymentSessions /

        NULLIF(CheckoutSessions, 0)

        AS DECIMAL(6,2)

    ) AS CheckoutToPaymentRate,

    CAST(

        100.0 * CompletedSessions /

        NULLIF(PaymentSessions, 0)

        AS DECIMAL(6,2)

    ) AS PaymentToCompletedRate,

    CAST(

        100.0 * CompletedSessions /

        NULLIF(ProductViewSessions, 0)

        AS DECIMAL(6,2)

    ) AS ProductViewToCompletedRate

FROM FunnelCounts

ORDER BY TrafficSource;

High-engagement Email sessions show their clearest relative friction at the Product View → Cart stage. Once Email users enter the cart, their downstream progression is comparable to or stronger than Organic users in this dataset. This suggests that the primary issue is concentrated earlier in the purchase journey rather than in checkout completion.

2.3.6.5 — Root Cause Validation / Final Diagnosis

So far, we know that the most important Email gap occurs at the Product View → Cart stage:

Email: 20.00% → Organic: 32.13%

Our previous statistical test also provided significant evidence of a difference between the two groups. In Step 2.3.6.5, we now need to investigate what might explain this drop-off by testing the remaining hypotheses one by one.

2.3.6.5.1 — Product-Level Analysis

Let’s examine whether Email users are more likely to view products that inherently have lower Add-to-Cart Rates.

Do Email users disproportionately view products that naturally have lower Add-to-Cart performance?

2.3.6.5.1.1 — Product-Level Add-to-Cart Performance

USE ShopSense;

GO

— 2.3.6.5.1.1

— Product-Level Add-to-Cart Performance

— All High-Engagement Email + Organic Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

SessionProductsAdded AS

(

    SELECT DISTINCT

        c.SessionID,

        ce.ProductID

    FROM Cohort c

    INNER JOIN dbo.CartEvents ce

        ON c.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Add’

),

ProductPerformance AS

(

    SELECT

        spv.ProductID,

        COUNT(*) AS ViewingSessions,

        SUM(

            CASE

                WHEN spa.ProductID IS NOT NULL THEN 1

                ELSE 0

            END

        ) AS AddToCartSessions

    FROM SessionProductsViewed spv

    LEFT JOIN SessionProductsAdded spa

        ON spv.SessionID = spa.SessionID

       AND spv.ProductID = spa.ProductID

    GROUP BY spv.ProductID

)

SELECT

    pp.ProductID,

    p.ProductName,

    pp.ViewingSessions,

    pp.AddToCartSessions,

    CAST(

        100.0 * pp.AddToCartSessions

        / NULLIF(pp.ViewingSessions, 0)

        AS DECIMAL(6,2)

    ) AS ProductAddToCartRate

FROM ProductPerformance pp

INNER JOIN dbo.Products p

    ON pp.ProductID = p.ProductID

ORDER BY

    ProductAddToCartRate ASC,

    ViewingSessions DESC;

At the top of the output, several products have a Product Add-to-Cart Rate of 0%. For example, Corewave Furniture 0259, Vanta Smart Home 0440, and Prism Audio 0853 were each viewed in 11 Sessions, yet none resulted in an Add-to-Cart event.

However, we still cannot conclude that these products are responsible for Email’s weaker performance. This output only demonstrates that product-level conversion performance is heterogeneous. The key question is whether Email users are disproportionately exposed to these lower-converting products compared with Organic users.

2.3.6.5.1.2 — Exposure to Low-ATC Products: Email vs Organic

USE ShopSense;

GO

— 2.3.6.5.1.2

— Product Performance Exposure by Traffic Source

— Are Email users disproportionately viewing low-ATC products?

— ALL High-Engagement Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

SessionProductsAdded AS

(

    SELECT DISTINCT

        c.SessionID,

        ce.ProductID

    FROM Cohort c

    INNER JOIN dbo.CartEvents ce

        ON c.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Add’

),

ProductPerformance AS

(

    SELECT

        spv.ProductID,

        COUNT(*) AS ViewingSessions,

        SUM(

            CASE

                WHEN spa.ProductID IS NOT NULL THEN 1

                ELSE 0

            END

        ) AS AddToCartSessions,

        100.0 *

        SUM(

            CASE

                WHEN spa.ProductID IS NOT NULL THEN 1

                ELSE 0

            END

        )

        / NULLIF(COUNT(*), 0) AS ProductAddToCartRate

    FROM SessionProductsViewed spv

    LEFT JOIN SessionProductsAdded spa

        ON spv.SessionID = spa.SessionID

       AND spv.ProductID = spa.ProductID

    GROUP BY spv.ProductID

),

ProductQuartiles AS

(

    SELECT

        ProductID,

        ProductAddToCartRate,

        NTILE(4) OVER

        (

            ORDER BY ProductAddToCartRate

        ) AS PerformanceQuartile

    FROM ProductPerformance

),

Exposure AS

(

    SELECT

        spv.TrafficSource,

        pq.PerformanceQuartile,

        COUNT(*) AS ProductExposureSessions

    FROM SessionProductsViewed spv

    INNER JOIN ProductQuartiles pq

        ON spv.ProductID = pq.ProductID

    GROUP BY

        spv.TrafficSource,

        pq.PerformanceQuartile

),

TrafficTotals AS

(

    SELECT

        TrafficSource,

        SUM(ProductExposureSessions) AS TotalProductExposureSessions

    FROM Exposure

    GROUP BY TrafficSource

)

SELECT

    e.TrafficSource,

    CASE e.PerformanceQuartile

        WHEN 1 THEN ‘Q1 – Lowest ATC’

        WHEN 2 THEN ‘Q2 – Low-Mid ATC’

        WHEN 3 THEN ‘Q3 – High-Mid ATC’

        WHEN 4 THEN ‘Q4 – Highest ATC’

    END AS ProductPerformanceGroup,

    e.ProductExposureSessions,

    CAST(

        100.0 * e.ProductExposureSessions

        / NULLIF(t.TotalProductExposureSessions, 0)

        AS DECIMAL(6,2)

    ) AS ExposureSharePercent

FROM Exposure e

INNER JOIN TrafficTotals t

    ON e.TrafficSource = t.TrafficSource

ORDER BY

    e.PerformanceQuartile,

    e.TrafficSource;

Product-mix differences do not appear to be the primary explanation for Email’s lower Product View → Cart progression. Email and Organic users were exposed to very similar distributions of product performance. Exposure to the lowest-ATC quartile was nearly identical (24.03% vs. 23.93%), while exposure to the lower-performing half of products differed by only about 2 percentage points. This suggests that Email’s 12.13 percentage-point Product View → Cart gap is unlikely to be driven primarily by greater exposure to inherently low-converting products.

2.3.6.5.1.3 — Same-Product Comparison

When Email and Organic users view the same products, do Email users still add them to cart at a lower rate?

USE ShopSense;

GO

— 2.3.6.5.1.3

— Same-Product Add-to-Cart Comparison

— Email vs Organic

— ALL High-Engagement Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

SessionProductsAdded AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        ce.ProductID

    FROM Cohort c

    INNER JOIN dbo.CartEvents ce

        ON c.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Add’

),

ProductSourcePerformance AS

(

    SELECT

        spv.ProductID,

        spv.TrafficSource,

        COUNT(*) AS ViewingSessions,

        SUM(

            CASE

                WHEN spa.ProductID IS NOT NULL THEN 1

                ELSE 0

            END

        ) AS AddToCartSessions

    FROM SessionProductsViewed spv

    LEFT JOIN SessionProductsAdded spa

        ON spv.SessionID = spa.SessionID

       AND spv.ProductID = spa.ProductID

       AND spv.TrafficSource = spa.TrafficSource

    GROUP BY

        spv.ProductID,

        spv.TrafficSource

),

ProductComparison AS

(

    SELECT

        ProductID,

        MAX(CASE WHEN TrafficSource = ‘Email’

            THEN ViewingSessions END) AS EmailViewingSessions,

        MAX(CASE WHEN TrafficSource = ‘Email’

            THEN AddToCartSessions END) AS EmailAddToCartSessions,

        MAX(CASE WHEN TrafficSource = ‘Organic’

            THEN ViewingSessions END) AS OrganicViewingSessions,

        MAX(CASE WHEN TrafficSource = ‘Organic’

            THEN AddToCartSessions END) AS OrganicAddToCartSessions

    FROM ProductSourcePerformance

    GROUP BY ProductID

),

EligibleProducts AS

(

    SELECT *

    FROM ProductComparison

    WHERE EmailViewingSessions >= 5

      AND OrganicViewingSessions >= 5

)

SELECT

    COUNT(*) AS ComparableProducts,

    SUM(

        CASE

            WHEN

                1.0 * EmailAddToCartSessions

                    / NULLIF(EmailViewingSessions, 0)

                <

                1.0 * OrganicAddToCartSessions

                    / NULLIF(OrganicViewingSessions, 0)

            THEN 1 ELSE 0

        END

    ) AS ProductsWhereEmailLower,

    SUM(

        CASE

            WHEN

                1.0 * EmailAddToCartSessions

                    / NULLIF(EmailViewingSessions, 0)

                >

                1.0 * OrganicAddToCartSessions

                    / NULLIF(OrganicViewingSessions, 0)

            THEN 1 ELSE 0

        END

    ) AS ProductsWhereEmailHigher,

    SUM(

        CASE

            WHEN

                1.0 * EmailAddToCartSessions

                    / NULLIF(EmailViewingSessions, 0)

                =

                1.0 * OrganicAddToCartSessions

                    / NULLIF(OrganicViewingSessions, 0)

            THEN 1 ELSE 0

        END

    ) AS ProductsWithEqualRate

FROM EligibleProducts;

This output is very important because it shows that the previous threshold was too restrictive for our dataset.

2.3.6.5.1.3 — Interpretation

The output shows:

ComparableProducts = 0

This means that there are no products with at least 5 Email Viewing Sessions and 5 Organic Viewing Sessions simultaneously.

This does not mean that there are no shared products between Email and Organic. Rather, because the Email cohort is much smaller only 70 High-Engagement Email Sessions compared with 361 Organic Sessions the data becomes highly sparse at the Product level, and the >= 5 threshold eliminates all products from the comparison.

Therefore, we should not conclude from this query that a Same-Product comparison is impossible. First, we need to determine how much actual Product overlap exists between Email and Organic.

2.3.6.5.1.3A — Product Overlap Diagnostic

USE ShopSense;

GO

— 2.3.6.5.1.3A

— Product Overlap Diagnostic

— Email vs Organic

— ALL High-Engagement Sessions

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

ProductExposure AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

ProductCounts AS

(

    SELECT

        ProductID,

        COUNT(DISTINCT CASE

            WHEN TrafficSource = ‘Email’

            THEN SessionID

        END) AS EmailViewingSessions,

        COUNT(DISTINCT CASE

            WHEN TrafficSource = ‘Organic’

            THEN SessionID

        END) AS OrganicViewingSessions

    FROM ProductExposure

    GROUP BY ProductID

)

SELECT

    COUNT(*) AS TotalViewedProducts,

    SUM(CASE

        WHEN EmailViewingSessions > 0

         AND OrganicViewingSessions > 0

        THEN 1 ELSE 0

    END) AS SharedProducts,

    SUM(CASE

        WHEN EmailViewingSessions >= 2

         AND OrganicViewingSessions >= 2

        THEN 1 ELSE 0

    END) AS SharedProducts_Min2,

    SUM(CASE

        WHEN EmailViewingSessions >= 3

         AND OrganicViewingSessions >= 3

        THEN 1 ELSE 0

    END) AS SharedProducts_Min3,

    SUM(CASE

        WHEN EmailViewingSessions >= 5

         AND OrganicViewingSessions >= 5

        THEN 1 ELSE 0

    END) AS SharedProducts_Min5,

    MAX(EmailViewingSessions) AS MaxEmailViewsPerProduct,

    MAX(OrganicViewingSessions) AS MaxOrganicViewsPerProduct

FROM ProductCounts;

Product exposure distributions were highly similar between Email and Organic traffic, providing little evidence that Email’s lower Product View → Cart progression was primarily driven by exposure to lower-performing products. A direct same-product comparison using a minimum of five viewing sessions per traffic source was not feasible because product-level observations were too sparse.

Out of 968 viewed products, 396 products were viewed at least once by both the Email and Organic groups. This confirms that there is meaningful Product overlap between the two groups. The issue with the previous query was therefore not a lack of overlap, but the limited number of observations at the individual Product level.

With a threshold of 3, only 15 products remain, which is too limited for broad conclusions. However, with a threshold of 2, we retain 90 products. This provides a useful basis for an exploratory directional analysis, provided that individual Product-level rates are not overinterpreted due to the small sample sizes.

2.3.6.5.1.3B — Same-Product Comparison with Min 2 Sessions

USE ShopSense;

GO

— 2.3.6.5.1.3B

— Same-Product Add-to-Cart Comparison

— Minimum 2 Viewing Sessions per Traffic Source

— ALL High-Engagement Sessions

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

SessionProductsAdded AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        ce.ProductID

    FROM Cohort c

    INNER JOIN dbo.CartEvents ce

        ON c.SessionID = ce.SessionID

    WHERE ce.EventType = ‘Add’

),

ProductSourcePerformance AS

(

    SELECT

        spv.ProductID,

        spv.TrafficSource,

        COUNT(*) AS ViewingSessions,

        SUM(

            CASE

                WHEN spa.ProductID IS NOT NULL THEN 1

                ELSE 0

            END

        ) AS AddToCartSessions

    FROM SessionProductsViewed spv

    LEFT JOIN SessionProductsAdded spa

        ON spv.SessionID = spa.SessionID

       AND spv.ProductID = spa.ProductID

       AND spv.TrafficSource = spa.TrafficSource

    GROUP BY

        spv.ProductID,

        spv.TrafficSource

),

ProductComparison AS

(

    SELECT

        ProductID,

        MAX(CASE WHEN TrafficSource = ‘Email’

            THEN ViewingSessions END) AS EmailViewingSessions,

        MAX(CASE WHEN TrafficSource = ‘Email’

            THEN AddToCartSessions END) AS EmailAddToCartSessions,

        MAX(CASE WHEN TrafficSource = ‘Organic’

            THEN ViewingSessions END) AS OrganicViewingSessions,

        MAX(CASE WHEN TrafficSource = ‘Organic’

            THEN AddToCartSessions END) AS OrganicAddToCartSessions

    FROM ProductSourcePerformance

    GROUP BY ProductID

),

EligibleProducts AS

(

    SELECT *

    FROM ProductComparison

    WHERE EmailViewingSessions >= 2

      AND OrganicViewingSessions >= 2

)

SELECT

    COUNT(*) AS ComparableProducts,

    SUM(CASE

        WHEN

            1.0 * EmailAddToCartSessions /

                NULLIF(EmailViewingSessions, 0)

            <

            1.0 * OrganicAddToCartSessions /

                NULLIF(OrganicViewingSessions, 0)

        THEN 1 ELSE 0

    END) AS ProductsWhereEmailLower,

    SUM(CASE

        WHEN

            1.0 * EmailAddToCartSessions /

                NULLIF(EmailViewingSessions, 0)

            >

            1.0 * OrganicAddToCartSessions /

                NULLIF(OrganicViewingSessions, 0)

        THEN 1 ELSE 0

    END) AS ProductsWhereEmailHigher,

    SUM(CASE

        WHEN

            1.0 * EmailAddToCartSessions /

                NULLIF(EmailViewingSessions, 0)

            =

            1.0 * OrganicAddToCartSessions /

                NULLIF(OrganicViewingSessions, 0)

        THEN 1 ELSE 0

    END) AS ProductsWithEqualRate

FROM EligibleProducts;

Product mix does not appear to be the primary driver of Email’s lower Product View → Cart progression. Email and Organic users were exposed to very similar distributions of low- and high-performing products, with exposure to the lowest-ATC quartile nearly identical (24.03% vs. 23.93%). Although 396 products were viewed by both traffic sources, product-level observations were too sparse for a reliable same-product conversion comparison. Overall, the available evidence provides little support for product selection or product mix as the main explanation for the Email conversion gap.

2.3.6.5.2 — Price & Discount Analysis

Are high-engagement Email users viewing more expensive products or receiving less attractive discounts than Organic users?

2.3.6.5.2.1 — Average Price & Discount Exposure

USE ShopSense;

GO

— 2.3.6.5.2.1

— Price & Discount Exposure

— Email vs Organic

— ALL High-Engagement Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

ProductExposure AS

(

    SELECT

        spv.SessionID,

        spv.TrafficSource,

        spv.ProductID,

        p.ListPrice,

        p.DiscountPercent,

        p.ListPrice *

        (1 – p.DiscountPercent / 100.0) AS EffectivePrice

    FROM SessionProductsViewed spv

    INNER JOIN dbo.Products p

        ON spv.ProductID = p.ProductID

)

SELECT

    TrafficSource,

    COUNT(*) AS ProductExposureSessions,

    CAST(

        AVG(ListPrice)

        AS DECIMAL(10,2)

    ) AS AvgListPrice,

    CAST(

        AVG(DiscountPercent)

        AS DECIMAL(6,2)

    ) AS AvgDiscountPercent,

    CAST(

        AVG(EffectivePrice)

        AS DECIMAL(10,2)

    ) AS AvgEffectivePrice,

    CAST(

        MIN(EffectivePrice)

        AS DECIMAL(10,2)

    ) AS MinEffectivePrice,

    CAST(

        MAX(EffectivePrice)

        AS DECIMAL(10,2)

    ) AS MaxEffectivePrice

FROM ProductExposure

GROUP BY TrafficSource

ORDER BY TrafficSource;

Average price and discount exposure were nearly identical between high-engagement Email and Organic users. Email users viewed slightly lower-priced products on average ($185.48 vs. $188.91 list price), received almost identical discounts (9.33% vs. 9.42%), and had a slightly lower average effective product price ($168.28 vs. $170.94). These results provide little evidence that higher prices or weaker discounts are the primary drivers of Email’s lower Product View → Cart progression.

2.3.6.5.2.2 — Effective Price Distribution

USE ShopSense;

GO

— 2.3.6.5.2.2

— Effective Price Distribution

— Email vs Organic

— ALL High-Engagement Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

ProductExposure AS

(

    SELECT

        spv.SessionID,

        spv.TrafficSource,

        spv.ProductID,

        p.ListPrice *

        (1 – p.DiscountPercent / 100.0) AS EffectivePrice

    FROM SessionProductsViewed spv

    INNER JOIN dbo.Products p

        ON spv.ProductID = p.ProductID

),

PriceQuartiles AS

(

    SELECT

        *,

        NTILE(4) OVER

        (

            ORDER BY EffectivePrice

        ) AS PriceQuartile

    FROM ProductExposure

),

Distribution AS

(

    SELECT

        TrafficSource,

        PriceQuartile,

        COUNT(*) AS ProductExposureSessions

    FROM PriceQuartiles

    GROUP BY

        TrafficSource,

        PriceQuartile

),

TrafficTotals AS

(

    SELECT

        TrafficSource,

        SUM(ProductExposureSessions) AS TotalExposureSessions

    FROM Distribution

    GROUP BY TrafficSource

)

SELECT

    d.TrafficSource,

    CASE d.PriceQuartile

        WHEN 1 THEN ‘Q1 – Lowest Price’

        WHEN 2 THEN ‘Q2 – Low-Mid Price’

        WHEN 3 THEN ‘Q3 – High-Mid Price’

        WHEN 4 THEN ‘Q4 – Highest Price’

    END AS PriceGroup,

    d.ProductExposureSessions,

    CAST(

        100.0 * d.ProductExposureSessions

        / NULLIF(t.TotalExposureSessions, 0)

        AS DECIMAL(6,2)

    ) AS ExposureSharePercent

FROM Distribution d

INNER JOIN TrafficTotals t

    ON d.TrafficSource = t.TrafficSource

ORDER BY

    d.PriceQuartile,

    d.TrafficSource;

Price and discount differences do not appear to explain Email’s lower Product View → Cart progression. Average effective prices were slightly lower for Email ($168.28 vs. $170.94), average discounts were nearly identical (9.33% vs. 9.42%), and exposure across price quartiles was highly similar. Email users were not disproportionately exposed to the highest-priced products; in fact, their exposure to the highest-price quartile was slightly lower than Organic. Overall, the evidence provides little support for price or discount exposure as the primary source of the Email conversion gap.

2.3.6.5.3 — Product Quality Signals

Are Email users being exposed to products with weaker ratings or fewer reviews, potentially reducing confidence before Add-to-Cart?

2.3.6.5.3.1 — Rating & Review Exposure

USE ShopSense;

GO

— 2.3.6.5.3.1

— Product Quality Signals

— Rating & Review Exposure

— Email vs Organic

— ALL High-Engagement Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

QualityExposure AS

(

    SELECT

        spv.SessionID,

        spv.TrafficSource,

        spv.ProductID,

        p.Rating,

        p.ReviewCount

    FROM SessionProductsViewed spv

    INNER JOIN dbo.Products p

        ON spv.ProductID = p.ProductID

)

SELECT

    TrafficSource,

    COUNT(*) AS ProductExposureSessions,

    CAST(

        AVG(CAST(Rating AS DECIMAL(10,4)))

        AS DECIMAL(6,2)

    ) AS AvgRating,

    CAST(

        AVG(CAST(ReviewCount AS DECIMAL(18,2)))

        AS DECIMAL(12,2)

    ) AS AvgReviewCount,

    MIN(Rating) AS MinRating,

    MAX(Rating) AS MaxRating,

    MIN(ReviewCount) AS MinReviewCount,

    MAX(ReviewCount) AS MaxReviewCount

FROM QualityExposure

GROUP BY TrafficSource

ORDER BY TrafficSource;

Product quality signals were highly similar between Email and Organic traffic. Email users viewed products with an average rating of 3.83 compared with 3.87 for Organic, while average review counts were 1,181.19 and 1,231.95 respectively. These relatively small differences provide little evidence that weaker product ratings or social proof are the primary drivers of Email’s lower Product View → Cart progression.

2.3.6.5.3.2 — Rating Distribution

USE ShopSense;

GO

— 2.3.6.5.3.2

— Product Rating Distribution

— Email vs Organic

— ALL High-Engagement Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

QualityExposure AS

(

    SELECT

        spv.SessionID,

        spv.TrafficSource,

        spv.ProductID,

        p.Rating

    FROM SessionProductsViewed spv

    INNER JOIN dbo.Products p

        ON spv.ProductID = p.ProductID

),

RatingQuartiles AS

(

    SELECT

        *,

        NTILE(4) OVER

        (

            ORDER BY Rating

        ) AS RatingQuartile

    FROM QualityExposure

),

Distribution AS

(

    SELECT

        TrafficSource,

        RatingQuartile,

        COUNT(*) AS ProductExposureSessions

    FROM RatingQuartiles

    GROUP BY

        TrafficSource,

        RatingQuartile

),

TrafficTotals AS

(

    SELECT

        TrafficSource,

        SUM(ProductExposureSessions) AS TotalExposureSessions

    FROM Distribution

    GROUP BY TrafficSource

)

SELECT

    d.TrafficSource,

    CASE d.RatingQuartile

        WHEN 1 THEN ‘Q1 – Lowest Rating’

        WHEN 2 THEN ‘Q2 – Low-Mid Rating’

        WHEN 3 THEN ‘Q3 – High-Mid Rating’

        WHEN 4 THEN ‘Q4 – Highest Rating’

    END AS RatingGroup,

    d.ProductExposureSessions,

    CAST(

        100.0 * d.ProductExposureSessions

        / NULLIF(t.TotalExposureSessions, 0)

        AS DECIMAL(6,2)

    ) AS ExposureSharePercent

FROM Distribution d

INNER JOIN TrafficTotals t

    ON d.TrafficSource = t.TrafficSource

ORDER BY

    d.RatingQuartile,

    d.TrafficSource;

Email users showed slightly greater exposure to lower-rated products, with 52.83% of Email product exposure falling in the lower half of the rating distribution compared with 49.44% for Organic (+3.39 pp). However, average ratings were also very similar (3.83 vs. 3.87). This suggests that product rating may represent a minor compositional difference, but the available evidence does not support it as the primary explanation for the substantially larger Email Product View → Cart gap.

2.3.6.5.3.3 — Review Count Distribution

USE ShopSense;

GO

— 2.3.6.5.3.3

— Review Count Distribution

— Email vs Organic

— ALL High-Engagement Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

QualityExposure AS

(

    SELECT

        spv.SessionID,

        spv.TrafficSource,

        spv.ProductID,

        p.ReviewCount

    FROM SessionProductsViewed spv

    INNER JOIN dbo.Products p

        ON spv.ProductID = p.ProductID

),

ReviewQuartiles AS

(

    SELECT

        *,

        NTILE(4) OVER

        (

            ORDER BY ReviewCount

        ) AS ReviewQuartile

    FROM QualityExposure

),

Distribution AS

(

    SELECT

        TrafficSource,

        ReviewQuartile,

        COUNT(*) AS ProductExposureSessions

    FROM ReviewQuartiles

    GROUP BY

        TrafficSource,

        ReviewQuartile

),

TrafficTotals AS

(

    SELECT

        TrafficSource,

        SUM(ProductExposureSessions) AS TotalExposureSessions

    FROM Distribution

    GROUP BY TrafficSource

)

SELECT

    d.TrafficSource,

    CASE d.ReviewQuartile

        WHEN 1 THEN ‘Q1 – Lowest Review Count’

        WHEN 2 THEN ‘Q2 – Low-Mid Review Count’

        WHEN 3 THEN ‘Q3 – High-Mid Review Count’

        WHEN 4 THEN ‘Q4 – Highest Review Count’

    END AS ReviewGroup,

    d.ProductExposureSessions,

    CAST(

        100.0 * d.ProductExposureSessions

        / NULLIF(t.TotalExposureSessions, 0)

        AS DECIMAL(6,2)

    ) AS ExposureSharePercent

FROM Distribution d

INNER JOIN TrafficTotals t

    ON d.TrafficSource = t.TrafficSource

ORDER BY

    d.ReviewQuartile,

    d.TrafficSource;

Product quality and social-proof differences appear modest. Email users had slightly greater exposure to lower-rated products and products with fewer reviews, but the differences were relatively small. The lower half of the review-count distribution represented 51.42% of Email exposure versus 49.72% for Organic, while average ratings were 3.83 vs. 3.87. These findings suggest that weaker product quality signals may be a minor contributing factor, but they do not appear sufficient to explain the substantially larger Email Product View → Cart gap.

2.3.6.5.4 — Stock / Availability Analysis

Are Email users viewing products with lower inventory availability, potentially limiting their ability or willingness to add products to cart?

2.3.6.5.4.1 — Stock Exposure: Email vs Organic

USE ShopSense;

GO

— 2.3.6.5.4.1

— Stock / Availability Exposure

— Email vs Organic

— ALL High-Engagement Sessions

— High Engagement = SearchCount >= 4

WITH SearchActivity AS

(

    SELECT

        SessionID,

        COUNT(*) AS SearchCount

    FROM dbo.Searches

    GROUP BY SessionID

),

Cohort AS

(

    SELECT

        s.SessionID,

        s.TrafficSource

    FROM dbo.Sessions s

    INNER JOIN SearchActivity sa

        ON s.SessionID = sa.SessionID

    WHERE sa.SearchCount >= 4

      AND s.TrafficSource IN (‘Email’, ‘Organic’)

),

SessionProductsViewed AS

(

    SELECT DISTINCT

        c.SessionID,

        c.TrafficSource,

        pv.ProductID

    FROM Cohort c

    INNER JOIN dbo.ProductViews pv

        ON c.SessionID = pv.SessionID

),

StockExposure AS

(

    SELECT

        spv.SessionID,

        spv.TrafficSource,

        spv.ProductID,

        p.StockQuantity

    FROM SessionProductsViewed spv

    INNER JOIN dbo.Products p

        ON spv.ProductID = p.ProductID

)

SELECT

    TrafficSource,

    COUNT(*) AS ProductExposureSessions,

    CAST(

        AVG(CAST(StockQuantity AS DECIMAL(18,2)))

        AS DECIMAL(12,2)

    ) AS AvgStockQuantity,

    MIN(StockQuantity) AS MinStockQuantity,

    MAX(StockQuantity) AS MaxStockQuantity,

    SUM(

        CASE WHEN StockQuantity = 0

        THEN 1 ELSE 0 END

    ) AS OutOfStockExposures,

    CAST(

        100.0 *

        SUM(CASE WHEN StockQuantity = 0 THEN 1 ELSE 0 END)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS OutOfStockExposurePercent,

    SUM(

        CASE WHEN StockQuantity BETWEEN 1 AND 10

        THEN 1 ELSE 0 END

    ) AS LowStockExposures,

    CAST(

        100.0 *

        SUM(CASE WHEN StockQuantity BETWEEN 1 AND 10 THEN 1 ELSE 0 END)

        / NULLIF(COUNT(*), 0)

        AS DECIMAL(6,2)

    ) AS LowStockExposurePercent

FROM StockExposure

GROUP BY TrafficSource

ORDER BY TrafficSource;

Inventory availability does not appear to explain Email’s lower Product View → Cart progression. Average stock levels were nearly identical for Email and Organic product exposure (149.24 vs. 148.73 units), while out-of-stock exposure was extremely rare in both groups. The available evidence therefore provides little support for stock availability as a primary source of the Email conversion gap.

2.3.6.5.5 — Root Cause Synthesis

| Hypothesis | Evidence | Assessment |

|—|—|—|

| Lower search engagement | Search clicks/views broadly similar | Not Supported |

| Device mix | Email gap observed across key devices | Not Supported as primary driver |

| Category mix | Differences exist, but Email underperforms within many categories | Not Supported as primary driver |

| Product mix | Lowest-ATC exposure 24.03% vs. 23.93% | Not Supported |

| Higher prices | Effective price $168.28 vs. $170.94 | Not Supported |

| Weaker discounts | 9.33% vs. 9.42% | Not Supported |

| Lower ratings | Small directional difference | Possible minor contributor |

| Fewer reviews | Small directional difference | Possible minor contributor |

| Stock availability | Avg stock 149.24 vs. 148.73; OOS extremely rare | Not Supported |

| Checkout/payment friction | Downstream funnel broadly comparable | Not Supported as primary driver |

| Product View → Cart friction | 20.00% vs. 32.13% | Strongest observed signal |

After testing multiple observable explanations—including search engagement, device, category mix, product mix, price, discounts, product quality signals, inventory availability, and downstream checkout behavior—the clearest unresolved difference remained at the Product View → Cart transition. High-engagement Email sessions converted from Product View to Cart at 20.00%, compared with 32.13% for Organic sessions. The available data therefore localizes the primary observed friction to the product-evaluation-to-cart stage, while the underlying causal mechanism cannot be identified from the current dataset alone.

2.3.6.5.6 — Final Business Diagnosis & Recommendations

The root-cause analysis identified the Product View → Cart transition as the clearest friction point for high-engagement Email users. Email sessions progressed from Product View to Cart at 20.00%, compared with 32.13% for Organic sessions, while downstream checkout behavior was broadly comparable once users entered the cart.

Alternative explanations—including search engagement, device mix, category mix, product mix, pricing, discounts, inventory availability, and downstream checkout behavior—did not provide sufficient evidence to explain the gap. Product rating and review exposure showed small directional differences but were not large enough to account for the observed funnel disparity.

The analysis therefore localizes the primary observed friction to the product-evaluation-to-cart stage. However, because the current dataset does not directly measure product-page UX, promotional-message consistency, CTA visibility, shipping communication, or other experience-level factors, the underlying causal mechanism cannot be determined from observational analysis alone.

The recommended next step is a controlled A/B experiment targeting high-engagement Email traffic, testing an enhanced product-page experience designed to improve purchase confidence and the transition from Product View to Add to Cart. The primary experiment metric should be Product View → Add-to-Cart Rate, supported by downstream conversion and revenue guardrails.

2.4 — A/B Testing

2.4.1 — Experiment Design

1. Experiment Objective

Determine whether an enhanced product-page experience can increase the Product View → Add-to-Cart rate among high-engagement Email users.

Can a clearer and more persuasive product-page experience help high-engagement Email users progress from product exploration to Add to Cart?

Traffic Source: Email

High Engagement: SearchCount >= 4

Reached Product View: Yes

Control vs. Treatment:

Control — Variant A

Current Product Page experience.

Treatment — Variant B

More prominent Add-to-Cart CTA

Clearer discount / promotional messaging

More visible delivery and return information

Stronger purchase-confidence signals

Hypotheses

Null Hypothesis (H₀):

The enhanced product-page experience does not increase the Product View → Add-to-Cart rate for high-engagement Email users.

H₀: pTreatment ≤ pControl

Alternative Hypothesis (H₁):

The enhanced product-page experience increases the Product View → Add-to-Cart rate for high-engagement Email users.

H₁: pTreatment > pControl

Experiment Assignment

50%     Control (A)

50% → Treatment (B)

Based on the root-cause analysis, an A/B experiment was designed to address the primary observed friction at the Product View → Add-to-Cart stage among high-engagement Email users. Eligible users were randomly assigned to either the existing product-page experience (Control) or an enhanced experience (Treatment) featuring a more prominent Add-to-Cart CTA, clearer promotional messaging, and stronger purchase-confidence information.

The primary experiment metric is Product View → Add-to-Cart Rate, supported by downstream conversion and revenue metrics and appropriate guardrails. The experiment tests whether the enhanced experience produces a measurable improvement in progression from product evaluation to purchase intent.

2.4.2 — A/B Test Analysis

2.4.2.1 — First, Identify the Existing Experiments

Since we have already created and populated the Experiments, ExperimentVariants, and ExperimentAssignments tables, we first need to identify which Experiments and Variants actually exist in the dataset before writing the main SQL query.

USE ShopSense;

GO

— 2.4.2.1

— Experiment & Variant Validation

SELECT

    e.ExperimentID,

    e.ExperimentName,

    e.PrimaryMetric,

    e.Status,

    e.StartDate,

    e.EndDate,

    ev.VariantID,

    ev.VariantName,

    ev.VariantDescription,

    ev.AllocationPercent,

    COUNT(ea.AssignmentID) AS AssignedObservations

FROM dbo.Experiments e

INNER JOIN dbo.ExperimentVariants ev

    ON e.ExperimentID = ev.ExperimentID

LEFT JOIN dbo.ExperimentAssignments ea

    ON ev.ExperimentID = ea.ExperimentID

   AND ev.VariantID = ea.VariantID

GROUP BY

    e.ExperimentID,

    e.ExperimentName,

    e.PrimaryMetric,

    e.Status,

    e.StartDate,

    e.EndDate,

    ev.VariantID,

    ev.VariantName,

    ev.VariantDescription,

    ev.AllocationPercent

ORDER BY

    e.ExperimentID,

    ev.VariantID;

2.4.2.2 — Review Assignments and Variants for Experiment 2

Before calculating the KPIs, we need to determine how many assignments belong to the Control and Treatment groups and whether the experiment assignments were made at the User level or Session level.

USE ShopSense;

GO

— 2.4.2.2

— Experiment 2: Assignment Validation

SELECT

    e.ExperimentID,

    e.ExperimentName,

    ev.VariantID,

    ev.VariantName,

    ev.VariantDescription,

    ev.AllocationPercent,

    COUNT(ea.AssignmentID) AS TotalAssignments,

    COUNT(DISTINCT ea.UserID) AS AssignedUsers,

    COUNT(DISTINCT ea.SessionID) AS AssignedSessions,

    MIN(ea.AssignmentTimestamp) AS FirstAssignment,

    MAX(ea.AssignmentTimestamp) AS LastAssignment

FROM dbo.Experiments e

INNER JOIN dbo.ExperimentVariants ev

    ON e.ExperimentID = ev.ExperimentID

LEFT JOIN dbo.ExperimentAssignments ea

    ON e.ExperimentID = ea.ExperimentID

   AND ev.VariantID = ea.VariantID

WHERE e.ExperimentID = 2

GROUP BY

    e.ExperimentID,

    e.ExperimentName,

    ev.VariantID,

    ev.VariantName,

    ev.VariantDescription,

    ev.AllocationPercent

ORDER BY ev.VariantID;

2.4.2.2A — Assignment Summary

USE ShopSense;

GO

— 2.4.2.2A

— Experiment 2: Assignment Summary

SELECT

    ev.VariantName,

    COUNT(ea.AssignmentID) AS TotalAssignments,

    COUNT(DISTINCT ea.UserID) AS AssignedUsers,

    COUNT(DISTINCT ea.SessionID) AS AssignedSessions,

    CAST(

        100.0 * COUNT(ea.AssignmentID)

        / NULLIF(

            SUM(COUNT(ea.AssignmentID)) OVER (), 0

        )

        AS DECIMAL(6,2)

    ) AS ActualAllocationPercent,

    MIN(ea.AssignmentTimestamp) AS FirstAssignment,

    MAX(ea.AssignmentTimestamp) AS LastAssignment

FROM dbo.ExperimentVariants ev

LEFT JOIN dbo.ExperimentAssignments ea

    ON ev.ExperimentID = ea.ExperimentID

   AND ev.VariantID = ea.VariantID

WHERE ev.ExperimentID = 2

GROUP BY ev.VariantName

ORDER BY ev.VariantName;

Review of Assignment Results

MetricControlTreatment
Total Assignments2,2502,250
Assigned Users2,2502,250
Assigned Sessions00
Actual Allocation50.00%50.00%

Total Assignments:  4,500

Control · 50%

Treatment · 50%

Interpretation

Experiment 2 used user-level assignment with 4,500 assignments evenly distributed between Control and Treatment (2,250 each). The observed 50/50 allocation matched the planned experiment split, providing a balanced starting point for A/B analysis. Further checks are required to verify assignment exclusivity and valid post-assignment outcomes.

2.4.2.3 — Control vs Treatment KPI Analysis

USE ShopSense;

GO

— 2.4.2.3

— Experiment 2: Control vs Treatment KPI Analysis

— User-level assignment

— Post-assignment sessions within experiment dates

WITH AssignmentCheck AS

(

    SELECT

        ea.UserID

    FROM dbo.ExperimentAssignments ea

    WHERE ea.ExperimentID = 2

      AND ea.UserID IS NOT NULL

    GROUP BY ea.UserID

    HAVING COUNT(DISTINCT ea.VariantID) = 1

),

ValidAssignments AS

(

    SELECT

        ea.UserID,

        ev.VariantName,

        MIN(ea.AssignmentTimestamp) AS AssignmentTimestamp

    FROM dbo.ExperimentAssignments ea

    INNER JOIN dbo.ExperimentVariants ev

        ON ea.VariantID = ev.VariantID

       AND ea.ExperimentID = ev.ExperimentID

    INNER JOIN AssignmentCheck ac

        ON ea.UserID = ac.UserID

    WHERE ea.ExperimentID = 2

    GROUP BY

        ea.UserID,

        ev.VariantName

),

EligibleSessions AS

(

    SELECT

        va.UserID,

        va.VariantName,

        s.SessionID

    FROM ValidAssignments va

    INNER JOIN dbo.Sessions s

        ON s.UserID = va.UserID

    INNER JOIN dbo.Experiments e

        ON e.ExperimentID = 2

    WHERE s.SessionStart >= va.AssignmentTimestamp

      AND s.SessionStart >= e.StartDate

      AND s.SessionStart < DATEADD(

            DAY, 1, COALESCE(e.EndDate, e.StartDate)

          )

),

SessionMetrics AS

(

    SELECT

        es.UserID,

        es.VariantName,

        es.SessionID,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.ProductViews pv

            WHERE pv.SessionID = es.SessionID

        ) THEN 1 ELSE 0 END AS HasProductView,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.CartEvents ce

            WHERE ce.SessionID = es.SessionID

              AND ce.EventType = ‘Add’

        ) THEN 1 ELSE 0 END AS HasAddToCart,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.CheckoutEvents ch

            WHERE ch.SessionID = es.SessionID

              AND ch.EventType = ‘Started’

        ) THEN 1 ELSE 0 END AS HasCheckout,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.Orders o

            WHERE o.SessionID = es.SessionID

        ) THEN 1 ELSE 0 END AS HasPurchase,

        COALESCE(

        (

            SELECT SUM(o.TotalAmount)

            FROM dbo.Orders o

            WHERE o.SessionID = es.SessionID

        ), 0) AS SessionRevenue

    FROM EligibleSessions es

)

SELECT

    va.VariantName,

    COUNT(DISTINCT va.UserID) AS AssignedUsers,

    COUNT(sm.SessionID) AS EligibleSessions,

    COALESCE(SUM(sm.HasProductView), 0)

        AS ProductViewSessions,

    COALESCE(SUM(

        CASE

            WHEN sm.HasProductView = 1

             AND sm.HasAddToCart = 1

            THEN 1 ELSE 0

        END

    ), 0) AS ProductViewToCartSessions,

    CAST(

        100.0 * COALESCE(SUM(

            CASE

                WHEN sm.HasProductView = 1

                 AND sm.HasAddToCart = 1

                THEN 1 ELSE 0

            END

        ), 0)

        / NULLIF(SUM(sm.HasProductView), 0)

        AS DECIMAL(8,2)

    ) AS ProductViewToCartRate,

    COALESCE(SUM(sm.HasCheckout), 0)

        AS CheckoutSessions,

    COALESCE(SUM(sm.HasPurchase), 0)

        AS PurchaseSessions,

    CAST(

        100.0 * COALESCE(SUM(sm.HasPurchase), 0)

        / NULLIF(COUNT(sm.SessionID), 0)

        AS DECIMAL(8,2)

    ) AS PurchaseConversionRate,

    CAST(

        COALESCE(SUM(sm.SessionRevenue), 0)

        / NULLIF(COUNT(sm.SessionID), 0)

        AS DECIMAL(12,2)

    ) AS RevenuePerSession

FROM ValidAssignments va

LEFT JOIN SessionMetrics sm

    ON va.UserID = sm.UserID

   AND va.VariantName = sm.VariantName

GROUP BY va.VariantName

ORDER BY va.VariantName;

Final A/B Test KPI Comparison

Experiment 2 showed a positive directional improvement in Product View → Add-to-Cart Rate, increasing from 29.17% in Control to 30.70% in Treatment. This represents an absolute lift of 1.53 percentage points and a relative uplift of approximately 5.25%. However, statistical validation is required before concluding that the treatment produced a reliable improvement.

Experiment 2 demonstrated a positive directional improvement in Product View → Add-to-Cart Rate, increasing from 29.17% in Control to 30.70% in Treatment (+1.53 percentage points; +5.25% relative uplift). Revenue per Session also increased by approximately 6.53%. However, Purchase Conversion Rate declined slightly from 15.11% to 14.97%. These mixed outcomes suggest that stronger cart engagement did not necessarily translate into higher purchase conversion, highlighting the importance of evaluating downstream metrics alongside the primary experiment KPI.

2.4.3 — Statistical Validation in Python

1. Primary Metric: Evaluate the difference in Product View → Cart Rate using User-Level Bootstrapping, and calculate the 95% Confidence Interval and p-value.

2. Secondary Metrics: Evaluate Purchase Conversion Rate and Revenue per Session as supplementary metrics and guardrail metrics.

3. Final Decision: Determine whether the evidence is sufficient to recommend rolling out the Treatment.

We want to determine whether the 1.53 percentage-point increase in Add-to-Cart Rate represents a statistically reliable improvement or could simply be due to random sampling variation.

2.4.3.1 — Export User-Level Experiment Data

USE ShopSense;

GO

— 2.4.3.1

— Experiment 2: User-Level Data Export

— One row per assigned user

— Control vs Treatment

WITH AssignmentCheck AS

(

    SELECT UserID

    FROM dbo.ExperimentAssignments

    WHERE ExperimentID = 2

      AND UserID IS NOT NULL

    GROUP BY UserID

    HAVING COUNT(DISTINCT VariantID) = 1

),

ValidAssignments AS

(

    SELECT

        ea.UserID,

        ev.VariantName,

        MIN(ea.AssignmentTimestamp) AS AssignmentTimestamp

    FROM dbo.ExperimentAssignments ea

    INNER JOIN dbo.ExperimentVariants ev

        ON ea.ExperimentID = ev.ExperimentID

       AND ea.VariantID = ev.VariantID

    INNER JOIN AssignmentCheck ac

        ON ea.UserID = ac.UserID

    WHERE ea.ExperimentID = 2

    GROUP BY ea.UserID, ev.VariantName

),

EligibleSessions AS

(

    SELECT

        va.UserID,

        va.VariantName,

        s.SessionID

    FROM ValidAssignments va

    INNER JOIN dbo.Sessions s

        ON s.UserID = va.UserID

    INNER JOIN dbo.Experiments e

        ON e.ExperimentID = 2

    WHERE s.SessionStart >= va.AssignmentTimestamp

      AND s.SessionStart >= e.StartDate

      AND s.SessionStart <

          DATEADD(DAY, 1, COALESCE(e.EndDate, e.StartDate))

),

SessionMetrics AS

(

    SELECT

        es.UserID,

        es.VariantName,

        es.SessionID,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.ProductViews pv

            WHERE pv.SessionID = es.SessionID

        ) THEN 1 ELSE 0 END AS HasProductView,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.CartEvents ce

            WHERE ce.SessionID = es.SessionID

              AND ce.EventType = ‘Add’

        ) THEN 1 ELSE 0 END AS HasAddToCart,

        CASE WHEN EXISTS

        (

            SELECT 1

            FROM dbo.Orders o

            WHERE o.SessionID = es.SessionID

        ) THEN 1 ELSE 0 END AS HasPurchase,

        COALESCE(

        (

            SELECT SUM(o.TotalAmount)

            FROM dbo.Orders o

            WHERE o.SessionID = es.SessionID

        ), 0) AS SessionRevenue

    FROM EligibleSessions es

),

UserMetrics AS

(

    SELECT

        UserID,

        VariantName,

        COUNT(*) AS EligibleSessions,

        SUM(HasProductView) AS ProductViewSessions,

        SUM(

            CASE

                WHEN HasProductView = 1

                 AND HasAddToCart = 1

                THEN 1 ELSE 0

            END

        ) AS AddToCartSessions,

        SUM(HasPurchase) AS PurchaseSessions,

        SUM(SessionRevenue) AS TotalRevenue

    FROM SessionMetrics

    GROUP BY UserID, VariantName

)

SELECT

    va.UserID,

    va.VariantName,

    COALESCE(um.EligibleSessions, 0) AS EligibleSessions,

    COALESCE(um.ProductViewSessions, 0) AS ProductViewSessions,

    COALESCE(um.AddToCartSessions, 0) AS AddToCartSessions,

    COALESCE(um.PurchaseSessions, 0) AS PurchaseSessions,

    COALESCE(um.TotalRevenue, 0) AS TotalRevenue

FROM ValidAssignments va

LEFT JOIN UserMetrics um

    ON va.UserID = um.UserID

   AND va.VariantName = um.VariantName

ORDER BY va.VariantName, va.UserID;

2.4.3 — Statistical Validation in Python

Experiment 2 was evaluated using user-level bootstrap confidence intervals and permutation testing to account for repeated sessions within users.

The Treatment increased Product View → Add-to-Cart Rate from 29.17% to 30.70%, representing an absolute uplift of 1.53 percentage points and a relative uplift of 5.24%.

However, the improvement was not statistically significant (p = 0.1002; 95% CI: −0.25 to +3.34 percentage points).

Purchase Conversion Rate declined slightly, while Revenue per Session increased by approximately 6.53%. Neither secondary outcome showed a statistically significant difference.

Final Decision: The experiment produced encouraging directional results, but the evidence is insufficient to justify a full Treatment rollout. Further experimentation with adequate statistical power and continued monitoring of downstream business metrics is recommended.

2.4.4 — Final Results & Business Recommendations

Experiment: Product Recommendation Layout A/B Test

The A/B experiment evaluated whether an improved product recommendation layout could increase Product View → Add-to-Cart Rate.

The Treatment achieved a 1.53 percentage-point absolute uplift (+5.24% relative) in the primary metric, increasing from 29.17% to 30.70%. However, user-level statistical validation found that this improvement was not statistically significant (p = 0.1002; 95% CI: −0.25 to +3.34 percentage points).

Secondary metrics showed mixed directional outcomes. Purchase Conversion Rate declined slightly from 15.11% to 14.97%, while Revenue per Session increased by approximately 6.53%. Neither difference was statistically significant.

Business Decision: The available evidence does not support a full rollout of the Treatment.

Recommendations:

  • Conduct a follow-up experiment with adequate statistical power and a predefined minimum detectable effect.
  • Monitor Purchase Conversion Rate, Checkout Completion, and Revenue per Session alongside the primary metric.
  • Validate whether improved cart engagement translates into meaningful business value.
  • Design a separate targeted experiment to investigate the Product View → Cart friction previously identified among high-engagement Email users.

Final Takeaway: Positive directional uplift alone is not sufficient to establish experiment success. Reliable product decisions require statistical validation, downstream business impact assessment, and careful interpretation of uncertainty.

Data Visualization & Business Intelligence

Why do highly engaged users fail to convert, and where should the business focus its optimization efforts?

Power BI Dashboard Development

We will create two report pages in Power BI:

1. Executive Overview: An overview of the store’s overall performance, revenue, conversion rates, and user behavior.

2. Conversion & Root Cause Analysis: Funnel analysis, comparison of Email and Organic traffic, and identification of key drop-off points.

3.1-Data Modelling

Power BI Data Model Refinement:

The initial Power BI data model was refined to improve clarity, organization, and analytical usability. Tables were rearranged to make relationships and data flows easier to understand, while preserving the core connections between users, sessions, searches, product interactions, orders, and experiment assignments. A disconnected Funnel Stages table was also introduced to support dynamic funnel visualizations and conversion analysis using DAX measures. These refinements made the model easier to navigate and better suited for building interactive business intelligence dashboards.

3.2 — Creating DAX Measures

1-Total Sessions =

DISTINCTCOUNT(Sessions[SessionID])

2-Search Sessions =

DISTINCTCOUNT(Searches[SessionID])

3-Purchase Sessions =

DISTINCTCOUNT(Orders[SessionID])

4-Purchase Conversion Rate =

DIVIDE(

    [Purchase Sessions],

    [Total Sessions],

    0

)

5-Total Revenue =

SUM(Orders[TotalAmount])

6-Revenue per Session =

DIVIDE(

    [Total Revenue],

    [Total Sessions],

    0

)

7-Add-to-Cart Sessions =

CALCULATE(

    DISTINCTCOUNT(CartEvents[SessionID]),

    CartEvents[EventType] = “Add”

)

Step 1 — Create Three New Measures

1-Product View Sessions =

DISTINCTCOUNT(ProductViews[SessionID])

2-Checkout Sessions =

CALCULATE(

    DISTINCTCOUNT(CheckoutEvents[SessionID]),

    CheckoutEvents[EventType] = “Started”

)

3-Purchase Sessions Fixed =

CALCULATE(

    DISTINCTCOUNT(Orders[SessionID]),

    TREATAS(

        VALUES(Sessions[SessionID]),

        Orders[SessionID]

    )

)

4-Purchase Conversion Rate Fixed =

DIVIDE(

    [Purchase Sessions Fixed],

    [Total Sessions],

    0

)

3.3 — KPI Validation

KPIAmount
Total Sessions40,000
Search Sessions26,000
Purchase Conversion Rate15.00%
Add-to-Cart Sessions12,000
Revenue per Session107.85
Total Revenue4.31M

The 15% Conversion Rate is consistent with 6,000 Purchase Sessions out of 40,000 Total Sessions. Additionally, Revenue per Session aligns with the displayed Total Revenue.

Since the values shown on the Cards are rounded, minor discrepancies are expected.

3.4 — Conversion Funnel Visualization

For the Funnel analysis, we measure each stage at the Session level. Therefore, a user with multiple similar events within the same session is counted only once per stage.

Step 2 — Create the Funnel Stages Table

Funnel Stages =

DATATABLE(

    “Stage”, STRING,

    “SortOrder”, INTEGER,

    {

        {“Sessions”, 1},

        {“Product View”, 2},

        {“Add-to-Cart”, 3},

        {“Checkout”, 4},

        {“Purchase”, 5}

    }

)

Step 3 — Create the Funnel Measure

Funnel Sessions =

SWITCH(

    SELECTEDVALUE(‘Funnel Stages'[stage]),

    “Sessions”, [Total Sessions],

    “Product View”, [Product View Sessions],

    “Add-to-Cart”, [Add-to-Cart Sessions],

    “Checkout”, [Checkout Sessions],

    “Purchase”, [Purchase Sessions Fixed],

    BLANK()

)

3.5 — Revenue Trend

1-Total Revenue Fixed =

CALCULATE(

    SUM(Orders[TotalAmount]),

    REMOVEFILTERS(Orders),

    TREATAS(

        VALUES(Sessions[SessionID]),

        Orders[SessionID]

    )

)

2-Revenue per Session Fixed =

DIVIDE(

    [Total Revenue Fixed],

    [Total Sessions],

    0

)

Dashboard 1

ShopSense | Executive Overview

E-commerce Performance & Customer Journey Analytics

Developed an interactive Power BI dashboard to provide a comprehensive overview of ShopSense’s e-commerce performance and customer journey.

The dashboard tracks six key performance indicators (KPIs), including Total Revenue, Purchase Conversion Rate, Revenue per Session, Total Sessions, Search Sessions, and Add-to-Cart Sessions.

Through monthly revenue trends, a customer conversion funnel, device distribution, and traffic source comparisons, the dashboard helps stakeholders monitor business performance, identify conversion drop-offs, and understand customer behavior.

Key Results: $4.31M in total revenue, a 15.00% purchase conversion rate, and 40,000 customer sessions.

Business Value: Transforms transactional and behavioral data into clear, actionable insights to support data-driven decisions and conversion optimization.

Dashboard 2

ShopSense | Conversion & Root Cause Analysis

In the first dashboard, we analyzed the store’s overall performance. Now, in the second dashboard, we aim to answer an important business question:

Why do highly engaged customers fail to convert, particularly in the Email channel?

According to our SQL analysis, the Product View → Add-to-Cart Conversion Rate among highly engaged sessions was 20.00% for Email traffic, compared with 32.13% for Organic traffic.

Our goal is to visualize this performance gap and identify key drop-off points, rather than claim that we have established its underlying cause.

Creating KPI Measure:

1. Product View Sessions

Product View Sessions =

DISTINCTCOUNT(ProductViews[SessionID])

2. Product View to Cart Sessions

Product View to Cart Sessions =

VAR ViewedSessions =

    VALUES(ProductViews[SessionID])

VAR CartSessions =

    CALCULATETABLE(

        VALUES(CartEvents[SessionID]),

        CartEvents[EventType] = “Add”

    )

RETURN

    COUNTROWS(

        INTERSECT(ViewedSessions, CartSessions)

    )

3. Product View to Cart Rate

Product View to Cart Rate =

DIVIDE(

    [Product View to Cart Sessions],

    [Product View Sessions],

    0

)

4.Product View Without Cart Sessions

Product View Without Cart Sessions =

[Product view Sessions]

    – [Product View to Cart Sessions]

5. High Engagement Sessions

High Engagement Sessions =

COUNTROWS(

    FILTER(

        VALUES(Sessions[SessionID]),

        CALCULATE(

            COUNTROWS(Searches)

        ) >= 4

    )

)

6. HE Product View to Cart Rate

HE Product View to Cart Rate =

VAR HighEngagementSessions =

    FILTER(

        VALUES(Sessions[SessionID]),

        CALCULATE(COUNTROWS(Searches)) >= 4

    )

VAR ViewedSessions =

    CALCULATETABLE(

        VALUES(ProductViews[SessionID]),

        TREATAS(

            HighEngagementSessions,

            ProductViews[SessionID]

        )

    )

VAR CartSessions =

    CALCULATETABLE(

        VALUES(CartEvents[SessionID]),

        REMOVEFILTERS(CartEvents),

        CartEvents[EventType] = “Add”,

        TREATAS(

            HighEngagementSessions,

            CartEvents[SessionID]

        )

    )

VAR ConvertedSessions =

    INTERSECT(ViewedSessions, CartSessions)

RETURN

    DIVIDE(

        COUNTROWS(ConvertedSessions),

        COUNTROWS(ViewedSessions)

    )

7. Create the Conversion Stages Table

HE Conversion Stages =

DATATABLE(

    “Stage”, STRING,

    “SortOrder”, INTEGER,

    {

        {“Product View”, 1},

        {“Add-to-Cart”, 2},

        {“Checkout”, 3},

        {“Payment”, 4},

        {“Completed”, 5}

    }

)

Power BI Data Model Enhancement – Conversion Analysis:

The Power BI data model was further enhanced by introducing a disconnected HE Conversion Stages table to support stage-to-stage conversion analysis for high-engagement sessions. This new table complements the existing Funnel Stages table, enabling DAX measures to calculate and compare conversion rates across different stages of the customer journey. The model layout was also reorganized for better readability, while preserving the existing relationships between transactional and behavioral tables. These enhancements enabled a more detailed comparison of Email and Organic traffic, helping identify conversion gaps and potential friction points in the purchase journey.

8. HE Checkout Started Sessions

HE Checkout Started Sessions =

VAR HighEngagementSessions =

    FILTER(

        VALUES(Sessions[SessionID]),

        CALCULATE(COUNTROWS(Searches)) >= 4

    )

RETURN

    CALCULATE(

        DISTINCTCOUNT(CheckoutEvents[SessionID]),

        REMOVEFILTERS(CheckoutEvents),

        CheckoutEvents[EventType] = “Started”,

        TREATAS(

            HighEngagementSessions,

            CheckoutEvents[SessionID]

        )

    )

9. HE Payment Sessions

HE Payment Sessions =

VAR HighEngagementSessions =

    FILTER(

        VALUES(Sessions[SessionID]),

        CALCULATE(

            COUNTROWS(Searches)

        ) >= 4

    )

VAR PaymentSessions =

    CALCULATETABLE(

        VALUES(CheckoutEvents[SessionID]),

        CheckoutEvents[EventType] = “Payment”

    )

RETURN

    COUNTROWS(

        INTERSECT(

            HighEngagementSessions,

            PaymentSessions

        )

    )

10. HE Payment Intersection Test

HE Payment Intersection Test =

VAR HESessions =

    FILTER(

        ALL(Sessions[SessionID]),

        CALCULATE(COUNTROWS(Searches)) >= 4

    )

VAR PaymentSessions =

    CALCULATETABLE(

        VALUES(CheckoutEvents[SessionID]),

        REMOVEFILTERS(CheckoutEvents),

        CheckoutEvents[EventType] = “Payment”

    )

RETURN

    COUNTROWS(

        INTERSECT(

            HESessions,

            PaymentSessions

        )

    )

11. HE Completed Sessions

HE Completed Sessions =

VAR HESessions =

    FILTER(

        ALL(Sessions[SessionID]),

        CALCULATE(COUNTROWS(Searches)) >= 4

    )

VAR CompletedSessions =

    CALCULATETABLE(

        VALUES(CheckoutEvents[SessionID]),

        REMOVEFILTERS(CheckoutEvents),

        CheckoutEvents[EventType] = “Completed”

    )

RETURN

    COUNTROWS(

        INTERSECT(

            HESessions,

            CompletedSessions

        )

    )

12. HE Funnel Sessions

HE Funnel Sessions =

SWITCH(

    SELECTEDVALUE(‘HE Conversion Stages'[Stage]),

    “Product View”, [HE Product View Sessions Diagnostic],

    “Add-to-Cart”, [He Cart Sessions Check],

    “Checkout”, [He Checkout Started Sessions],

    “Payment”, [HE Payment Intersection Test],

    “Completed”, [HE Completed Sessions],

    BLANK()

)

13. HE Conversion Rate Stages table

HE Conversion Rate Stages =

DATATABLE(

    “Stage”, STRING,

    “SortOrder”, INTEGER,

    {

        {“View to Cart”, 1},

        {“Cart to Checkout”, 2},

        {“Checkout to Payment”, 3},

        {“Payment to Completed”, 4}

    }

)

14. HE Stage Conversion Rate

HE Stage Conversion Rate =

VAR CurrentStage =

    SELECTEDVALUE(‘HE Conversion Rate Stages'[Stage])

RETURN

    SWITCH(

        CurrentStage,

        “View to Cart”,

            DIVIDE(

                [He Cart Sessions Check],

                [HE Product View Sessions Diagnostic]

            ),

        “Cart to Checkout”,

            DIVIDE(

                [He Checkout Started Sessions],

                [He Cart Sessions Check]

            ),

        “Checkout to Payment”,

            DIVIDE(

                [HE Payment Intersection Test],

                [He Checkout Started Sessions]

            ),

        “Payment to Completed”,

            DIVIDE(

                [HE Completed Sessions],

                [HE Payment Intersection Test]

            ),

        BLANK()

    )

15.He Product View Sassions Diagnostic

HE Product View Sessions Diagnostic =

VAR HighEngagementSessions =

    FILTER(

        VALUES(Sessions[SessionID]),

        CALCULATE(COUNTROWS(Searches)) >= 4

    )

RETURN

    COUNTROWS(

        CALCULATETABLE(

            VALUES(ProductViews[SessionID]),

            TREATAS(

                HighEngagementSessions,

                ProductViews[SessionID]

            )

        )

    )

16.He Cart Sessions Check

HE Cart Sessions Check =

VAR HighEngagementSessions =

    FILTER(

        VALUES(Sessions[SessionID]),

        CALCULATE(COUNTROWS(Searches)) >= 4

    )

RETURN

    CALCULATE(

        DISTINCTCOUNT(CartEvents[SessionID]),

        CartEvents[EventType] = “Add”,

        REMOVEFILTERS(CartEvents),

        TREATAS(

            HighEngagementSessions,

            CartEvents[SessionID]

        )

    )

The Conversion & Root Cause Analysis dashboard investigates customer journey friction, focusing on high-engagement sessions (four or more searches). The analysis revealed a significant conversion gap between Email and Organic traffic at the Product View → Add-to-Cart stage, with conversion rates of 20.00% and 32.13%, respectively—a difference of 12.13 percentage points. Interestingly, Email traffic performed better at the subsequent Cart → Checkout stage (85.71% vs. 66.38%), indicating that the primary observed friction occurs earlier in the purchase journey. Further analysis of product exposure, pricing, discounts, ratings, reviews, and stock availability did not reveal a clear explanation for this gap. Based on these findings, an enhanced product-page experience was recommended for A/B testing, focusing on clearer calls to action, promotional messaging, and delivery/return information. The objective is to improve add-to-cart conversion while monitoring downstream purchase conversion and revenue per session. The underlying cause remains a hypothesis rather than a confirmed causal finding.

Tableau

Dashboard 3 — A/B Testing & Experiment Performance

Our goal is to evaluate the performance of the Control and Treatment groups in Experiment 2: Product Recommendation Layout.

Step 1 — Prepare the Data in SQL Server

For Tableau, it is better to first create a clean, consolidated dataset that contains all the information required for the dashboard in a single table.

Field                                                   Description

UserID                                                 Unique user identifier

VariantName                                      Control / Treatment

EligibleSessions                                 Number of eligible sessions

ProductViewSessions                         Number of sessions with at least one product view

ProductViewToCartSessions              Number of sessions with both a product view and an add-to-cart event

PurchaseSessions                                Number of sessions with at least one order

TotalRevenue                                     Total revenue generated from sessions

USE ShopSense;

GO

— Dashboard 3 | Experiment 2 Dataset

WITH ValidAssignments AS (

    SELECT

        ea.UserID,

        MAX(ev.VariantName) AS VariantName,

        MIN(ea.AssignmentTimestamp) AS AssignmentTimestamp

    FROM dbo.ExperimentAssignments ea

    INNER JOIN dbo.ExperimentVariants ev

        ON ea.VariantID = ev.VariantID

       AND ea.ExperimentID = ev.ExperimentID

    WHERE ea.ExperimentID = 2

      AND ea.UserID IS NOT NULL

    GROUP BY ea.UserID

    HAVING COUNT(DISTINCT ea.VariantID) = 1

),

EligibleSessions AS (

    SELECT

        va.UserID,

        va.VariantName,

        s.SessionID

    FROM ValidAssignments va

    INNER JOIN dbo.Sessions s

        ON s.UserID = va.UserID

    INNER JOIN dbo.Experiments e

        ON e.ExperimentID = 2

    WHERE s.SessionStart >= va.AssignmentTimestamp

      AND s.SessionStart >= e.StartDate

      AND s.SessionStart < DATEADD(

          DAY, 1, COALESCE(e.EndDate, e.StartDate)

      )

),

SessionMetrics AS (

    SELECT

        es.UserID,

        es.SessionID,

        CASE WHEN EXISTS (

            SELECT 1

            FROM dbo.ProductViews pv

            WHERE pv.SessionID = es.SessionID

        ) THEN 1 ELSE 0 END AS HasProductView,

        CASE WHEN EXISTS (

            SELECT 1

            FROM dbo.CartEvents ce

            WHERE ce.SessionID = es.SessionID

              AND ce.EventType = ‘Add’

        ) THEN 1 ELSE 0 END AS HasAddToCart,

        CASE WHEN EXISTS (

            SELECT 1

            FROM dbo.Orders o

            WHERE o.SessionID = es.SessionID

        ) THEN 1 ELSE 0 END AS HasPurchase,

        COALESCE((

            SELECT SUM(o.TotalAmount)

            FROM dbo.Orders o

            WHERE o.SessionID = es.SessionID

        ), 0) AS SessionRevenue

    FROM EligibleSessions es

)

SELECT

    va.UserID,

    va.VariantName,

    COUNT(sm.SessionID) AS EligibleSessions,

    COALESCE(SUM(sm.HasProductView), 0)

        AS ProductViewSessions,

    COALESCE(SUM(

        CASE

            WHEN sm.HasProductView = 1

             AND sm.HasAddToCart = 1

            THEN 1 ELSE 0

        END

    ), 0) AS ProductViewToCartSessions,

    COALESCE(SUM(sm.HasPurchase), 0)

        AS PurchaseSessions,

    COALESCE(SUM(sm.SessionRevenue), 0)

        AS TotalRevenue

FROM ValidAssignments va

LEFT JOIN SessionMetrics sm

    ON va.UserID = sm.UserID

GROUP BY

    va.UserID,

    va.VariantName

ORDER BY

    va.VariantName,

    va.UserID;

Add-to-Cart Conversion Rate | Control vs Treatment

Important Note: Since each row represents a single user, we calculate conversion rates in Tableau using the ratio of aggregated totals.

Create Calculated Field:

1.PV to Cart Conversion Rate

SUM([ProductViewToCartSessions])

/

SUM([ProductViewSessions])

2.Purchase Conversion Rate

SUM([PurchaseSessions])

/

SUM([EligibleSessions])

3. Revenue per Session

SUM([TotalRevenue])

/

SUM([EligibleSessions])

4. Add-to-Cart Uplift (pp)

(

    { FIXED : SUM(

        IF [VariantName] = “Treatment”

        THEN [ProductViewToCartSessions] END

    )}

    /

    { FIXED : SUM(

        IF [VariantName] = “Treatment”

        THEN [ProductViewSessions] END

    )}

    –

    { FIXED : SUM(

        IF [VariantName] = “Control”

        THEN [ProductViewToCartSessions] END

    )}

    /

    { FIXED : SUM(

        IF [VariantName] = “Control”

        THEN [ProductViewSessions] END

    )}

) * 100

This dashboard evaluates the performance of Control and Treatment groups in Experiment 2, Product Recommendation Layout, to assess the impact of the proposed experience on customer conversion and revenue. The Treatment group achieved a higher Product View-to-Cart Conversion Rate, increasing from 29.17% to 30.70%, representing a +1.53 percentage-point improvement (+5.25% relative uplift). Revenue per Session also increased from 102.04 to 108.70 (+6.53%), suggesting a positive directional impact on revenue generation. However, Purchase Conversion Rate declined slightly from 15.11% to 14.97% (−0.14 percentage points), indicating that increased cart engagement did not translate into higher purchase conversion. These mixed results highlight the importance of monitoring downstream business outcomes alongside the primary experiment metric. Statistical validation is required before determining whether the observed improvements are significant and recommending a full rollout.

Key points:

  • 1. Customer Journey & Behavioral Analysis
  • The analysis identified a meaningful segment of highly engaged users who interacted extensively with search and product-discovery features but did not complete a purchase.
  • High engagement was operationally defined as sessions containing four or more searches (SearchCount >= 4), providing a consistent cohort definition for deeper behavioral analysis.
  • High engagement alone did not guarantee conversion, demonstrating that strong search activity and product exploration can coexist with substantial downstream funnel friction.
  • This finding shifted the analysis from measuring engagement alone toward identifying where highly engaged users fail to progress toward purchase.
  • 2. Search Engagement Analysis
  • High-engagement non-purchasing users continued to interact heavily with search results and products, indicating that their failure to convert was not simply caused by a lack of activity or product exploration.
  • When Email and Organic high-engagement non-purchasing sessions were compared, their average search activity was very similar: 4.11 searches per Email session vs. 4.18 for Organic.
  • Email users generated slightly more search-result interactions, averaging 7.90 search clicks per session vs. 7.39 for Organic.
  • Email users also recorded slightly more product exploration, with 8.39 product views per session vs. 7.92 for Organic.
  • Average product-view duration was also broadly comparable: 243.02 seconds for Email vs. 254.81 seconds for Organic.
  • These results suggest that the Email conversion issue is not explained by weaker search engagement or substantially lower product browsing activity.
  • 3. Traffic Source Analysis — Email vs. Organic
  • Traffic-source analysis identified Email as an important segment for deeper investigation, particularly among high-engagement users who failed to purchase.
  • Despite substantial search and product interaction, Email users showed weaker progression toward the cart than comparable Organic users.
  • This distinction is important: the observed issue is not that Email users are disengaged; rather, they appear to be engaged users who encounter friction after product discovery.
  • Organic therefore served as a useful behavioral benchmark for understanding where Email sessions diverged in the purchase journey.
  • 4. Device-Level Analysis
  • Device segmentation showed that the weaker Email progression was not isolated to a single device type.
  • Among high-engagement non-purchasing sessions, Cart Progression was 9.09% for Email Desktop vs. 18.48% for Organic Desktop.
  • On Mobile, the corresponding rates were 8.70% for Email vs. 19.90% for Organic.
  • Tablet showed 0.00% for Email vs. 32.00% for Organic, although the Email Tablet cohort contained only 5 sessions, making this estimate highly unstable.
  • Because the Email gap appeared across Desktop and Mobile as well as the very small Tablet segment, the evidence does not support a purely device-specific explanation.
  • The small Tablet sample also demonstrates the importance of considering sample size alongside percentage differences rather than interpreting extreme rates in isolation.
  • 5. Category Mix Analysis
  • Category reach analysis showed some differences between Email and Organic users, but both traffic sources interacted with a broad range of product categories.
  • Certain categories were more heavily represented among Email sessions. For example, Furniture reached 40.98% of Email sessions vs. 30.84% of Organic sessions, a difference of +10.14 percentage points.
  • Other notable Email-overrepresented categories included Gaming (+8.50 pp), Menswear (+7.90 pp), Womenswear (+6.23 pp), Laptops (+6.20 pp), and Nonfiction (+5.98 pp).
  • However, category differences alone did not provide sufficient evidence that the overall Email conversion problem was caused primarily by a different product-category mix.
  • 6. Category-Level Cart Progression
  • Cart progression varied across categories, confirming that product/category context influences funnel behavior.
  • Across the combined high-engagement non-purchasing cohort, category-level Cart Progression ranged from approximately 14.78% for Fitness to 23.36% for Travel among the observed categories.
  • More importantly, when category and traffic source were analyzed together, Email generally showed lower Cart Progression than Organic within the same categories.
  • Examples included Womenswear: 4.17% Email vs. 21.57% Organic, Furniture: 4.00% vs. 21.05%, and Makeup: 7.41% vs. 23.44%.
  • Similar gaps appeared across several other categories, suggesting that the Email problem cannot be explained solely by Email users browsing a less-converting category mix.
  • The pattern instead points toward a traffic-source-related behavioral difference occurring within categories.
  • 7. Product View → Cart — Primary Funnel Friction
  • The clearest funnel difference was identified at the Product View → Cart transition.
  • Within the high-engagement, non-purchasing cohort, Email users had a Product View → Cart progression rate of 8.20%, compared with 20.45% for Organic users.
  • This represented an absolute difference of 12.26 percentage points, making Product View → Cart the strongest candidate for the primary friction point.
  • Importantly, users had already searched, clicked, and viewed products before reaching this stage. The problem therefore appears after product discovery but before purchase intent is translated into an Add-to-Cart action.
  • 8. Statistical Validation of the Product View → Cart Gap
  • A two-proportion Z-test was used to evaluate whether the observed Email–Organic difference could reasonably be attributed to sampling variation.
  • The test produced a Z-statistic of 2.2559 and a p-value of 0.0241.
  • Because p < 0.05, the null hypothesis of equal progression rates was rejected at the 5% significance level.
  • The estimated absolute difference was 12.26 percentage points, with a 95% confidence interval of 4.03% to 20.48%.
  • Cohen’s h = 0.3579 indicated a meaningful difference in practical terms rather than relying solely on statistical significance.
  • Together, these results provide stronger evidence that the lower Email Product View → Cart progression is a real behavioral signal in the analyzed dataset.
  • 9. Cart → Checkout Analysis
  • Among high-engagement non-purchasing users who reached the cart, Email users did not show weaker progression into checkout.
  • Email achieved a 60.00% Cart → Checkout rate, compared with 38.10% for Organic in this restricted cohort.
  • This indicates that the strongest Email friction occurs before the cart, rather than consistently throughout every downstream funnel stage.
  • Once an Email user expressed stronger purchase intent by adding a product to the cart, subsequent progression was considerably better than the earlier Product View → Cart transition.
  • 10. Checkout → Payment Analysis
  • Within the high-engagement non-purchasing cohort, Email showed 0 of 3 Checkout Started sessions reaching Payment, compared with 7 of 24 Organic sessions (29.17%).
  • However, the Email result is based on only three observations, making 0/3 insufficient evidence of a general Email payment-stage problem.
  • This result should therefore be treated as a secondary signal requiring more data, rather than as a confirmed root cause.
  • The analysis demonstrates why funnel percentages should always be interpreted together with their underlying denominators.
  • 11. Payment → Completed Analysis
  • To correctly analyze the final funnel stage, the No Purchase restriction was removed because retaining it would structurally exclude successful purchases.
  • Across all high-engagement sessions, Email recorded 9 Payment sessions and 9 Completed sessions, producing a 100.00% Payment → Completed rate.
  • Organic recorded 60 Payment sessions and 53 Completed sessions, corresponding to 88.33%.
  • Therefore, once Email users actually reached Payment, there was no evidence of a systematic completion problem in this dataset.
  • The 100% Email rate should nevertheless be interpreted cautiously because it is based on only nine Payment sessions.
  • 12. Full Funnel Comparison
  • A final comparison using a consistent cohort of all high-engagement Email and Organic sessions was conducted to avoid mixing populations across funnel stages.
  • Email contained 70 high-engagement sessions, while Organic contained 361; all of these sessions reached Product View.
  • Email progressed from Product View → Cart at 20.00%, compared with 32.13% for Organic, a 12.13 percentage-point disadvantage.
  • After reaching the cart, Email performed strongly: Cart → Checkout was 85.71% for Email vs. 66.38% for Organic.
  • Checkout → Payment was relatively similar: 75.00% for Email vs. 77.92% for Organic, a difference of only 2.92 percentage points.
  • Payment → Completed was 100.00% for Email vs. 88.33% for Organic, although the smaller Email denominator requires cautious interpretation.
  • Overall Product View → Completed conversion was 12.86% for Email vs. 14.68% for Organic, leaving a relatively modest final difference of 1.82 percentage points.
  • Overall Analytical Conclusion
  • The evidence consistently identifies Product View → Cart as the clearest friction point for high-engagement Email users.
  • The issue does not appear to originate from insufficient search activity, because Email users demonstrated search, click, product-view, and viewing-duration behavior broadly comparable to Organic users.
  • The pattern is also not adequately explained by device mix or category mix, because weaker Email cart progression appeared across multiple devices and within multiple product categories.
  • Once Email users entered the cart, their downstream behavior was generally comparable to or stronger than Organic users, substantially narrowing the final conversion gap.
  • The current evidence therefore supports a focused diagnosis: Email users successfully discover and explore products but are less likely to translate that engagement into an Add-to-Cart action.
  • This makes the Search/Product Discovery → Product Evaluation → Cart transition the highest-priority area for the next root-cause investigation, rather than treating checkout or payment as the primary problem.

A/B Testing & Experiment Design:

  • Extended the analysis from customer behavior and funnel diagnostics to experimentation, using Experiment 2 (Product Recommendation Layout) to evaluate an alternative product experience.
  • Analyzed two equally allocated groups, Control and Treatment, with 2,250 assigned users per variant.
  • Defined Product View-to-Cart Conversion Rate as the primary performance indicator, while monitoring Purchase Conversion Rate and Revenue per Session as downstream business metrics.
  • Distinguished the existing experiment from the proposed Email-specific product-page intervention, ensuring that experimental findings were not incorrectly presented as direct proof of the original Email conversion problem.

A/B Test Performance — Primary Metric

  • The Treatment group achieved a 30.70% Product View-to-Cart Conversion Rate, compared with 29.17% for Control.
  • This represented an absolute improvement of +1.53 percentage points and a +5.25% relative uplift.
  • The result provided a positive directional signal that the alternative product recommendation layout may improve progression from product exploration to cart engagement.

Downstream Conversion & Revenue Impact

  • Purchase Conversion Rate decreased slightly from 15.11% in Control to 14.97% in Treatment, a difference of −0.14 percentage points.
  • Revenue per Session increased from 102.04 to 108.70, representing a +6.53% relative improvement.
  • These mixed outcomes demonstrated that stronger Add-to-Cart engagement does not necessarily translate into higher purchase conversion.
  • Evaluating multiple KPIs provided a more balanced assessment of experiment performance than relying exclusively on the primary conversion metric.

Experiment Interpretation & Decision-Making

  • The Treatment showed promising directional improvements in Add-to-Cart Conversion and Revenue per Session, but the results alone were insufficient to justify a full rollout.
  • Statistical validation and uncertainty estimates are necessary to determine whether the observed differences provide reliable evidence of improvement.
  • Recommended further investigation into the gap between cart engagement and completed purchases, while monitoring downstream conversion and revenue metrics before making a deployment decision.

Business Intelligence & Data Storytelling

  • Developed three complementary dashboards to communicate e-commerce performance, conversion friction, and experimentation outcomes.
  • Used Power BI for executive-level reporting and customer journey analysis, and Tableau for A/B experiment performance visualization.
  • Translated technical findings into business-focused recommendations, connecting customer behavior, funnel performance, and experimental results.
  • Structured the dashboards to support a coherent analytical narrative, progressing from performance monitoring to problem diagnosis and evidence-based recommendations.

Results & Recommendations:

  • 1. Identified the Primary Conversion Bottleneck

The analysis identified the Product View → Cart transition as the most significant observed friction point among high-engagement Email users. Their conversion rate was 20.00%, compared with 32.13% for Organic traffic, representing a 12.13 percentage-point gap. This finding helped prioritize product evaluation and cart engagement over broader changes to the checkout process.

  • 2. Narrowed Down Potential Causes

Further investigation showed that differences in search engagement, device usage, product-category distribution, pricing, discounts, ratings, reviews, and product availability did not provide a convincing explanation for the observed conversion gap. Although the exact underlying cause remains unconfirmed, the analysis narrowed the investigation toward the experience between product discovery and Add-to-Cart.

  • 3. Evaluated A/B Experiment Performance

Experiment 2, Product Recommendation Layout, showed a positive directional improvement in Product View-to-Cart Conversion Rate, increasing from 29.17% in Control to 30.70% in Treatment (+1.53 percentage points; +5.25% relative uplift).

Revenue per Session also increased by 6.53%, while Purchase Conversion Rate declined slightly by 0.14 percentage points. These mixed results highlighted the need to evaluate overall business performance rather than relying on a single experiment metric.

  • 4. Established a Data-Driven Decision Framework

The project combined behavioral segmentation, funnel analysis, statistical testing, and business intelligence dashboards to support evidence-based decision-making. Rather than treating increased engagement as proof of business success, the analysis distinguished observed improvements from statistically validated outcomes and emphasized the importance of downstream conversion and revenue metrics.

Business Recommendations

  • 1. Test an Enhanced Product-Page Experience

Design a targeted A/B experiment for high-engagement Email users, focusing on clearer Add-to-Cart buttons, promotional messaging, delivery information, return policies, and customer confidence signals. Use Product View-to-Cart Conversion Rate as the primary metric, while monitoring Purchase Conversion Rate and Revenue per Session.

  • 2. Improve Email-to-Product Experience Consistency

Review the alignment between Email campaign messaging, promotional offers, landing pages, and product details. Ensure that customers encounter consistent pricing, discounts, product information, and expectations throughout their journey. Treat message mismatch as a hypothesis to test rather than an established cause.

  • 3. Investigate Cart-to-Purchase Behavior

Although the existing experiment increased Add-to-Cart engagement, it did not produce a corresponding improvement in Purchase Conversion Rate. Further analysis should examine cart abandonment, checkout progression, shipping costs, payment friction, and purchasing behavior to understand where additional conversions may be lost.

  • 4. Validate Experimental Results Before Rollout

Conduct statistical validation using appropriate methods that account for user-level experiment assignment. Evaluate confidence intervals, statistical significance, and practical business impact before recommending full deployment of the Treatment experience. Consider additional experimentation if the evidence remains inconclusive.

  • 5. Establish Continuous Conversion Monitoring

Use the Power BI and Tableau dashboards to track funnel performance, traffic-source differences, high-engagement customer behavior, experiment results, and revenue outcomes. Regular monitoring can help identify emerging friction points, evaluate future improvements, and support continuous optimization.

  • Final Business Conclusion

ShopSense demonstrates how an end-to-end analytics workflow can transform a broad business concern—high customer engagement without corresponding purchases—into a focused, measurable optimization opportunity. By identifying the Product View-to-Cart stage as the primary observed bottleneck, investigating alternative explanations, and evaluating a related A/B experiment, the project provides a foundation for targeted product improvements and evidence-based decision-making. The findings support further experimentation and statistical validation rather than an immediate full rollout, reinforcing the importance of balancing engagement metrics with actual conversion and revenue performance.

Action: Tools, Techniques & Analytical Implementation

In this project, I applied SQL, data modeling, statistical analysis, and business intelligence techniques to investigate customer behavior, identify conversion bottlenecks, evaluate A/B testing results, and translate analytical findings into actionable business recommendations.

1. SQL Server — Data Extraction & Analysis

Used SQL Server Management Studio (SSMS) to design and query a relational e-commerce database, validate data quality, analyze customer journeys, and calculate conversion metrics.

SQL Functions & Clauses:

Aggregate Functions: SUM, COUNT, AVG, MIN, MAX, COUNT(DISTINCT)

Query Operations: SELECT, WHERE, GROUP BY, HAVING, ORDER BY, DISTINCT

Joins: INNER JOIN, LEFT JOIN

Conditional Logic: CASE WHEN, COALESCE, NULLIF

Date Functions: DATEADD, DATEDIFF

Advanced Query Techniques: Common Table Expressions (CTEs), subqueries, EXISTS, and conditional aggregation

Key Applications: Funnel analysis, traffic-source segmentation, product-level analysis, conversion-rate calculations, data validation, and A/B experiment performance evaluation.

2. Data Modeling & Data Preparation

Designed and refined the relational data structure to support reliable analysis and interactive reporting.

Techniques:

Relational database design and normalization (3NF)

Primary and foreign keys

Entity Relationship Diagrams (ERDs)

Table relationships and filter propagation

Data cleaning, type conversion, and duplicate validation

Data aggregation and transformation

Disconnected helper tables for dynamic funnel analysis

Key Applications: Building a consistent analytical foundation for Power BI and Tableau dashboards.

3. Power BI: DAX & Business Intelligence

Developed interactive dashboards to monitor e-commerce performance, analyze customer engagement, and identify conversion friction across traffic sources.

DAX Functions & Techniques:

Aggregation: SUM, COUNTROWS, DISTINCTCOUNT

Filter Context: CALCULATE, CALCULATETABLE, FILTER, ALL, REMOVEFILTERS

Logical Functions: IF, SWITCH, ISBLANK

Table Functions: VALUES, INTERSECT, DATATABLE

Context & Relationships: SELECTEDVALUE, TREATAS

Calculation Handling: DIVIDE, VAR, RETURN

Key Applications: KPI development, dynamic conversion funnels, high-engagement segmentation, stage-to-stage conversion analysis, and Email vs. Organic performance comparisons.

4. Tableau — Calculated Fields & Visualization

Used Tableau to develop the A/B Testing & Experiment Performance dashboard and compare Control and Treatment groups.

Techniques:

Calculated fields and aggregate calculations

SUM and conditional IF expressions

FIXED Level of Detail (LOD) expressions

Percentage-point and relative uplift calculations

KPI cards and comparative bar charts

Dashboard formatting and data storytelling

Key Applications: Visualizing Add-to-Cart Conversion Rate, Purchase Conversion Rate, Revenue per Session, and experiment uplift.

5. Python — Statistical Analysis & Experiment Evaluation

Applied Python-based statistical techniques to evaluate conversion differences and support evidence-based interpretation of experimental results.

Libraries & Techniques:

Pandas and NumPy for data manipulation and numerical calculations

Statistical hypothesis testing

Conversion-rate comparisons

Confidence interval estimation

Effect-size interpretation

User-level bootstrap methodology for A/B experiment evaluation

Key Applications: Assessing uncertainty in conversion differences and distinguishing directional improvements from statistically supported conclusions.

6. A/B Testing & Business Decision-Making

Evaluated Experiment 2, Product Recommendation Layout, using user-level assignments and multiple business performance metrics.

Analytical Techniques:

Control vs. Treatment comparison

Primary and secondary KPI evaluation

Absolute and relative uplift calculations

Downstream conversion monitoring

Statistical uncertainty assessment

Business impact evaluation

Experiment-driven recommendations

Key Applications: Assessing whether changes in product engagement were accompanied by improvements in purchase conversion and revenue.

7. Reporting & Business Recommendations

Integrated findings from SQL Server, Python, Power BI, and Tableau into a structured analytical workflow.

Deliverables:

Relational database and data model documentation

SQL-based behavioral and conversion analysis

Root cause investigation

A/B testing evaluation

Power BI executive and conversion dashboards

Tableau experiment performance dashboard

Business recommendations and portfolio documentation

Outcome: Delivered an end-to-end e-commerce analytics case study demonstrating the ability to transform raw transactional and behavioral data into measurable insights, evaluate potential improvements, and support data-driven business decisions.

Link:

Thank you so much for reading my project.  I will be happy to receive your feedback and opinion about the project.

Link to Project Post on LinkedIn