How to Create a Cohort View in Odoo 18
By Braincuber Team
Published on January 16, 2026
Odoo ships with a rich set of visualization tools—lists, kanbans, graphs, pivots. But when you need to understand how groups of records behave over time, the Cohort View stands apart. It's designed specifically for retention analysis: tracking how a "cohort" (a group defined by a common start date) evolves through subsequent time periods.
Think subscription churn rates, employee tenure patterns, or project completion timelines. The cohort view transforms raw data into a time-based matrix that instantly reveals trends you'd miss in standard reports. This tutorial walks you through building a custom cohort view from scratch—complete with the Python model, security rules, and XML definitions.
What is a Cohort View? A cohort view groups records by their creation date (or any date field) and tracks a specific metric across time intervals (days, weeks, months). It's ideal for answering questions like: "Of the employees who joined in January, how many remained active by March?"
Why Use Cohort Analysis?
Trend Detection
Spot patterns across time periods that aggregate reports hide. See if retention improves or worsens month-over-month.
Lifecycle Tracking
Understand how entities (customers, employees, projects) progress through stages over their lifecycle.
Churn Analysis
Calculate drop-off rates between periods. Perfect for subscription models or workforce retention studies.
Data-Driven Decisions
Base business decisions on actual behavior patterns rather than single-point snapshots.
Prerequisites
- Odoo 18 development environment
- Custom module structure ready
- Basic understanding of Odoo models and views
- The
web_cohortmodule (included in Odoo Enterprise, or available as community addon)
Important: The cohort view requires the web_cohort module. Add it to your module's dependencies in __manifest__.py.
Step 1: Create the Python Model
We'll build a Project Milestone tracker as our example. Each milestone has a start date (when created) and a completion date—perfect for cohort analysis showing how quickly milestones get completed across different project batches.
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class ProjectMilestone(models.Model):
_name = 'project.milestone'
_description = 'Project Milestone Tracker'
_rec_name = 'name'
_order = 'create_date desc'
name = fields.Char(string="Milestone", required=True)
project_id = fields.Many2one('project.project', string="Project", required=True)
assigned_to = fields.Many2one('res.users', string="Assigned To", default=lambda self: self.env.user)
# Dates for cohort analysis
start_date = fields.Date(string="Start Date", default=fields.Date.today, required=True)
completion_date = fields.Date(string="Completion Date")
state = fields.Selection([
('draft', 'Draft'),
('in_progress', 'In Progress'),
('completed', 'Completed'),
('cancelled', 'Cancelled')
], default='draft', string="Status")
priority = fields.Selection([
('0', 'Low'),
('1', 'Normal'),
('2', 'High'),
('3', 'Critical')
], default='1', string="Priority")
notes = fields.Text(string="Notes")
The key fields for cohort analysis are start_date (when the milestone begins) and completion_date (when it's finished). The cohort view will group milestones by their start date and show how many get completed over time.
Step 2: Configure Security Access
Create the access control file to allow users to interact with your model:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_project_milestone_user,project.milestone.user,model_project_milestone,base.group_user,1,1,1,0 access_project_milestone_manager,project.milestone.manager,model_project_milestone,project.group_project_manager,1,1,1,1
Step 3: Define the Cohort View
Now for the main event—the XML view definition. The cohort tag accepts several key attributes:
date_start— The field that defines when a record "enters" the cohort (usually creation date)date_stop— The field that defines when the record reaches its end state (completion, cancellation, etc.)interval— Time granularity:day,week,month, oryearmode— Eitherchurn(shows drop-off) orretention(shows persistence)
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Action Window -->
<record id="action_project_milestone" model="ir.actions.act_window">
<field name="name">Project Milestones</field>
<field name="res_model">project.milestone</field>
<field name="view_mode">list,form,cohort</field>
<field name="context">{'search_default_my_milestones': 1}</field>
</record>
<!-- List View -->
<record id="view_project_milestone_list" model="ir.ui.view">
<field name="name">project.milestone.list</field>
<field name="model">project.milestone</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
<field name="project_id"/>
<field name="assigned_to"/>
<field name="start_date"/>
<field name="completion_date"/>
<field name="state" widget="badge"
decoration-success="state == 'completed'"
decoration-info="state == 'in_progress'"
decoration-muted="state == 'draft'"/>
</list>
</field>
</record>
<!-- Cohort View -->
<record id="view_project_milestone_cohort" model="ir.ui.view">
<field name="name">project.milestone.cohort</field>
<field name="model">project.milestone</field>
<field name="arch" type="xml">
<cohort string="Milestone Completion Analysis"
date_start="start_date"
date_stop="completion_date"
interval="week"
mode="churn"/>
</field>
</record>
<!-- Menu Item -->
<menuitem id="menu_project_milestone"
name="Milestones"
action="action_project_milestone"
parent="project.menu_main_pm"
sequence="15"/>
</odoo>
Step 4: Update the Manifest
{
'name': 'Project Milestone Tracker',
'version': '18.0.1.0.0',
'category': 'Project',
'summary': 'Track project milestones with cohort analysis',
'depends': ['project', 'web_cohort'],
'data': [
'security/ir.model.access.csv',
'views/project_milestone_views.xml',
],
'installable': True,
'application': False,
'license': 'LGPL-3',
}
Understanding the Cohort Output
After installing and adding some milestone records, the cohort view displays a matrix:
- Rows: Each row represents a cohort (milestones started in Week 1, Week 2, etc.)
- Columns: Each column shows the time elapsed since start (Week 0, Week 1, Week 2...)
- Cells: The percentage or count of records that reached
date_stopby that interval
Reading the Matrix: In churn mode, cells show what percentage "dropped off" (completed). In retention mode, cells show what percentage "remained" (still incomplete). The color intensity indicates the value—darker means higher churn/retention.
Best Practices
Cohort View Tips:
- Choose Meaningful Dates:
date_startshould represent a business event (order date, hire date), not justcreate_dateunless that's truly relevant. - Match Interval to Use Case: Use
dayfor short-cycle processes,monthfor subscriptions,yearfor long-term retention. - Filter Wisely: Add search filters to narrow cohorts (e.g., by project, department, product category).
- Combine with Pivot: Use cohort for pattern discovery, then pivot for deeper numeric analysis.
Conclusion
The cohort view transforms Odoo from a simple record keeper into a behavioral analytics platform. By tracking how groups evolve over time, you gain insights that static reports simply cannot provide. Whether you're analyzing customer churn, employee retention, or project velocity, the cohort view gives you the temporal dimension your data needs.
Key Takeaway: Add web_cohort to dependencies → Define a model with date_start and date_stop fields → Create a cohort view with interval and mode attributes → Analyze time-based patterns in your data.
