Ruby on Rails

PostHog makes it easy to get data about traffic and usage of your Ruby on Rails app. Integrating PostHog enables analytics, custom events capture, feature flags, and automatic exception tracking.

This guide walks you through integrating PostHog into your Rails app using the posthog-rails gem.

Beta: integration via LLM

Install PostHog for Rails in seconds with our wizard by running this prompt with LLM coding agents like Cursor and Bolt, or by running it in your terminal.

prompt
npx -y @posthog/wizard@latest --region us

Or, to integrate manually, continue with the rest of this guide.

Features

  • Automatic exception tracking – Captures unhandled and rescued exceptions
  • ActiveJob instrumentation – Tracks background job exceptions
  • User context – Automatically associates exceptions with the current user
  • Smart filtering – Excludes common Rails exceptions (404s, etc.) by default
  • Rails 7.0+ error reporter – Integrates with Rails' built-in error reporting

Installation

Add both gems to your Gemfile:

Gemfile
gem 'posthog-ruby'
gem 'posthog-rails'

Then run:

Terminal
bundle install

Generate the initializer

Run the install generator to create the PostHog initializer:

Terminal
rails generate posthog:install

This creates config/initializers/posthog.rb with sensible defaults and documentation.

Configuration

The generated initializer includes all available options:

config/initializers/posthog.rb
# Core PostHog client initialization
PostHog.init do |config|
# Required: Your PostHog API key
config.api_key = '<ph_project_api_key>'
# Optional: Your PostHog instance URL
config.host = 'https://us.i.posthog.com'
# Optional: Personal API key for feature flags
config.personal_api_key = 'phx_xxxxxxxxx'
# Error callback to detect misconfiguration
config.on_error = proc { |status, msg|
Rails.logger.error("PostHog error: #{msg}")
}
end
# Rails-specific configuration
PostHog::Rails.configure do |config|
config.auto_capture_exceptions = true # Enable automatic exception capture
config.report_rescued_exceptions = true # Report exceptions Rails rescues
config.auto_instrument_active_job = true # Instrument background jobs
config.capture_user_context = true # Include user info in exceptions
config.current_user_method = :current_user # Method to get current user
# Add additional exceptions to ignore
config.excluded_exceptions = ['MyCustomError']
end

You can find your project API key and instance address in your project settings.

Tip: Use Rails.application.credentials to avoid hardcoding API keys. First, add your keys and then reference them in your initializer:

Terminal
rails credentials:edit
config/credentials.yml.enc
posthog:
api_key: <ph_project_api_key>
host: https://us.i.posthog.com
personal_api_key: phx_xxxxxxxxx
config/initializers/posthog.rb
config.api_key = Rails.application.credentials.posthog[:api_key]
config.host = Rails.application.credentials.posthog[:host]
config.personal_api_key = Rails.application.credentials.posthog[:personal_api_key]

Capturing events

Track custom events anywhere in your Rails app:

Ruby
# Track an event
PostHog.capture(
distinct_id: current_user.id,
event: 'post_created',
properties: { title: @post.title }
)
# Identify a user
PostHog.identify(
distinct_id: current_user.id,
properties: {
email: current_user.email,
plan: current_user.plan
}
)

Error tracking

For full details on setting up error tracking with Rails, see our Rails error tracking installation guide.

Automatic exception tracking

When auto_capture_exceptions is enabled, exceptions are automatically captured:

Ruby
class PostsController < ApplicationController
def show
@post = Post.find(params[:id])
# Any exception here is automatically captured
end
end

Manual exception capture

You can also manually capture exceptions:

Ruby
PostHog.capture_exception(
exception,
current_user.id,
{ custom_property: 'value' }
)

Background job exceptions

When auto_instrument_active_job is enabled, ActiveJob exceptions are automatically captured with job context:

Ruby
class EmailJob < ApplicationJob
def perform(user_id)
user = User.find(user_id)
UserMailer.welcome(user).deliver_now
# Exceptions are automatically captured
end
end

Associating jobs with users

By default, PostHog extracts a distinct_id from job arguments by looking for a user_id key:

Ruby
# PostHog will automatically use options[:user_id] as the distinct_id
ProcessOrderJob.perform_later(order.id, user_id: current_user.id)

