Totalizer makes it easy for Ruby on Rails developers to report on Product and Engagement metrics.
By defining three metrics, Growth, Vanity and Key Activity, you can generate reports on Acquisition, Activity, Vanity, Activation, Engagement, Retention and Churn.
Metrics are only worthwhile if your team sees them so Totalizer includes notifiers for Slack and email.
Add this line to your application's Gemfile:
gem 'totalizer'
And then execute:
$ bundle
Or install it yourself as:
$ gem install totalizer
You need to define your Growth Metric and Key Activity Metric in order to use Totalizer. You can do this by creating a Totalizer initializer file in your Rails application:
# config/initializers/totalizer.rb
Totalizer.growth_metric = Totalizer::Metric.new model: User
Totalizer.vanity_metric = Totalizer::Metric.new model: Post
Totalizer.activity_metric = Totalizer::Metric.new model: Post, map: 'user_id'
The Growth Metric and the Key Activity Metric need to map to the same id to allow comparison.
A Metric is a calculation based on one of your models for a duration of time.
metric = Totalizer::Metric.new(model: User)
metric.value
#=> 10 (the number of records for the period)
metric.start
#=> 20 (the number of records before the period)
metric.finish
#=> 30 (the number of records at the end of the period)
metric.rate
#=> 0.5 (how much the number changed over the period)
You can pass the following parameters into the Metric:
model
(required): The Rails model class that Totalizer will query.date
: When to start measuring your records. Default isnow
.duration
: Duration (in days) to measure your records from. Must be an integer. Default is7
.filter
: Write a custom query to determine which records to use in calculation. For example to find all users who created a public response you could pass in:filter: "is_public = true"
.map
: Which field to map records on. For example, to find unique users who did a response you could pass in:map: 'user_id'
. Default isid
.
By default, running the Totalizer rake tasks will output the metrics to your logs
You can configure Totalizer to email metrics using ActionMailer, just ensure you have ActionMailer configured.
To do this add the following lines to your initializer:
Totalizer.notifiers = {
action_mailer: {
from: %{"notifier" <notifier@example.com>},
to: %w{team@example.com}
}
}
You can also optionally include: subject
.
If you are using mandrill_mailer gem in your application then you can configure Totalizer to email metrics using MandrillMailer, just ensure you have MandrillMailer configured.
To do this add the following lines to your initializer:
Totalizer.notifiers = {
mandrill_mailer: {
from: %{"notifier" <notifier@example.com>},
to: %w{team@example.com}
}
}
You can also optionally include: subject
.
You can configure Totalizer to post to Slack by including the slack-notifier gem in your Gemfile.
gem 'slack-notifier'
Then add the following lines to your initializer:
Totalizer.notifiers = {
slack: {
webhook_url: ENV['SLACK_WEBHOOK_URL'],
channel: ENV['SLACK_CHANNEL']
}
}
You can also optionally include: username
, icon_emoji
and color
.
Totalizer comes with two rake tasks you can run.
You don’t need to review every metric every day, but it’s good practice to monitor growth and activity on a daily basis so you can respond to any spikes or dips.
Totalizer generates your Acquisition and Activity metrics for the previous day and the previous week.
$ rake totalizer:daily
This will generate the following report:
Acquisition
Signed up this period (with rate of change)
Yesterday: 20 (∆ 10%)
Vanity
Total this period (with rate of change)
Yesterday: 15 (∆ 5%)
Activity
Key activities this period (with rate of change)
Yesterday: 60 (∆ 9%)
Every week it's important to review your important metrics to ensure you are trending in the right direction.
Totalizer generates your Acquisition, Vanity, Activity, Activation, Engagement, Retention and Churn for the previous week and previous month.
$ rake totalizer:weekly
This will generate the following report:
Acquisition
Signed up this period (with rate of change)
Last 7 days: 77 (∆ 7%)
Last 30 days: 444 (∆ 10%)
Vanity
Total this period (with rate of change)
Last 7 days: 92 (∆ 4%)
Last 30 days: 412 (∆ 5%)
Activity
Key activities this period (with rate of change)
Last 7 days: 120 (∆ 8%)
Last 30 days: 250 (∆ 6%)
Activation
Created this period and did key activity
Last 7 days: 77 → 58 (75.32%)
Last 30 days: 444 → 355 (79.95%)
Engagement
Created before this period and did key activity this period
Last 7 days: 56.18% (150/267)
Last 30 days: 34.14% (210/615)
Retention
Did key activity the previous period and again this period
Last 7 days: 61.19% (134/219)
Last 30 days: 69.42% (722/1040)
Churn
Did key activity last period but not this period over the total who did key activity last period plus new users
Last 7 days: 6.21% (9/145)
Last 30 days: 3.29% (34/1032)
To change the descriptions for each metric you can add the following to your initializer:
Totalizer.descriptions.acquisition = "New users"
Totalizer.descriptions.vanity = "Posts created"
Totalizer.descriptions.activity = "Users who created post"
Totalizer.descriptions.engagement = "Existing users who created post"
Totalizer.descriptions.retention = "Existing user who created post again"
Totalizer.descriptions.churn = "Existing user who did not do key activity"
You can also run a single rake task every day which will run execute the daily task each time and execute the weekly task on a defined week day which by default is Monday.
This is handy for things like Heroku Scheduler where you can only schedule daily tasks.
$ rake totalizer:combined
To change the week day add the following line to your initializer:
Totalizer.weekly_day = 0 #(0-6, Sunday is zero)
In addition to Metric, you can also use the following underlying objects.
The Totalizer Factory is what generates the Acquisition, Activation, Engagement, Retention and Churn reports.
By defining one growth metric, like new user creation, and one key activity metric, like creating a post, you can generate all five reports.
To create a Factory just use this in your Rails application:
growth_metric = Totalizer::Metric.new(model: User)
activity_metric = Totalizer::Metric.new(model: Project, map: 'user_id')
factory = Totalizer::Factory.new(growth_metric: growth_metric, activity_metric: activity_metric)
This will return a message object for each calculation.
You can pass the following parameters into the Factory:
growth_metric
: (required) a Totalizer metric representing growth, usually a User model.activity_metric
: (required) a Totalizer metric representing the key activity a user should do within your application.date
: When to start measuring your records from. Must be a DateTime. Default isnow
.duration
: Duration (in days) to measure your records. Must be an integer. Default is7
.
growth_metric = Totalizer::Metric.new(model: User)
activity_metric = Totalizer::Metric.new(model: Project, map: 'user_id')
factory = Totalizer::Factory.new(growth_metric: growth_metric, activity_metric: activity_metric)
acquisition = factory.acquisition
acquisition.title
#=> "Acquisition"
acquisition.pretext
#=> "Signed up in the last 7 days"
acquisition.text
#=> "74 (Growth rate: 10%)"
growth_metric = Totalizer::Metric.new(model: User)
activity_metric = Totalizer::Metric.new(model: Project, map: 'user_id')
factory = Totalizer::Factory.new(growth_metric: growth_metric, activity_metric: activity_metric)
activation = factory.activation
activation.title
#=> "Activation"
activation.pretext
#=> "Signed up in the last 7 days and did key activity"
activation.text
#=> "63/90 (Conversion rate: 70%)"
growth_metric = Totalizer::Metric.new(model: User)
activity_metric = Totalizer::Metric.new(model: Project, map: 'user_id')
factory = Totalizer::Factory.new(growth_metric: growth_metric, activity_metric: activity_metric)
engagement = factory.engagement
engagement.title
#=> "Engagement"
retention.pretext
#=> "Signed up more than 7 days ago and did key activity in the last 7 days"
engagement.text
#=> "42/350 (Engagement rate: 12%)"
growth_metric = Totalizer::Metric.new(model: User)
activity_metric = Totalizer::Metric.new(model: Project, map: 'user_id')
factory = Totalizer::Factory.new(growth_metric: growth_metric, activity_metric: activity_metric)
retention = factory.retention
retention.title
#=> "Retention"
retention.pretext
#=> "Did key activity more than 7 days ago and again in the last 7 days"
retention.text
#=> "42/75 56%"
growth_metric = Totalizer::Metric.new(model: User)
activity_metric = Totalizer::Metric.new(model: Project, map: 'user_id')
factory = Totalizer::Factory.new(growth_metric: growth_metric, activity_metric: activity_metric)
churn = factory.churn
churn.title
#=> "Churn"
churn.pretext
#=> "Acquired more than 7 days ago and did not do key activity in last 7 days over total acquired"
churn.text
#=> "33/75 44%"
A step allows you to easily compare two sets of ids to see who converted.
To create a Step just use this in your Rails application:
first_metric = Totalizer::Metric.new(model: User)
second_metric = Totalizer::Metric.new(model: Post, map: 'user_id')
step = Totalizer::Step.new first_step_metric.ids, second_step_metric.ids
step.start
#=> 20 (the number of records that started the step)
step.finish
#=> 10 (the number of records that finished the step)
step.rate
#=> 0.5 (the rate that converted from start to finish)
step.ids
#=> [1,2,3,4,5,6,7,8,9,10] (the ids of the records that finished)
You can use the result of one step to feed into another step. Continuing on the example above, you could do the following:
third_metric = Totalizer::Metric.new(model: Comment, map: 'user_id')
next_step = Totalizer::Step.new step.ids, third_metric.ids
You can also report on Acquisition, Activity, Activation, Retention, Engagement and Churn yourself without using a Factory.
acquisition = Totalizer::Metric.new(model: User, duration: 7)
acquisition.value
#=> 7
acquisition.rate
#=> 10
activity = Totalizer::Metric.new(model: Post, map: 'user_id')
acquisition.value
#=> 20
acquisition.rate
#=> 5
sign_up = Totalizer::Metric.new(model: User, duration: 7)
do_action = Totalizer::Metric.new(model: Post, map: 'user_id')
activation = Totalizer::Step.new sign_up.ids, do_action.ids
activation.start
#=> 10
activation.finish
#=> 5
activation.rate
#=> 0.5
sign_up = Totalizer::Metric.new(model: User, duration: 7)
do_action = Totalizer::Metric.new(model: Post, map: 'user_id')
existing_active = (sign_up.start_ids & do_action.ids).size
#=> 14
"(existing_active.to_f / sign_up.start.to_f * 100).round(0)}%"
#=> 12%
this_week = Totalizer::Metric.new(model: Post, map: 'user_id')
last_week = Totalizer::Metric.new(model: Post, map: 'user_id')
retention = Totalizer::Step.new this_week.ids, last_week.ids
retention.start
#=> 14
retention.finish
#=> 7
retention.rate
#=> 0.5
"#{(retention.rate * 100).round(0)}%"
#=> 50%
acquisition = Totalizer::Metric.new(model: User, duration: 30)
active_last_period = Totalizer::Metric.new(model: Post, map: 'user_id', duration: 30, date: 30.days.ago)
active_this_period = Totalizer::Metric.new(model: Post, map: 'user_id', duration: 30)
new_and_existing_customers = acquisition.end_value
#=> 100
lost_existing_customers = (active_last_period.ids - active_this_period.ids).size
#=> 5
lost_existing_customers.to_f / (new_and_existing_customers - lost_existing_customers).to_f
#=> 0.04
- Fork it ( https://github.com/micdijkstra/totalizer/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
- Update the version number in
lib/totalizer/version.rb
- Run
gem build totalizer.gemspec
- Run
gem push totalizer-0.0.X.gem
The MIT License (MIT)
Copyright (c) 2016 Michael Dijkstra
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.