Sentry groups errors into issues, deduplicates stack traces, and fires alerts when regressions spike. ClickHouse® 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.
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.
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.
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:
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:
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:
- Events API for SDK mirror rows (high-volume NDJSON)
- Kafka connector when Relay publishes to a topic
- Pipes for release health endpoints per build real-time APIs on ClickHouse
- JWT fixed_params for per-tenant
projectscoping in embedded dashboards - Branches to test new tag mappings before SDK rollout
Example release comparison endpoint:
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.
