---
title: Insights overview
description: Query automatic Ruby instrumentation, framework events, and custom application events in Honeybadger Insights.
url: https://docs.honeybadger.io/lib/ruby/insights/
---

[Insights](https://docs.honeybadger.io/guides/insights/) lets you observe what your Ruby application does in production.

Honeybadger records common Ruby activity automatically, including requests, database queries, background jobs, cache calls, and runtime metrics. From there, you can add context and custom events from your own code, then use [BadgerQL](https://docs.honeybadger.io/guides/insights/badgerql/) to ask questions across the whole event stream. Any field you send is queryable as soon as it arrives, with no schema to define ahead of time.

## Start with automatic instrumentation

Insights is on by default in v6.0+. The gem starts recording events as soon as your app boots.

[Automatic instrumentation](https://docs.honeybadger.io/lib/ruby/insights/automatic-instrumentation/)Configure what the gem captures.

We capture a wide range of events automatically.

[Ruby event reference](https://docs.honeybadger.io/insights/event-types/ruby/)See every Ruby event type and field.

## Add a built-in dashboard

Automatic events power built-in dashboards, no setup necessary.

[Rails](https://docs.honeybadger.io/guides/dashboards/rails/)Slow requests, queries, and partials; cache hit rates by controller

[Sidekiq](https://docs.honeybadger.io/guides/dashboards/sidekiq/)Job counts, durations, and failure rates by worker

[Active Job](https://docs.honeybadger.io/guides/dashboards/active-job/)Job counts, durations, and failure rates by job class

[Autotuner](https://docs.honeybadger.io/guides/dashboards/autotuner/)Heap growth, GC counts, and memory tuning suggestions

[Puma](https://docs.honeybadger.io/guides/dashboards/puma/)Request backlog, running threads, and pool capacity over time

Pre-aggregated alternatives for apps that have [metrics enabled](https://docs.honeybadger.io/lib/ruby/insights/collecting-and-reporting-metrics/):

[Rails Metrics](https://docs.honeybadger.io/guides/dashboards/rails-metrics/)Pre-aggregated throughput, controller durations, and DB/view timings

[Sidekiq Metrics](https://docs.honeybadger.io/guides/dashboards/sidekiq-metrics/)Pre-aggregated job durations, queue depth, latency, and capacity

[Active Job Metrics](https://docs.honeybadger.io/guides/dashboards/active-job-metrics/)Pre-aggregated job throughput, durations, and stats by job class

[Karafka](https://docs.honeybadger.io/guides/dashboards/karafka/)Consumer lag, processing durations, and broker errors by topic

[Net::HTTP Metrics](https://docs.honeybadger.io/guides/dashboards/net-http-metrics/)Outbound HTTP throughput, durations, and status codes by host

[Solid Queue Metrics](https://docs.honeybadger.io/guides/dashboards/solid-queue-metrics/)Job statuses, active workers and dispatchers, and queue depths

## Add application context

Adding event context attaches fields to the current thread. Once set, every event emitted from that thread includes them. Lets say our app is A/B testing a new checkout flow. We could record the A/B variant simply with event context:

Set the variant on context

```ruby
Honeybadger.event_context({ checkout_variant: })
```

The `checkout_variant` field is now on every ActiveRecord event for that request. You can group by it like any other field.

ActiveRecord work by checkout variant

```badgerql
filter event_type::str == "sql.active_record" and isNotNull(checkout_variant::str)
| stats
    count() as queries,
    avg(duration::float) as avg_ms
  by checkout_variant::str
| sort queries desc
```

| queries | avg\_ms | checkout\_variant |
| ------- | ------- | ----------------- |
| 26815   | 1.93    | new               |
| 11873   | 1.71    | control           |

The new variant ran more than twice as many queries with similar per-query time. Keep in mind that adding another A/B variant will extend any of the examples here without the need to change anything on the Honeybadger side.

Go deeper: check for possible N+1 queries

The gem attaches a `request_id` to every event from the same request. To turn total ActiveRecord work into queries per request, group events by `request_id` first to get a per-request count, then aggregate by variant.

```badgerql
filter event_type::str == "sql.active_record" and isNotNull(checkout_variant::str)
| stats count() as queries by request_id::str, checkout_variant::str
| stats
    count() as request_count,
    avg(queries) as avg_q,
    percentile(95, queries) as p95_q
  by checkout_variant
| sort p95_q desc
| only
    toHumanString(request_count) as requests,
    toHumanString(avg_q) as avg_queries,
    toHumanString(p95_q) as p95_queries,
    checkout_variant
```

| requests | avg\_queries | p95\_queries | checkout\_variant |
| -------- | ------------ | ------------ | ----------------- |
| 631      | 42.18        | 97           | new               |
| 638      | 18.61        | 31           | control           |

The new variant runs more queries per request, and the p95 is much higher than control. That pattern often points at an N+1.

[Event context](https://docs.honeybadger.io/lib/ruby/insights/event-context/)Block-scoped context, cross-thread propagation, and clearing.

## Record application events

Custom events record activity the framework cannot see at all. Rails knows a checkout request ran. Only your app knows whether the payment authorized:

Send a custom payment event

```ruby
Honeybadger.event("payment.authorized", {
  payment_provider: payment.provider,
  amount: checkout.total,
  currency: checkout.currency,
  authorization_id: payment.authorization_id
})
```

This query breaks down the amounts collected by variant and provider:

Payments by variant and provider

```badgerql
filter event_type::str == "payment.authorized"
| stats
    count() as authorizations,
    sum(amount::float) as authorized_amount
  by checkout_variant::str, payment_provider::str
| sort authorized_amount desc
```

| authorizations | authorized\_amount | checkout\_variant | payment\_provider |
| -------------- | ------------------ | ----------------- | ----------------- |
| 413            | 34108.00           | new               | stripe            |
| 218            | 18722.00           | new               | paypal            |
| 418            | 32167.00           | control           | stripe            |
| 220            | 13639.00           | control           | paypal            |

Go deeper: more insights, same instrumentation

Conversion rate by variant

```badgerql
filter event_type::str == "payment.authorized" or controller::str == "CheckoutsController"
| stats count(event_type::str == "payment.authorized") as auth_events
  by request_id::str, checkout_variant::str
| stats
    count() as auths,
    count(auth_events > 0) as checkouts,
    checkouts / auths as conv_rate
  by checkout_variant::str
| only conv_rate, checkout_variant
```

| conv\_rate | checkout\_variant |
| ---------- | ----------------- |
| 0.92       | new               |
| 0.86       | control           |

Revenue per payment provider per variant

```badgerql
filter event_type::str == "payment.authorized"
| stats sum(amount::float) as total
  by payment_provider::str, checkout_variant::str
| sort total desc
| only toHumanString(total) as revenue, payment_provider, checkout_variant
```

| revenue | payment\_provider | checkout\_variant |
| ------- | ----------------- | ----------------- |
| 34,108  | stripe            | new               |
| 32,167  | stripe            | control           |
| 18,722  | paypal            | new               |
| 13,639  | paypal            | control           |

Average checkout response time by variant

```badgerql
filter event_type::str == "process_action.action_controller"
  and controller::str == "CheckoutsController"
| stats avg(duration::float) as avg_ms by checkout_variant::str
| only toHumanString(avg_ms, "milliseconds") as avg, checkout_variant
```

| avg   | checkout\_variant |
| ----- | ----------------- |
| 488ms | new               |
| 198ms | control           |

Conversion rate over time, by variant

```badgerql
filter event_type::str == "payment.authorized" or controller::str == "CheckoutsController"
| stats
    count(event_type::str == "payment.authorized") as auth_events,
    min(@ts) as request_ts
  by request_id::str, checkout_variant::str
| stats count(auth_events > 0) / count() as conv_rate
  by checkout_variant::str, bin(1h, request_ts) as hour
| sort hour asc
```

| conv\_rate | checkout\_variant | hour                |
| ---------- | ----------------- | ------------------- |
| 0.93       | new               | 2026-06-26 14:00:00 |
| 0.86       | control           | 2026-06-26 14:00:00 |
| 0.92       | new               | 2026-06-26 15:00:00 |
| 0.86       | control           | 2026-06-26 15:00:00 |
| 0.91       | new               | 2026-06-26 16:00:00 |
| 0.87       | control           | 2026-06-26 16:00:00 |

The new variant holds a consistent lead over control across the rollout window.

[Sending custom events](https://docs.honeybadger.io/lib/ruby/insights/sending-events-to-insights/)The full Honeybadger.event API, naming conventions, and delivery.

---

## Try Honeybadger for FREE

Intelligent logging, error tracking, and Just Enough APM™ in one dev-friendly platform. Find and fix problems before users notice.

[Start free trial](https://app.honeybadger.io/users/sign_up)

[See plans and pricing](https://www.honeybadger.io/plans/)