For more control, use the posthog_distinct_id class method:

Ruby
class SendWelcomeEmailJob < ApplicationJob
posthog_distinct_id ->(user, options) { user.id }
def perform(user, options = {})
UserMailer.welcome(user).deliver_now
end
end

Rails 7.0+ error reporter

PostHog integrates with Rails' built-in error reporting:

Ruby
# These errors are automatically sent to PostHog
Rails.error.handle do
# Code that might raise an error
end
Rails.error.record(exception, context: { user_id: current_user.id })

PostHog automatically extracts the user's distinct ID from user_id or distinct_id in the context hash.

User context

PostHog Rails automatically captures user information from your controllers. If your user method has a different name, configure it:

Ruby
PostHog::Rails.config.current_user_method = :logged_in_user

User ID extraction

By default, PostHog Rails auto-detects the user's distinct ID by trying these methods:

  1. posthog_distinct_id – Define this on your User model for full control
  2. distinct_id – Common analytics convention
  3. id – Standard ActiveRecord primary key

You can configure a specific method:

Ruby
PostHog::Rails.config.user_id_method = :email

Or define a method on your User model:

Ruby
class User < ApplicationRecord
def posthog_distinct_id
"user_#{id}" # or external_id, or any unique identifier
end
end

Excluded exceptions

The following exceptions are not reported by default (common 4xx errors):

  • AbstractController::ActionNotFound
  • ActionController::BadRequest
  • ActionController::InvalidAuthenticityToken
  • ActionController::RoutingError
  • ActionController::UnknownFormat
  • ActiveRecord::RecordNotFound

Add more with:

Ruby
PostHog::Rails.config.excluded_exceptions = ['MyException']

Feature flags

Use feature flags in your Rails app:

Ruby
class PostsController < ApplicationController
def show
if PostHog.is_feature_enabled('new-post-design', current_user.id)
render 'posts/show_new'
else
render 'posts/show'
end
end
end

For local evaluation, ensure you've set personal_api_key:

Ruby
config.personal_api_key = Rails.application.credentials.posthog[:personal_api_key]

See our Ruby SDK docs for details on local evaluation with Puma and Unicorn servers.

Testing

In your test environment, disable PostHog or use test mode:

config/environments/test.rb
PostHog.init do |config|
config.test_mode = true # Events are queued but not sent
end

Or in your specs:

spec/rails_helper.rb
RSpec.configure do |config|
config.before(:each) do
allow(PostHog).to receive(:capture)
end
end

Configuration reference

Core PostHog options

OptionTypeDefaultDescription
api_keyStringrequiredYour PostHog project API key
hostStringhttps://us.i.posthog.comPostHog instance URL
personal_api_keyStringnilFor feature flag evaluation
test_modeBooleanfalseDon't send events (for testing)
on_errorProcnilError callback

Rails-specific options

OptionTypeDefaultDescription
auto_capture_exceptionsBooleanfalseAutomatically capture exceptions
report_rescued_exceptionsBooleanfalseReport exceptions Rails rescues
auto_instrument_active_jobBooleanfalseInstrument ActiveJob
capture_user_contextBooleantrueInclude user info
current_user_methodSymbol:current_userController method for user
user_id_methodSymbolnilMethod to extract ID from user object
excluded_exceptionsArray[]Additional exceptions to ignore

Troubleshooting

Exceptions not being captured

  1. Verify PostHog is initialized:

    Ruby
    Rails.console
    > PostHog.initialized?
    => true
  2. Check your excluded exceptions list

  3. Verify middleware is installed:

    Ruby
    Rails.application.middleware

User context not working

  1. Verify current_user_method matches your controller method
  2. Check that the user object responds to posthog_distinct_id, distinct_id, or id
  3. If using a custom identifier, set PostHog::Rails.config.user_id_method = :your_method

Feature flags not working

Ensure you've set personal_api_key in your configuration.

Next steps

For any technical questions for how to integrate specific PostHog features into Rails (such as analytics, feature flags, A/B testing, etc.), have a look at our Ruby SDK docs.

Community questions

Was this page useful?

Questions about this page? or post a community question.