---
title: "Keep clickhouse integration sentry queryable"
excerpt: "Sentry issue grouping vs raw events in ClickHouse®. Relay dual-write, Envelope ingest, transaction rollups, KPI parity with alerts."
authors: "Tinybird"
categories: "AI Resources"
createdOn: "2026-08-27 00:00:00"
publishedOn: "2026-08-27 00:00:00"
updatedOn: "2026-08-27 00:00:00"
status: "published"
---

Sentry groups errors into issues, deduplicates stack traces, and fires alerts when regressions spike. ClickHouse{% sup %}®{% /sup %} stores raw error and transaction events for SQL aggregations, release comparisons, and product APIs without Sentry's per-event ingest pricing curve. A working **clickhouse integration sentry** setup keeps Sentry as the developer workflow and ClickHouse as the analytical warehouse.

Sentry does not archive every event to ClickHouse by default. The bridge is dual-write at the SDK, a Relay sidecar, or batch export through Sentry's data APIs.

## Issue grouping vs raw event warehouse

Sentry's value is fingerprinting: similar stack traces collapse into one issue, assignees get notified, and releases track regressions. ClickHouse value is row-level SQL: error rate by `release`, p95 transaction duration by `transaction`, join errors to subscription tier.

| Workload | Sentry | ClickHouse |
| --- | --- | --- |
| Issue triage and assignment | Primary | Not applicable |
| Stack trace deduplication | Primary | Store fingerprint hash only |
| Error rate by release over 6 months | Sampled stats | Full SQL on raw events |
| Performance transaction trends | Discover / dashboards | Rollups + APIs |
| Join errors to product usage tables | Limited | Native SQL |
| Customer-facing reliability score | Not default | Pipes / endpoints |

