# Telemetry & Error Reporting Atrium includes an optional, opt-in error reporting system powered by [Sentry](https://sentry.io). This document explains exactly what is collected, what is not collected, and how to control the setting. ## Opt-in only Error reporting is **disabled by default** for all self-hosted installations. The first time an organization owner logs into the dashboard, a banner asks whether they want to share anonymous crash data. The owner can: - **Accept** — error reports are sent to the Atrium maintainers to help fix bugs. - **Decline** — nothing is ever sent. No data leaves your server. The preference can be changed at any time in **Settings → General → Error Reporting**. ## What is collected When error reporting is enabled, Sentry captures unhandled exceptions and errors from both the web app (browser) and the API (server). Each report includes: | Data | Details | |------|---------| | **Stack trace** | File names, line numbers, and function names from the Atrium codebase | | **Error message** | The exception message (e.g. "Cannot read properties of undefined") | | **Browser / OS** | Browser name and version, operating system name and version | | **URL** | The page path where the error occurred (e.g. `/dashboard/projects`) | | **Anonymous session ID** | A random ID generated by Sentry per session — not tied to any user account | | **Sentry SDK version** | Version of the Sentry client library | ## What is never collected - **No personally identifiable information (PII)** — user names, email addresses, IP addresses, and passwords are never included. - **No client data** — project names, file names, invoice contents, and any data belonging to your clients are never sent. - **No organization details** — your organization name, branding, or configuration are not included. - **No authentication tokens** — session tokens, API keys, and credentials are never captured. - **No financial data** — Stripe keys, payment details, or invoice amounts are never sent. Sentry is configured with `sendDefaultPii: false` (the default), which strips cookies, request bodies, and user identity from all events. ## Hosted deployment If you are using the Atrium-hosted service (run by the maintainers), error reporting is always active and consent is not requested. This is necessary to operate a reliable service. ## Disabling at the infrastructure level Self-hosters who prefer to guarantee no data ever leaves their environment can omit the `SENTRY_DSN` and `NEXT_PUBLIC_SENTRY_DSN` environment variables entirely. Without a DSN configured, Sentry is not initialized and no data is ever sent, regardless of the in-app setting. ## Disabling at the source code level If you are building from source and want a hard guarantee that Sentry is never bundled, you can remove the integration entirely: 1. **Uninstall the packages:** ```bash bun remove @sentry/nestjs @sentry/nextjs --filter @atrium/api --filter @atrium/web ``` 2. **Delete the Sentry config files:** ``` apps/api/src/instrument.ts apps/web/sentry.client.config.ts apps/web/sentry.server.config.ts apps/web/sentry.edge.config.ts apps/web/src/lib/sentry.ts ``` 3. **Revert `apps/web/next.config.ts`** — remove the `withSentryConfig()` wrapper and return the plain `nextConfig` object. 4. **Remove `captureException` call sites** — search for `Sentry.captureException` in `apps/api/src/` and delete those lines. 5. **Remove the telemetry consent banner** — delete `apps/web/src/components/telemetry-consent-banner.tsx` and remove its import from `apps/web/src/app/(dashboard)/layout.tsx`. After these steps, no Sentry code will be present in the build at all. ## Data retention and access Error reports are stored in Sentry and accessible only to the Atrium maintainers. Reports are used solely to identify and fix bugs in the Atrium codebase. Data is retained according to Sentry's default retention policy (90 days on the free tier). --- # Product Analytics Separate from error reporting, Atrium supports optional web analytics via the `NEXT_PUBLIC_TRACKERS` environment variable. This is **off by default and self-directed**: nothing loads unless you configure it, and the data goes to *your* analytics instance, never to the Atrium maintainers. ## Enabling it ```bash NEXT_PUBLIC_TRACKERS='[{"src":"https://umami.example.com/script.js","data-website-id":"your-id"}]' ``` Set it as a normal runtime environment variable on your container. Every route that can report is rendered per request, so the running container's environment is read directly — no rebuild required, and changing the value takes effect on restart. The published `vibralabs/atrium` image ships with **no** tracker configured, and this is deliberate: because analytics is runtime configuration, the image the maintainers publish is the same one everyone runs, and it reports nowhere by default. A self-hosted Atrium never sends anything to the maintainers. > Historical note: the auth pages (`/signup`, `/accept-invite`, ...) used to be > statically prerendered, which resolved this variable at build time and left > them permanently untracked in any image built without it. They are now > rendered per request (`apps/web/src/app/(auth)/layout.tsx`). ## Identifiers are stripped before sending Analytics scripts normally transmit the full URL and page title. In Atrium those contain identifiers — project ids, organization slugs, task ids in query strings, and titles carrying client names. `apps/web/src/lib/mask-analytics.ts` rewrites every payload in the browser before it is sent: | Sent as | Instead of | |---------|------------| | `/portal/projects/[id]` | `/portal/projects/cm...` | | `/login/[slug]` | `/login/` | | `/portal/sign/[token]` | `/portal/sign/` | | *(no query string)* | `?task=`, `?id=` | | *(no page title)* | `Client Project Name \| Atrium` | The identifiers are never transmitted, rather than being sent and trusted to stay private. This is wired up automatically via the tracker's `data-before-send` hook; set your own `data-before-send` value if you want different handling. ## No individual user tracking Atrium does **not** identify users to analytics. There is no user id, no account id, and no per-person attribute in any event. Product events are aggregate counts only: - **Onboarding** — `signup_started`, `signup_completed`, `signup_failed`, `setup_completed`, `setup_step_skipped`, `setup_email_configured` - **Portal usage** — `portal_file_downloaded` (file extension only, never the name), `portal_request_posted`, `portal_document_responded` (approve/reject only, never the document or the stated reason) These answer "do invited clients use their portals" without answering "what did this particular client do". If you fork Atrium and add user identification, say so in your own privacy policy.