There is nothing to install
Thermite speaks Sentry's wire protocol, so the official Sentry SDK for your language already
works against it. There is no @thermite/* package, no fork, no shim — you set the DSN and stop.
This is a tested guarantee, not an intention: an_unmodified_sentry_sdk_reports_into_thermite
sends through a stock Sentry client on every CI run and asserts the event lands and groups.
Get a DSN
Open Project settings → DSN keys. The default DSN looks like this:
The same card mints component DSNs — labeled keys for the parts of one product (worker,
saas, cli). They report into the same issue stream and stay filterable by component, so you
do not have to split a product into separate projects to know which half broke.
The public key is not a secret in the usual sense. It grants exactly one capability: sending events to one project.
Python
pip install sentry-sdkimport sentry_sdk
sentry_sdk.init(
dsn="https://<public_key>@thermite.example.com/1",
release="myapp@1.4.2", # or the git SHA — see Recommended settings
environment="production",
traces_sample_rate=0.0, # Thermite stores no transactions
)Framework integrations (Django, Flask, FastAPI, Celery, …) are auto-enabled by sentry-sdk and
need nothing from Thermite.
Cron check-ins
Scheduled jobs report through the same DSN. The monitor is created on first sighting and carries its own schedule, so nothing is configured twice:
from sentry_sdk.crons import monitor
@monitor(
monitor_slug="nightly-import",
monitor_config={
"schedule": {"type": "crontab", "value": "0 3 * * *"},
"timezone": "Europe/Berlin",
"checkin_margin": 5, # minutes late before the run counts as missed
"max_runtime": 30, # minutes running before it counts as overrunning
},
)
def nightly_import():
...{"type": "interval", "value": 15, "unit": "minute"} works in place of a crontab expression.
A missed or overrunning run becomes an ordinary error event — same grouping, same alerts, same triage queue as an exception. Cron monitoring is a new source of events, not a second pipeline.
JavaScript and TypeScript
bun add @sentry/browser # or @sentry/nodeimport * as Sentry from "@sentry/browser";
Sentry.init({
dsn: "https://<public_key>@thermite.example.com/1",
release: "myapp@1.4.2",
environment: "production",
tracesSampleRate: 0,
});On the server, @sentry/node v8+ must be initialised before any instrumented module is
imported — put Sentry.init() in its own instrument.ts and import that first. Initialising it
halfway down index.ts silently loses most auto-instrumentation.
Rust
Rust is the one language with a first-party SDK, because the Sentry Rust client is seventeen
crates and a hub-and-scope stack to fill in about fourteen fields. thermite-sdk models those
fields and nothing else, and builds for wasm32-unknown-unknown.
let mut options = thermite_sdk::Options::new(std::env::var("THERMITE_DSN")?);
options.release = Some(env!("CARGO_PKG_VERSION").to_string());
options.environment = Some("production".into());
// Held for the life of `main`: dropping it flushes whatever the sender thread still has queued.
let _guard = thermite_sdk::init(options)?;Panic reporting and session tracking are both on by default. The web feature swaps the sender
thread for fetch; tracing-layer turns ERROR records into events and everything else into
breadcrumbs.
What Thermite does with each envelope item
Every SDK sends more than Thermite reads. Nothing is rejected over the extras — an envelope carrying a transaction still delivers its events — but it helps to know what survives:
| Item | Handling | Quota |
|---|---|---|
event |
Stored, grouped into an issue, alerted, queued for triage | 1 per event |
session |
Folded into release-health rollups (crash-free rate) | none |
check_in |
Opens or closes a cron monitor run | none |
client_report |
The SDK's own drop counters, surfaced as outcomes | none |
transaction, log, attachment |
Dropped and counted under unsupported:<type> |
none |
Quota is charged per event item, never per request — one envelope carrying fifty events costs fifty.
Ingest endpoints
| Endpoint | Purpose |
|---|---|
POST /api/{project_id}/envelope/ |
The modern endpoint. Everything in the table above. |
POST /api/{project_id}/store/ |
A bare event payload, for older SDKs. |
POST /api/{project_id}/otlp/v1/logs |
OTLP log records. Error-severity records become events; the rest are counted and dropped. |
Credentials are resolved from ?sentry_key=, then X-Sentry-Auth, then the envelope's own dsn
header — whichever your SDK happens to use.
Recommended settings
Rate limits
An over-quota project gets 429 with both Retry-After and the Sentry-standard
X-Sentry-Rate-Limits: <seconds>:error:project:quota_exceeded. Official SDKs read that header
and back off on their own — there is nothing to configure, and a well-behaved SDK will stop
sending rather than hammer a project that is already out of budget.
Envelopes that hit the limit partway through keep the events already accepted. The SDK retries the whole envelope, and the event ids it already delivered deduplicate on the way back in.
Verify it works
Send something on purpose
sentry_sdk.capture_message("hello from thermite")Check the project
The issue appears on the project's issue list within a second or two. If it does not, the project's Outcomes tell you whether the event was rejected, over quota, or never arrived.