f in x
Cohort Analysis for Retention and Churn — Metrics That Make Your E-commerce Profitable
> cd .. / HUB_EDITORIALE
Analisi dei dati e metriche

Cohort Analysis for Retention and Churn — Metrics That Make Your E-commerce Profitable

[2026-06-27] Author: Ing. Calogero Bono
Zenithby Meteora Web Il sistema operativo della tua attività. Social, clienti, prenotazioni e fatture in un'unica piattaforma. Palestre, barber, professionisti. Scopri Zenith Demo gratis · senza carta

Why your e-commerce isn't growing even with many new customers?

The metric you see in Google Analytics — "new users" — is the most deceptive. If you bring 1000 new clients every month but 85% never return, you're spending to fill a leaky bucket. We, at Meteora Web, see this every day in the projects that land on our table: inflated acquisition budgets, eroding margins, and no one looking at customer lifetime value.

Cohort analysis is the tool that separates those who understand retention from those who just count vanity numbers. After running the ERP system of a clothing retailer internally — where season margins depended entirely on repeat purchases — we learned that without cohorts you can't govern a business.

What is cohort analysis and why is it crucial for retention?

A cohort is a group of users who perform a specific action within a defined time window. The most common: cohort by first purchase date. Take all customers who first bought in January 2026, and track how many come back in February, March, April, etc.

The difference from aggregate metrics? You look at longitudinal behavior, not averages. Example: your December might have 1000 purchases, but if they're all from new customers who never return, you'll crash the next month. With cohorts you immediately see that 30-day retention is at 10%.

Sponsored Protocol

Meta Ads and Google Ads give you 7-day ROAS. But that number doesn't tell you about loyalty. We always start with the question: "What is a customer worth at 90 days?" — because that's where you begin to understand whether your ad spend makes sense.

How to calculate cohort retention with real data?

Assume an orders table with customer_id, order_date, amount. To calculate monthly cohort retention:

WITH first_order AS (
  SELECT 
    customer_id, 
    MIN(DATE(order_date)) AS first_date
  FROM orders
  GROUP BY customer_id
),
cohorts AS (
  SELECT 
    f.customer_id,
    DATE_FORMAT(f.first_date, '%Y-%m') AS cohort_month,
    TIMESTAMPDIFF(MONTH, f.first_date, o.order_date) AS order_month
  FROM orders o
  JOIN first_order f ON o.customer_id = f.customer_id
)
SELECT 
  cohort_month,
  COUNT(DISTINCT customer_id) AS total_customers,
  SUM(CASE WHEN order_month = 0 THEN 1 ELSE 0 END) AS month_0,
  SUM(CASE WHEN order_month = 1 THEN 1 ELSE 0 END) AS month_1,
  SUM(CASE WHEN order_month = 2 THEN 1 ELSE 0 END) AS month_2,
  SUM(CASE WHEN order_month = 3 THEN 1 ELSE 0 END) AS month_3
FROM cohorts
GROUP BY cohort_month
ORDER BY cohort_month;

The result: a table with rows per cohort and columns per period. Column month_0 is the first purchase (always 100% implied retention). To get retention rate, divide each column by total customers of that cohort.

Sponsored Protocol

Real example: if the January cohort has 500 customers and in March (month_2) 75 return, the 60-day retention is 15%. If by May of the same year it drops to 5%, you have a structural problem.

How to interpret results to reduce churn?

Three common scenarios we encounter:

  • High initial retention but drop after 90 days → your product is good but you lack a reactivation strategy. Emails, personalized offers, loyalty programs.
  • Low retention from the first month → you're likely attracting the wrong customers. Revise ad targeting and landing pages.
  • Recent cohorts worse than older ones → something changed (pricing, UX, competition). Check if the latest site update slowed loading or if you changed shipping provider.

We worked with a clothing brand that saw 30-day retention drop from 28% to 12% after a WooCommerce theme change. Reverting the change brought it back to 28%. Cohort is an early indicator — don't wait for the annual balance sheet to spot the problem.

Sponsored Protocol

What concrete actions based on cohort analysis?

Here's what to do now, immediately, ordered by impact:

  1. Calculate 30, 60, 90-day retention for each monthly cohort. If you don't have structured data, use Google Analytics 4 (Cohort Exploration report) or tools like Mixpanel. But your own database is the cleanest source.
  2. Compare cohorts by acquisition channel. Add a campaign column. If the Google Ads cohort has 20% retention and the referral cohort 35%, shift budget.
  3. Segment by average order value. Do customers who spend over €100 have better retention? Focus upsell on low-value ones.
  4. Set an alert: if 60-day retention drops below 15% (varies by industry, but a starting point for fashion/accessories e-commerce), trigger a customer journey review.

To dive deeper into data-driven metrics across the entire funnel, read our main article: Analytics and Data-Driven Marketing — The Definitive Pillar (link to English version if available).

Useful tools for cohort analysis — from free to advanced

You can start with a Google Sheet and an SQL query on a dump of your orders. Or use dedicated tools:

Sponsored Protocol

  • Google Analytics 4: Exploration > Cohort technique. Limitation: only events, not easily custom transactions.
  • Metabase / Superset: SQL-based dashboards for daily cohort views.
  • Python (pandas): If you have a data science stack, the snippet below gives a ready pivot table.
import pandas as pd
from datetime import timedelta

df = pd.read_sql("SELECT customer_id, order_date FROM orders", connection)
df['first_date'] = df.groupby('customer_id')['order_date'].transform('min')
df['cohort_month'] = df['first_date'].dt.to_period('M')
df['order_month'] = ((df['order_date'] - df['first_date']) / timedelta(days=30)).astype(int)

cohort = df.groupby(['cohort_month', 'order_month']).agg(unique_customers=('customer_id', 'nunique')).reset_index()
cohort_pivot = cohort.pivot(index='cohort_month', columns='order_month', values='unique_customers')
print(cohort_pivot)

Common mistakes we see in projects — and how to avoid them

1. Confusing cohort with demographic segment. A cohort is temporal, not by age/gender. Want to know if March-acquired customers behave like October ones? Fine, but date-based cohort is the foundation.

Sponsored Protocol

2. Not normalizing. If you have 1000 customers in January and 500 in June, absolute numbers tell you nothing. Always use percentages.

3. Forgetting seasonality. A December (Christmas) cohort will have different retention from June. Don't compare different months without context. Compare same month across years.

4. Ignoring economic value. Retention alone isn't enough. A returning customer who spends $10 is different from one spending $200. Also calculate cumulative value per cohort (CAC vs LTV).

For further reading on analysis tools, check official GA4 cohort documentation or Mixpanel's guide to cohort analysis.

What to do now

Three immediate actions for your business:

  1. Export your order list from the last 12 months (at least).
  2. Calculate 30, 60, 90-day retention for each monthly cohort using SQL, Python, or GA4.
  3. If 90-day retention is below 20% (Italian e-commerce fashion average), you have a retention problem to fix urgently. Contact us if you want a free data check.

Owning control of your data — without lifetime fees for proprietary platforms — is the only way to do serious data-driven marketing. We at Meteora Web have been doing this for 8 years, every day.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere Informatico, co-fondatore di Meteora Web. Esperto in architetture software, sicurezza informatica e sviluppo sistemi scalabili.
[ Read Full Dossier ]

> METEORA_WEB // DIGITAL AGENCY

We build the digital presence your business deserves.

Websites, social media, online advertising, e-commerce and high-performance hosting, engineered with method by computer engineers in Sciacca, for all of Italy.

> MW_JOURNAL

> READ_ALL()