First-party email analytics for Rails
🔥 For web and native app analytics, check out Ahoy
🚄 To manage unsubscribes, check out Mailkick
Add this line to your application’s Gemfile:
gem 'ahoy_email'And run the generator. This creates a model to store messages.
rails generate ahoy_email:install
rails db:migrateThere are three main features:
Ahoy Email creates an Ahoy::Message record for each email sent by default. You can disable history for a mailer:
class CouponMailer < ApplicationMailer
track message: false # use only/except to limit actions
endOr by default:
AhoyEmail.default_options[:message] = falseAhoy Email records the user a message is sent to - not just the email address. This gives you a history of messages for each user, even if they change addresses.
By default, Ahoy tries @user then params[:user] then User.find_by(email: message.to) to find the user.
You can pass a specific user with:
class CouponMailer < ApplicationMailer
track user: -> { params[:some_user] }
endThe user association is polymorphic, so use it with any model.
To get all messages sent to a user, add an association:
class User < ApplicationRecord
has_many :messages, class_name: "Ahoy::Message", as: :user
endAnd run:
user.messagesRecord extra attributes on the Ahoy::Message model.
Create a migration to add extra attributes to the ahoy_messages table. For example:
class AddCouponIdToAhoyMessages < ActiveRecord::Migration[6.1]
def change
add_column :ahoy_messages, :coupon_id, :integer
end
endThen use:
class CouponMailer < ApplicationMailer
track extra: {coupon_id: 1}
endYou can use a proc as well.
class CouponMailer < ApplicationMailer
track extra: -> { {coupon_id: params[:coupon].id} }
endUse UTM tagging to attribute a conversion (like an order) to an email campaign. If you use Ahoy for web analytics:
- Send an email with UTM parameters
- When a user visits the site, Ahoy will create a visit with the UTM parameters
- When a user orders, the visit will be associated with the order (if configured)
Add UTM parameters to links with:
class CouponMailer < ApplicationMailer
track utm_params: true # use only/except to limit actions
endThe defaults are:
utm_medium-emailutm_source- the mailer name likecoupon_mailerutm_campaign- the mailer action likeoffer
You can customize them with:
class CouponMailer < ApplicationMailer
track utm_params: true, utm_campaign: -> { "coupon#{params[:coupon].id}" }
endSkip specific links with:
<%= link_to "Go", some_url, data: {skip_utm_params: true} %>While it’s nice to get feedback on the performance of your emails, we discourage the use of open tracking. If you do decide to use open or click tracking, be sure to get consent from your users and consider a short retention period. Check out this article for more best practices.
Create a migration with:
class AddTokenToAhoyMessages < ActiveRecord::Migration[6.1]
def change
add_column :ahoy_messages, :token, :string
add_index :ahoy_messages, :token
# for opens
add_column :ahoy_messages, :opened_at, :timestamp
# for clicks
add_column :ahoy_messages, :clicked_at, :timestamp
end
endCreate an initializer config/initializers/ahoy_email.rb with:
AhoyEmail.api = trueAnd add to mailers you want to track:
class CouponMailer < ApplicationMailer
track open: true, click: true
endUse only and except to limit actions
class CouponMailer < ApplicationMailer
track click: true, only: [:welcome]
endOr make it conditional
class CouponMailer < ApplicationMailer
track click: -> { params[:user].opted_in? }
endFor opens, an invisible pixel is added right before the </body> tag in HTML emails. If the recipient has images enabled in their email client, the pixel is loaded and the open time recorded.
For clicks, a redirect is added to links to track clicks in HTML emails.
https://chartkick.com
becomes
https://yoursite.com/ahoy/messages/rAnDoMtOkEn/click?url=https%3A%2F%2Fchartkick.com&signature=...
A signature is added to prevent open redirects.
Skip specific links with:
<%= link_to "Go", some_url, data: {skip_click: true} %>By default, unsubscribe links are excluded. To change this, use:
AhoyEmail.default_options[:unsubscribe_links] = trueYou can specify the domain to use with:
AhoyEmail.default_options[:url_options] = {host: "mydomain.com"}Subscribe to open and click events by adding to the initializer:
class EmailSubscriber
def open(event)
# your code
end
def click(event)
# your code
end
end
AhoyEmail.subscribers << EmailSubscriber.newHere’s an example if you use Ahoy to track visits and events:
class EmailSubscriber
def open(event)
event[:controller].ahoy.track "Email opened", message_id: event[:message].id
end
def click(event)
event[:controller].ahoy.track "Email clicked", message_id: event[:message].id, url: event[:url]
end
end
AhoyEmail.subscribers << EmailSubscriber.newWe recommend encrypting the to field (as well as the subject if it’s sensitive). Lockbox is great for this. Use Blind Index if you need to query by the to field.
Create app/models/ahoy/message.rb with:
class Ahoy::Message < ApplicationRecord
self.table_name = "ahoy_messages"
belongs_to :user, polymorphic: true, optional: true
encrypts :to
blind_index :to
endDelete older data with:
Ahoy::Message.where("created_at < ?", 1.year.ago).in_batches.delete_allDelete data for a specific user with:
Ahoy::Message.where(user_id: 1).in_batches.delete_allSet global options
AhoyEmail.default_options[:user] = -> { params[:admin] }Use a different model
AhoyEmail.message_model = -> { UserMessage }Or fully customize how messages are tracked
AhoyEmail.track_method = lambda do |data|
# your code
endIf you prefer to use Mongoid instead of Active Record, create app/models/ahoy/message.rb with:
class Ahoy::Message
include Mongoid::Document
belongs_to :user, polymorphic: true, optional: true, index: true
field :to, type: String
field :mailer, type: String
field :subject, type: String
field :sent_at, type: Time
endView the changelog
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features
To get started with development:
git clone https://github.com/ankane/ahoy_email.git
cd ahoy_email
bundle install
bundle exec rake test