bloqr-backend integrates Sentry for Cloudflare Workers (@sentry/cloudflare) for automatic error capture, performance tracing, and release tracking.
The integration is additive and opt-in: when SENTRY_DSN is absent the worker
runs identically to before — no SDK is imported and no events are captured.
All three layers use the same SENTRY_DSN secret — set once via
wrangler secret put SENTRY_DSN and both the Worker and the Angular frontend
(via /api/sentry-config) pick it up automatically.
2. Prerequisites — create your Sentry project
Security notice: The Sentry DSN is a sensitive credential. Never commit it
to source control. Always store it as a Cloudflare Worker Secret
(wrangler secret put SENTRY_DSN) or in your untracked .env.local.
When SENTRY_DSN is absent the wrapper is a minimal-overhead pass-through — the
Sentry SDK is not imported and no events are captured. To enable error capture,
set the secret (see §4).
tracesSampleRate — withSentryWorker() applies a default sample rate. Override
it in the config callback (e.g. tracesSampleRate: 0.1) to stay within Sentry’s
free quota in production; use 1.0 in staging.
6. Tail Worker capture
The tail worker (worker/tail.ts) automatically forwards unhandled Worker
exceptions to Sentry when SENTRY_DSN is set. The integration is already
wired — no code changes are needed.
How it works:
On each tail event batch, if SENTRY_DSN is present in TailEnv, the
Sentry SDK is dynamically imported and initialised (tracesSampleRate: 0
— no transactions, only exceptions).
Each exception in event.exceptions is forwarded to Sentry via
sentry.captureException() inside sentry.withScope(), with contextual
tags (outcome, scriptName, url, method).
Before the event loop closes, sentry.flush(2000) is awaited via
ctx.waitUntil() to ensure buffered events are sent.
Any Sentry failure is caught silently — the tail worker continues regardless.
Setup — set the secret for the tail worker deployment:
Why a separate secret? The tail worker is a separate Cloudflare deployment
(see wrangler.tail.toml) and has its own binding scope. Even though both
workers share the same DSN value, secrets must be set independently.
7. Using SentryDiagnosticsProvider and the provider factory
Quickstart — use the factory (recommended)
worker/services/diagnostics-factory.ts exports createDiagnosticsProvider(env),
which reads SENTRY_DSN and OTEL_EXPORTER_OTLP_ENDPOINT from Env and
returns the right provider (or a composite of both) with zero boilerplate:
Forwards Angular errors to Sentry via captureException
frontend/server.ts
Frontend Worker SSR handler — wrapped with SentryCloudflare.withSentry()
frontend/wrangler.toml
Declares tail_consumers, SENTRY_DSN and documents how SENTRY_RELEASE is injected at deploy time for the frontend Worker
.github/workflows/sentry-sourcemaps.yml
Source map upload CI workflow
.env.example
SENTRY_DSN stub (search Error Reporting)
10. Frontend RUM
The Angular admin UI ships with Sentry Browser SDK (@sentry/angular v9)
for real-user monitoring — unhandled JS errors, browser performance tracing,
and session replay.
Quick start — enable RUM in 3 steps
Step 1 — Create a Sentry project (or reuse the existing one)
If you already have a Sentry project from §2, skip this step.
If not, create one at sentry.io: Projects → Create Project → JavaScript → Browser.
Step 2 — Set the SENTRY_DSN Worker secret
Terminal window
# This single secret enables BOTH the Worker backend Sentry capture (§5)
# AND the Angular frontend RUM — they share the same DSN.
wranglersecretputSENTRY_DSN
# Paste your DSN, e.g.: https://abc123@o999.ingest.sentry.io/12345
After deploying the Worker, the Angular app fetches the DSN from
GET /api/sentry-config at boot and initialises Sentry automatically.
No rebuild is required — the same artifact works in any environment.
The workflow runs automatically on every push to main and on v* release tags.
It skips silently if SENTRY_ORG is not set, so it is safe to skip this step initially.
How RUM is initialised
The DSN is fetched at runtime from /api/sentry-config (the Worker
exposes it from the SENTRY_DSN Worker Secret). It is never baked into the
build artifact, which means the same build artifact can run in any environment.
ZTA note:/api/sentry-config (and all other pre-auth config endpoints) is protected by
anonymous-tier rate limiting via checkRateLimitTiered in worker/handlers/router.ts, even
though it requires no authentication. This prevents scraping or DoS of the config endpoint.
The DSN itself is intentionally public (Sentry uses it in every browser request), but the
endpoint still enforces rate limits. See worker/utils/cors.ts for the CORS policy.
If the endpoint is unreachable or SENTRY_DSN is unset, initSentry() is a
no-op and the app boots normally.
All required secrets and variables
Name
Where
Description
SENTRY_DSN
Cloudflare Worker Secret
Public DSN — safe to send to the browser
SENTRY_RELEASE
Cloudflare Worker var (deploy-time)
Git SHA — links events to uploaded source maps
SENTRY_AUTH_TOKEN
GitHub secret
CI-only — used by @sentry/cli to upload source maps
SENTRY_ORG
GitHub variable (vars.)
Your Sentry organisation slug
SENTRY_PROJECT
GitHub variable (vars.)
Your Sentry project slug
Source map association: SENTRY_RELEASE must match the --release value used by the
sentry-sourcemaps.yml CI workflow (which uses ${{ github.sha }}). Set it at deploy time:
Without a matching release, Sentry will capture errors correctly but stack traces will
remain minified. The SENTRY_DSN alone is sufficient for error capture.
Session Replay
replayIntegration() is enabled with conservative sampling:
Setting
Value
Meaning
replaysSessionSampleRate
0.05
Replay 5 % of all sessions
replaysOnErrorSampleRate
1.0
Always replay sessions that contain an error
Privacy / GDPR: Session replay captures user interactions including form
inputs, clicks, and navigation events. Sensitive fields (passwords, credit
cards, PII) are masked by default, but you should review what is captured
for your specific use case. Sentry provides maskAllText: true and
blockAllMedia: true replay options, plus a
data scrubbing pipeline
for server-side filtering. Review and enable these before enabling session
replay in EU or privacy-sensitive production environments.
Source map upload workflow
.github/workflows/sentry-sourcemaps.yml runs on every push to main and
on v* release tags. It builds the Angular app with source maps enabled and
uploads them to Sentry so that minified stack traces are readable. The upload
uses --release "${{ github.sha }}" to associate source maps with the exact
commit SHA deployed, enabling accurate stack trace de-minification.
The workflow skips silently if SENTRY_ORG is not configured (via the if:
condition), so it is safe to merge before Sentry is set up.
Verifying RUM
Open Sentry → Issues — unhandled Angular errors appear within ~30 s.
Open Sentry → Performance — browser page-load and navigation spans
appear when tracesSampleRate > 0.
Open Sentry → Replays — session recordings appear based on the
sample rates configured in frontend/src/app/sentry.ts.
RUM Troubleshooting
Symptom
Likely cause
Fix
No RUM events in Sentry
SENTRY_DSN not set or /api/sentry-config unreachable
Check wrangler secret put SENTRY_DSN; verify the Worker is deployed
Browser console: TypeError: Sentry is not a function
@sentry/angular not installed
Run pnpm install from the repo root
No replays visible
replaysSessionSampleRate too low or DSN wrong
Verify DSN in the Network tab (GET /api/sentry-config should return a non-null DSN)
Source maps not resolving
SENTRY_AUTH_TOKEN / SENTRY_ORG / SENTRY_PROJECT not configured
Set all three in GitHub secrets/vars and re-run the sentry-sourcemaps.yml workflow