Error Tracking
Temps includes Sentry-compatible error tracking built-in — point your existing @sentry/react, @sentry/nextjs, or any other Sentry SDK at your Temps DSN and errors appear in your dashboard with zero code changes. No Sentry account, no monthly bill, no data leaving your infrastructure.
How it works
Temps implements the Sentry envelope ingestion protocol at /api/<project_id>/envelope/, so any Sentry SDK works without modification. Error grouping uses a built-in vector similarity engine — no OpenAI API call is made; embeddings are computed locally using a hash tokenizer into a 384-dimension vector, then stored in pgvector for cosine-similarity lookup. The platform captures the full Sentry feature set — envelope protocol (v7+), stack trace fingerprinting, source map parsing, user and request context, breadcrumbs, session correlation, and W3C trace ID correlation with spans and proxy logs — all running on your own infrastructure with no third-party services, no per-event pricing, and full integration with Temps analytics and session replay.
| Temps | Sentry Cloud | Self-hosted Sentry | |
|---|---|---|---|
| Protocol | Sentry envelope (v7+) | Sentry envelope (v7+) | Sentry envelope (v7+) |
| SDK compatibility | All official Sentry SDKs | All official Sentry SDKs | All official Sentry SDKs |
| Error grouping | Stack trace + local vector similarity | Stack trace + ML clustering | Stack trace + ML clustering |
| Source maps | Built-in upload + parsing | Built-in | Built-in |
| Session replay | Built-in (same platform) | Add-on (paid plan) | Separate setup required |
| Analytics integration | Built-in | Separate product | Separate product |
| Uptime monitoring | Built-in | Separate product | Separate product |
| Pricing | Free (self-hosted) / ~$6/mo (Cloud) | $0–$80+/mo by event volume | Self-hosted infra cost |
| Data location | Your server | Sentry cloud | Your server |
Sentry compatibility
Temps implements the complete Sentry envelope protocol, allowing you to use official Sentry SDKs without modification.
Supported Features
- Name
Envelope Ingestion- Description
Full Sentry envelope protocol support (v7+)
- Name
Error Events- Description
Exception tracking with stack traces
- Name
Transaction Events- Description
Performance monitoring integration
- Name
Breadcrumbs- Description
Event trail leading up to errors
- Name
User Context- Description
User identification and metadata
- Name
Tags & Metadata- Description
Custom tagging and context
- Name
Releases- Description
Track errors by release version
Compatibility Matrix
Fully Supported SDKs
- @sentry/browser (JavaScript)
- @sentry/react (React)
- @sentry/nextjs (Next.js)
- @sentry/node (Node.js)
- @sentry/python (Python)
- @sentry/go (Go)
- @sentry/php (PHP)
- @sentry/ruby (Ruby)
- @sentry/java (Java)
- @sentry/dotnet (.NET)
Supported Platforms
- Web browsers
- Node.js servers
- React Native
- Electron
- Mobile apps (iOS, Android)
- Desktop apps
- Serverless functions
- Docker containers
Setup and integration
Get started with error tracking in minutes using your existing Sentry SDK.
Step 1: Get Your DSN
Get your project DSN
- 1
Open your project's error tracking setup page at https://<temps_app>/projects/<project_slug>/errors?tab=setup.
- 2
Copy your project's unique DSN from the setup page (the public key is a 64-character hex string unique to your project).
Checkpoint: Confirm the DSN matches the format https://<public_key>@<temps_app>/<project_id> before pasting it into your SDK config.
- 3
Paste the DSN into your Sentry SDK init (for example as NEXT_PUBLIC_SENTRY_DSN) and trigger a test error with Sentry.captureException(new Error('Test error from Temps')).
- 4
Reload the Error Tracking page in the dashboard to confirm the test event arrived.
Checkpoint: The new error group appears in the project's error list, confirming the SDK is sending events.
Each project gets a unique DSN (Data Source Name) for error reporting. The DSN format is:
https://<public_key>@<temps_app>/<project_id>
Example DSN format:
https://0000000000000000000000000000000000000000000000000000000000000000@your-temps-instance.com/1
Step 2: Install Sentry SDK
Install the official Sentry SDK for your platform:
npm install @sentry/react
Step 3: Configure SDK
Point the Sentry SDK to your Temps instance:
Configure Sentry SDK
import * as Sentry from '@sentry/react';
Sentry.init({
// Copy your DSN from: https://<temps_app>/projects/<project_slug>/errors?tab=setup
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN || 'YOUR_DSN_HERE',
environment: 'production',
release: '[email protected]',
// Performance monitoring
tracesSampleRate: 1.0,
integrations: [new Sentry.BrowserTracing()],
beforeSend(event, hint) {
// Filter sensitive data
return event;
}
});
Step 4: Test Error Tracking
Trigger a test error to verify setup:
Test Error Tracking
// Throw test error
Sentry.captureException(new Error('Test error from Temps'));
// Capture message
Sentry.captureMessage('Test message', 'info');
// Add breadcrumb
Sentry.addBreadcrumb({
message: 'User clicked button',
level: 'info',
data: { button: 'signup' }
});
Error grouping
Temps automatically groups similar errors together using stack trace fingerprinting and local vector similarity clustering.
Grouping Strategies
- Name
Stack Trace Fingerprinting- Description
Groups errors with identical stack traces (default)
- Name
Exception Type- Description
Groups by exception class/type (TypeError, ReferenceError, etc.)
- Name
Error Message- Description
Groups by error message pattern (parameterized)
- Name
Vector Similarity- Description
Uses a built-in hash tokenizer + pgvector cosine similarity to find semantically similar errors — computed locally, no external API required
- Name
Custom Fingerprinting- Description
Define custom grouping rules via fingerprint tags
Custom Fingerprinting
Override default grouping with custom fingerprints:
Custom Fingerprinting
Sentry.captureException(error, {
fingerprint: ['database-error', 'connection-timeout'],
});
// Dynamic fingerprint
Sentry.captureException(error, {
fingerprint: ['api-error', error.response?.status],
});
Update Group Status
Merge and split operations are available in the dashboard via the Error Details page Actions menu. Use the CLI to update group status:
# Resolve a group
bunx @temps-sdk/cli errors update --group-id <group-id> --project-id <project-id> --status resolved
# Ignore a group
bunx @temps-sdk/cli errors update --group-id <group-id> --project-id <project-id> --status ignored
Error details
Each error event captures comprehensive context for debugging.
Error Anatomy
- Name
Exception Info- Description
Type, message, stack trace with line numbers
- Name
Request Context- Description
URL, method, headers, query params, request body
- Name
User Context- Description
User ID, email, IP address, custom properties
- Name
Environment- Description
Browser/runtime version, OS, device type
- Name
Tags- Description
Custom tags (environment, version, feature flags)
- Name
Breadcrumbs- Description
Event trail leading to error (clicks, API calls, console logs)
- Name
Additional Data- Description
Custom metadata, local variables, state snapshots
Enrich Error Context
Add custom context to errors:
Add Context
Sentry.setUser({
id: 'user-123',
email: '[email protected]',
username: 'johndoe',
subscription: 'pro'
});
Source context
Temps can show the actual source code around each stack frame, not just file:line. How the source gets there depends on the language.
JavaScript / TypeScript resolves automatically from source maps — the original source travels inside the .map (sourcesContent), so minified production frames turn into readable code. The official Sentry build plugins and sentry-cli upload to Temps unchanged; for git-based deploys Temps injects SENTRY_URL / SENTRY_AUTH_TOKEN, so uploads are zero-config.
Go, Rust, Python, and other compiled or native languages already report the original file:line — they just don't ship the source. Upload the raw source per release and Temps renders the code around each frame.
Native source context is opt-in per project — enable it under Settings → General → Error Tracking Source Context. Your application source is only stored when you turn it on.
Keeping releases in sync
The release you upload source under must match the release your app reports (SENTRY_RELEASE) — typically the deployed commit SHA or tag. Temps injects SENTRY_RELEASE at deploy time (the commit SHA for git builds, the image tag or digest for image deploys), so keying your uploads the same way makes them line up automatically.
Compiled binaries (Go, Rust) can set the release in the SDK init call — if you hard-code a placeholder there, the SDK ignores the injected SENTRY_RELEASE and source won't line up. Leave the release unset so the injected value wins, or bake the real commit/tag at build time (e.g. Go -ldflags "-X main.version=$VERSION").
Uploading source
For git-based deploys, enabling the toggle is all you need — Temps captures the source from the build automatically, keyed by the commit SHA.
For image deploys or custom CI, upload it yourself, keyed by the same release:
# Upload every source file under the repo, keyed by the release.
bunx @temps-sdk/cli errors source-files upload \
--project-id <id> --release "$CI_COMMIT_SHA" --dir .
Trace Correlation
Temps stores a W3C Trace Context trace ID alongside errors so the unified Observe page can link an exception to the request, spans, and other events that share the same trace. This is what powers the cross-source jumps in the /projects/<slug>/observe timeline.
Schema
The m20260502_000001_add_observe_correlation migration (shipped in temps 0.1.0) adds the correlation columns and lookup indexes. Every column is nullable, so existing rows are unaffected, and the migration is written to be safely re-runnable — each step uses IF NOT EXISTS.
| Table | Column | Type | Purpose |
|---|---|---|---|
proxy_logs | trace_id | text (nullable) | W3C trace ID for the request |
proxy_logs | error_group_id | integer (nullable) | Links a request to the error group it produced |
error_events | trace_id_indexed | text (nullable) | Trace ID promoted from the event payload, indexed for joins |
revenue_events | deployment_id | integer (nullable) | Correlate revenue with a deployment |
revenue_events | environment_id | integer (nullable) | Correlate revenue with an environment |
revenue_events | trace_id | text (nullable) | W3C trace ID for the revenue event |
Supporting indexes added by the same migration:
| Index | Definition |
|---|---|
idx_proxy_logs_project_trace | proxy_logs (project_id, trace_id) |
idx_proxy_logs_error_group | proxy_logs (error_group_id) WHERE error_group_id IS NOT NULL |
idx_error_events_project_trace | error_events (project_id, trace_id_indexed) |
idx_revenue_events_project_occurred | revenue_events (project_id, occurred_at DESC) |
How the trace ID is extracted
For error events, temps-error-tracking ingestion probes the event payload for a trace ID and promotes the first valid value to error_events.trace_id_indexed. It checks, in order: data.sentry.contexts.trace.trace_id, top-level data.contexts.trace.trace_id, and data.trace.trace_id. A value is accepted only if it is exactly 32 ASCII-hex characters and is not the all-zero trace ID the W3C spec reserves as invalid.
The temps-proxy reverse proxy includes a helper, extract_traceparent_trace_id, that reads the inbound traceparent request header (matched case-insensitively against traceparent, Traceparent, and TRACEPARENT), splits on -, and takes the trace-id field. It applies the same validation: the value must be 32 ASCII-hex characters, must not be all zeros, and is lowercased before use. Six unit tests cover the valid case, a missing header, the all-zero value, the wrong length, non-hex characters, and uppercase folding.
To send a trace ID through to Temps, set a standard traceparent header on the request:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
│ └─ trace-id (32 hex) ────────────┘ └─ span-id ──┘ └ flags
└─ version
Proxy proxy_logs.trace_id population is not yet wired. The extract_traceparent_trace_id helper exists and is validated, but the live proxy logging path writes request rows through a batched multi-row INSERT whose column list does not yet include trace_id, so the extracted value is currently dropped before the proxy_logs write. The schema column and indexes are in place, and error events are already correlated via error_events.trace_id_indexed, but do not rely on the proxy populating proxy_logs.trace_id for live requests yet.
Error resolution
Manage error lifecycle from discovery to resolution.
Error States
- Name
Unresolved- Description
New or ongoing errors (default state)
- Name
Resolved- Description
Marked as fixed (manually or automatically)
- Name
Ignored- Description
Known errors that should be suppressed
- Name
Regressed- Description
Error recurred after being resolved
Mark as Resolved
Mark an error group as resolved
- 1
Open the Error Details page for the error group you fixed.
- 2
Open the Actions menu and choose Resolve.
- 3
Pick a resolution option: mark as resolved now, resolve in the next release, resolve in a specific release, or set auto-resolve after X days with no new events. (Release-scoped and auto-resolve options are dashboard-only; the CLI always performs an immediate resolve.)
- 4
Confirm the resolution.
Checkpoint: The error group's status changes to Resolved; if it recurs later it will reappear as Regressed.
Resolve Errors
# Resolve error group
bunx @temps-sdk/cli errors update --group-id <group-id> --project-id <project-id> --status resolved
# Resolve multiple groups (run per group)
bunx @temps-sdk/cli errors update --group-id error-123 --project-id <project-id> --status resolved
bunx @temps-sdk/cli errors update --group-id error-456 --project-id <project-id> --status resolved
Ignore Errors
Ignore a known error group
- 1
Open the Error Details page for the error group you want to suppress.
- 2
Open the Actions menu and choose Ignore.
- 3
Confirm to suppress the group (configure pattern-based ignore rules in the web UI for recurring noise).
Checkpoint: The error group's status changes to Ignored and it no longer surfaces in the default unresolved list.
Suppress known errors you don't want to track:
Ignore Errors
Sentry.init({
dsn: '...',
ignoreErrors: [
// Ignore specific error messages
'ResizeObserver loop limit exceeded',
'Non-Error promise rejection',
// Ignore error patterns
/^Loading chunk [\d]+ failed$/,
],
// Ignore errors from specific URLs
denyUrls: [
/extensions\//i,
/^chrome:\/\//i,
],
beforeSend(event, hint) {
// Custom ignore logic
if (event.exception) {
const error = hint.originalException;
if (error.message?.includes('Network error')) {
return null; // Don't send to Temps
}
}
return event;
}
});