A pixel for Quora tracking

How to measure user retention with Cohort Charts on Forest Admin

Blind guessing can’t help you prevent customer churn. Instead, you should rely on Cohort Analysis that gives you a deeper understanding of your customers and helps you answer the most pressing questions. Read how to do it with Forest Admin.

How to measure user retention with Cohort Charts on Forest Admin

Have you recently launched a new product or a feature? Congratulations! Most likely, you’re now regularly checking the number of new downloads, and celebrating each time this number hits your KPIs.

Growth, however, can be a vanity metric. When only growth is measured, having lots of new sign-ups can cover up the unpleasant fact that users download the app and then never come back. Does it mean you shouldn’t track growth? Absolutely not. But you need to keep a close eye on retention and measure user engagement over time. Performing a Cohort Analysis is the most insightful method of doing that and now you can easily build Cohort Charts on Forest Admin.

A laptop on a sofa showing various type of charts.

What is a Cohort Analysis?


Cohort Analysis separates growth and engagement metrics by breaking a group of all users into smaller units that share characteristics. To measure retention, cohorts are usually segmented by signup dates, and they allow business owners and CMOs to understand the customer lifecycle. A clear Cohort Chart shows how many users are engaging with the app, when do they start losing interest and when most of them churn.

The most common use cases for a Cohort Analysis

Although a need for measuring user retention is the most common reason to perform a Cohort Analysis, there are other insights you can obtain through it, for example:

  • To measure the quality of marketing efforts like webinars by analysing how many leads turn into loyal returning customers.
  • To realize whether your business is affected by seasonality.
  • To track if the website and product updates impact user acquisition and retention.
  • To prevent customer churn by monitoring when it happens in most cases.
  • To monitor sales cycle — from making the first contact with a prospect, through a meeting or meetings, onboarding, to making a deal.


How to perform a cohort analysis to track customer retention rate with Forest Admin


Cohort charts are one of the various types of charts supported by Forest Admin. Some of them are natively included and can be easily added and managed in the Layout Editor, either in the Dashboard or Analytics tab.

  • Single value (the number of customers, MRR, etc.)
  • Repartition (the number of customers by countries, paid VS free, etc.)
  • Time-based (e.g. the number of signups per month)
  • Percentage (e.g. the percentage of paying customers)
  • Objective (e.g. orders passed per year VS another objective)
  • Leaderboard (e.g. the most engaged users)

If you’re going to build one of the above-mentioned charts in Forest Admin, check this step-by-step tutorial on how to create charts.

An example of a dashboard built on Forest Admin including a few different types of charts.
An example of a dashboard built on Forest Admin including a few different types of charts.

Building more advanced API-based charts, such as Cohort Charts, is also straightforward. With Smart Actions, Forest Admin allows you to code a chart containing exactly the data you want, and to have it displayed exactly the way you want. To learn more, read the tutorial on how to create Smart Charts.

Before you start building your Cohort Charts, we advise you to perform these steps:

  • Make sure your data is in order. In Forest Admin, your raw data is pulled from a database and displayed as a clear cohort graph.
  • Create cohort identifiers: You need to define the groups of users, for example by the day they registered or made a purchase.
  • Calculate lifecycle stages: You need to attribute the amount of time between events (e.g. weeks).

Then, you can follow this example to create your Cohort Chart:

Template tab

<div class="c-smart-chart">
 <div id="demo"></div>
</div>