Do not try to rebuild Sentry issue grouping in ClickHouse. Store `fingerprint`, `issue_id` when available, and raw event fields for analytics. For error monitoring architecture context, see [real-time error monitoring](https://www.tinybird.co/blog/real-time-error-monitoring).

## Three ingest paths: SDK, Relay, and export

| Path | Sentry feature | ClickHouse role | Latency |
| --- | --- | --- | --- |
| **SDK dual-write** | Sentry SDK in app | Parallel POST to ClickHouse/Tinybird | Seconds |
| **Relay proxy + mirror** | Self-hosted Relay or sentry-mirror | Forward Envelopes to a second DSN or HTTP sink | Seconds |
| **Batch export** | Sentry data export (Enterprise) | Backfill and compliance | Hours |

Live dual-write fits high-volume product analytics. Batch export fits backfill when Sentry was already production before ClickHouse existed.

```text
App SDK ──┬──► Sentry (issues, alerts, releases)
          └──► ClickHouse / Tinybird Events API

Self-hosted Relay ──┬──► Sentry upstream
                    └──► sentry-mirror or custom HTTP sink ──► ClickHouse

Sentry data export ──► object storage ──► batch loader ──► ClickHouse
```

## Envelope protocol and row shape

Sentry's Envelope format bundles items (`event`, `transaction`, `session`, attachments). Your ClickHouse sink should unpack items and route by type.

```sql
CREATE TABLE sentry.events
(
    event_time DateTime64(3),
    project LowCardinality(String),
    environment LowCardinality(String),
    release LowCardinality(String),
    level LowCardinality(String),
    platform LowCardinality(String),
    transaction LowCardinality(String),
    fingerprint String,
    message String,
    exception_type LowCardinality(String),
    user_id String,
    tags Map(String, String)
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_time)
ORDER BY (project, release, event_time);

CREATE TABLE sentry.transactions
(
    event_time DateTime64(3),
    project LowCardinality(String),
    transaction LowCardinality(String),
    release LowCardinality(String),
    duration_ms Float64,
    status LowCardinality(String),
    trace_id String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_time)
ORDER BY (project, transaction, event_time);
```

Separate tables for errors and transactions. Query patterns differ. Do not merge into one wide table "to keep it simple."

### SDK dual-write with beforeSend

Mirror at the SDK layer with `beforeSend` so Sentry still receives the canonical event and your sink gets a scrubbed copy:

```javascript
Sentry.init({
  dsn: "https://key@sentry.io/project",
  beforeSend(event) {
    void fetch("https://api.tinybird.co/v0/events?name=sentry_events", {
      method: "POST",
      headers: { Authorization: "Bearer TB_TOKEN", "Content-Type": "application/json" },
      body: JSON.stringify({
        event_time: new Date().toISOString(),
        project: event.project ?? "web-app",
        environment: event.environment ?? "",
        release: event.release ?? "",
        level: event.level ?? "",
        fingerprint: (event.fingerprint ?? []).join("-"),
        message: event.message ?? event.exception?.values?.[0]?.value ?? "",
        exception_type: event.exception?.values?.[0]?.type ?? "",
      }),
    }).catch(() => {});
    return event;
  },
});
```

Use async fire-and-forget or a local queue so ClickHouse backpressure never blocks error reporting to Sentry.

## Performance transactions and release health

Sentry performance monitoring sends transaction events with `transaction`, `duration`, and trace context. Roll up in ClickHouse for release comparison:

```sql
SELECT
    release,
    transaction,
    quantile(0.95)(duration_ms) AS p95_ms,
    countIf(status = 'internal_error') AS errors,
    count() AS total
FROM sentry.transactions
WHERE event_time >= now() - INTERVAL 7 DAY
  AND project = 'web-app'
GROUP BY release, transaction
ORDER BY release DESC, p95_ms DESC;
```

Align time windows with Sentry Discover queries before you trust both during a release postmortem.

## Relay and sentry-mirror for self-hosted Sentry

Self-hosted teams run Relay at the edge for PII scrubbing and rate limiting. Relay forwards Envelopes to Sentry upstream; it does not natively POST to ClickHouse.

For mirroring ingest to a second destination, Sentry publishes **sentry-mirror**: a sidecar that accepts Envelope traffic on a configured DSN and forwards to one or more outbound DSNs with optional category filters and sample rates. Point a custom outbound sink at your ClickHouse HTTP endpoint or Kafka topic, or run a small proxy that unpacks Envelopes and inserts rows.

The mirror must receive **post-scrub** payloads so Sentry and ClickHouse agree on which fields exist. Log dropped fields in staging when scrubbing rules change.

## Tinybird on the Sentry pipeline

Tinybird fits the ClickHouse side of Sentry dual-write:

1. **Events API** for SDK mirror rows (high-volume NDJSON)
2. **Kafka connector** when Relay publishes to a topic
3. **Pipes** for release health endpoints per [build real-time APIs on ClickHouse](https://www.tinybird.co/blog/build-real-time-apis-clickhouse-tinybird)
4. **JWT fixed_params** for per-tenant `project` scoping in embedded dashboards
5. **Branches** to test new tag mappings before SDK rollout

Example release comparison endpoint:

```sql
NODE release_errors
SQL >
    SELECT
        release,
        countIf(level = 'error') AS errors,
        count() AS events,
        errors / events AS error_rate
    FROM sentry_events
    WHERE event_time >= now() - INTERVAL 24 HOUR
      AND project = {{String(project)}}
    GROUP BY release
    ORDER BY release DESC

TYPE endpoint
```

Canva reports 3.6 PB processed per month and 54 ms p99 query latency on Tinybird's product page. Resend reports 100 TB per month and 62 ms p90 query latency without relying on cache. Tinybird is SOC 2 Type II certified.

## 5 operational mistakes on Sentry ClickHouse integrations

### 1. Rebuilding issue grouping in ClickHouse

Sentry fingerprints are complex. ClickHouse will not replace the Issues UI.

**Fix:** Store fingerprint and issue metadata. Keep triage in Sentry.

### 2. Blocking Sentry SDK on ClickHouse insert failure

Analytics sink failures must never drop error reports.

**Fix:** Async mirror with bounded queue. Drop mirror rows under backpressure, not Sentry events.

### 3. One table for events and transactions

Mixed schemas produce empty columns and bad sort keys.

**Fix:** Separate MergeTree tables per event type.

### 4. Sort key led by `user_id`

User IDs are high cardinality and ruin merge performance.

**Fix:** `ORDER BY (project, release, event_time)`. Keep `user_id` as a plain column.

### 5. Release health KPIs without parity checks

Sentry alert fired but ClickHouse dashboard shows green.

**Fix:** Nightly parity on error count by release with identical filters and sample rate documentation.

## What the integration comes down to

Sentry integration with ClickHouse is complementary. Sentry owns issue workflow, deduplication, and developer alerts. ClickHouse owns raw event retention, SQL analytics, release comparisons, and product-facing reliability APIs.

Dual-write at the SDK or Relay for live facts. Use export for backfill. Separate error and transaction tables. Write down which system owns each release health KPI before production.

## Frequently Asked Questions (FAQs)

### Does Sentry natively sync all events to ClickHouse?

No. Use SDK dual-write (for example `beforeSend`), sentry-mirror with a custom sink, or batch export into ClickHouse.

### Will mirroring break Sentry rate limits?

Mirror traffic is independent. Size ClickHouse ingest for combined volume. Sentry quotas apply only to Sentry-bound events.

### Should I store full stack traces in ClickHouse?

Store exception type and message for aggregations. Full stacks inflate storage. Keep deep triage in Sentry.

### Can ClickHouse replace Sentry for alerting?

No for developer workflow. ClickHouse can drive product dashboards and custom alerts on rollups.

### How do performance transactions fit?

Route transaction Envelope items to a dedicated table. Roll up p95 by transaction and release.

### When should teams add Tinybird on top of ClickHouse?

When you want managed ingest, SQL endpoints, and tenant scoping without operating ClickHouse clusters.

{% cta
  title="SQL APIs on your Sentry event pipeline"
  text="Tinybird is managed ClickHouse with high-volume Events API ingest, release rollups as Pipes, and sub-second endpoints. Keep Sentry for issues; ship analytics from the same events."
  button={href: "https://cloud.tinybird.co/signup", target: "_blank", text: "Try Tinybird free"}
/%}
