The problem
Every SaaS app eventually needs to answer the same questions:
- Which features do my users actually use?
- Who are my most active users?
- When did a user last do something meaningful?
- Which users are going inactive?
The typical answer is "add Mixpanel" or "set up Segment." But that means:
- Sending your user data to a third party
- Paying for another service
- Adding a JS snippet
- Learning another dashboard
For most Rails apps, this is overkill. The data you need is already in your database.
What I built
rails-persona is a Ruby gem that adds model-level behavioral analytics directly to your ActiveRecord models. No external services, no JS, no cookies — just your own database.
class User < ApplicationRecord
include Persona::Trackable
persona do
track :login
track :export_report
track :view_dashboard
track :upgrade_plan
end
end
Then track actions anywhere in your app:
current_user.track!(:login)
current_user.track!(:upgrade_plan, metadata: { plan: "pro", amount: 49 })
And query behavior instantly:
user.most_frequent_action # => :login
user.inactive_since?(30) # => false
user.persona_summary # => { login: 42, export_report: 5 }
user.daily_activity(7) # => { "2024-05-28" => 4, "2024-05-29" => 7 }
user.peak_hour # => 14 (2pm)
User.persona_leaderboard # => top 10 most active users
How it's different from ahoy
ahoy is a great gem but it solves a different problem — it tracks HTTP visits and page views. rails-persona tracks what users do inside your app at the model level.
| ahoy | rails-persona | |
|---|---|---|
| Focus | HTTP visits + page views | Model actions + behavior |
| Needs JS | Yes | No |
| Async built-in | No | Yes (Sidekiq) |
| Bulk tracking | No | Yes (insert_all!) |
| Class leaderboards | No | Yes |
| Works on any model | Awkward | First-class |
Key features
Async tracking — never slow down a request:
Persona.configure do |config|
config.async = true # fires a Sidekiq job
end
Bulk tracking — uses insert_all! under the hood:
user.bulk_track!([:login, :view_dashboard, :export_report])
Open tracking — skip the whitelist entirely:
persona do
open_tracking! # any string is valid
end
Data pruning — keep your DB clean:
Persona.configure do |config|
config.max_events_per_record = 500
config.auto_prune_after_days = 90
end
Works on any model — not just User:
class Post < ApplicationRecord
include Persona::Trackable
persona do
track :viewed
track :shared
track :bookmarked
end
end
Post.persona_class_summary # => { viewed: 50_420, shared: 890 }
Installation
# Gemfile
gem "rails-persona"
bundle install
rails db:migrate
Why I built this
I was the sole engineer on a production SaaS called CinnaLab PRM — an AI-powered Partner Relationship Management platform. I kept wanting to know things like "which users are using the partner portal vs ignoring it?" and "who's about to churn based on inactivity?"
I didn't want to set up Mixpanel for an internal SaaS. I just wanted to query my own database. rails-persona is what I wish had existed.
Links
- GitHub: github.com/sghani001/rails-persona
- RubyGems: rubygems.org/gems/rails-persona
If you try it, I'd love feedback — open an issue or leave a comment below!
Top comments (0)