Component tab

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { loadExternalStyle, loadExternalJavascript } from 'client/utils/smart-view-utils';
function isValidHex(color){
    return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(color);
}
function shadeColor(color, percent) { //#
    color = isValidHex(color) ? color : "#3f83a3"; //handling null color;
    percent = 1.0 - Math.ceil(percent / 10) / 10;
    var f=parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF;
    return "#"+(0x1000000+(Math.round((t-R)*p)+R)*0x10000+(Math.round((t-G)*p)+G)*0x100+(Math.round((t-B)*p)+B)).toString(16).slice(1);
}
export default class extends Component {
  @service lianaServerFetch;
  @tracked loaging = true;
  constructor(...args) {
    super(...args);
    this.loadPlugin();
  }
  async loadPlugin() {
    await loadExternalJavascript('https://d3js.org/d3.v6.min.js');
    this.loaging = false;
    this.renderChart()
  }
  getRows(data){
    var rows = [];
    var keys = Object.keys(data);
    var days = [];
    var percentDays = [];
    for(var key in keys){
        if(data.hasOwnProperty(keys[key])) {
            days = data[keys[key]];
            percentDays.push(keys[key]);
            for(var i = 0; i < days.length; i++){
                percentDays.push(i > 0 ? Math.round((days[i]/days[0] * 100) * 100) / 100 : days[i]);
            }
            rows.push(percentDays);
            percentDays = [];
        }
      }
    return rows;
  }
  @action
  async renderChart() {
    // To fetch data from the backend
    // const data = await this.lianaServerFetch.fetch('/forest/custom-route', {});
    const options = {
      data : {
          // You can use any data format, just change the getRows logic
          "May 3, 2021" : [79, 18, 16, 12, 16, 11, 7, 5],
          "May 10, 2021" : [168, 35, 28, 30, 24, 12, 10 ],
          "May 17, 2021" : [188, 42, 32, 34, 25, 18],
          "May 24, 2021" : [191, 42, 32, 28, 12],
          "May 31, 2021" : [191, 45, 34, 30],
          "June 7, 2021" : [184, 42, 32],
          "June 14, 2021" : [182, 44],
      },
      title : "Retention rates by weeks after signup"
    };
    var graphTitle = options.title || "Retention Graph";
    var data = options.data || null;
    const container = d3.select("#demo").append("div")
        .attr("class", "box");
    var header = container.append("div")
        .attr("class", "box-header with-border");
    var title = header.append("p")
        .attr("class", "box-title")
        .text(graphTitle);
    var body = container.append("div")
        .attr("class", "box-body");
    var table = body.append("table")
        .attr("class", "table table-bordered text-center");
    var headData = ["Cohort", "New users", "1", "2", "3", "4", "5", "6", "7"];
    var tHead = table.append("thead")
        .append("tr")
        .attr("class", "retention-thead")
        .selectAll("td")
        .data(headData)
        .enter()
        .append("td")
        .attr("class", function (d, i) {
            if(i == 0)
                return "retention-date"
            else
                return "days"
        })
        .text(function (d) {
            return d;
        });
    var rowsData = this.getRows(data);
    var tBody = table.append("tbody");
    var rows = tBody.selectAll("tr")
        .data(rowsData).enter()
        .append("tr");
    var cells = rows.selectAll("td")
        .data(function (row, i) {
            return row;
        }).enter()
        .append("td")
        .attr("class", function (d, i) {
            if(i == 0)
                return "retention-date";
            else
                return "days";
        })
        .attr("style", function (d, i) {
            if(i > 1)
            return "background-color :" + shadeColor("#00c4b4", d);
        })
        .append("div")
        .attr("data-toggle", "tooltip")
        .text(function (d, i) {
            return d + (i > 1 ? "%" : "");
        });
  }
}

In this snippet, we have chosen the D3js library but of course, you are free to choose any other library.

Now, you need to determine the style of your Cohort Chart, and you can also follow this example:

Style tab

.c-smart-chart {
  display: flex;
  white-space: normal;
  bottom: 0;
  left: 0;
  right: 0;
  top: 0;
  background-color: var(--color-beta-surface);
}
.box{
  position:relative;
  border-radius:3px;
  background:#ffffff;
  width:100%;
}
.box-body{
  max-height:500px;
  overflow:auto;
  border-top-left-radius:0;
  border-top-right-radius:0;
  border-bottom-right-radius:3px;
  border-bottom-left-radius:3px;
}
.box-header{
  color:#444;
  display:block;
  padding:10px;
  position:relative
}
.box-header .box-title{
    display:inline-block;
    font-size:18px;
    margin:0;
    line-height:1;
}
.box-title{
    display:inline-block;font-size:18px;margin:0;line-height:1
}
.retention-thead, .retention-date{
    background-color: #cfcfcf;
    font-weight: 700;
    padding: 8px;
}
.days{
  cursor: pointer;
  padding: 8px;
  text-align: center;
}

The resulting chart will look similar to this one:

An example of a cohort chart in a Forest Admin dashboard.

It shows the number of users who signed up and the percentage of those engaging with the app over time.

Conclusion


Blind guessing can’t help you prevent customer churn. Instead, you should rely on Cohort Analysis that gives you a deeper understanding of your customers and helps you answer the most pressing questions, such as:

  • What is the point where most users churn?
  • When is the best time to re-engage with previously active users?
  • When is the best time to launch remarketing campaign?
  • How to improve the sales cycle?


Now, the next step is to fix what is causing the issues and retain loyal customers for long-term growth. Try doing it on Forest Admin for free. 🌲