Choosing Between Client‑Side and Server‑Side Sentry SDKs for a Web App
Decide whether to use Sentry’s client‑side, server‑side, or both SDKs in a web app by comparing setup, visibility, and duplication risks, then see a hybrid initialization example.
18 Mar 2026, 04:18 UTC

Decision and constraints
You need to decide how to instrument a web application with Sentry so that errors from both the browser and the backend are visible, while keeping setup simple, respecting rate limits, and avoiding duplicate events. The main constraints are:
- Client‑side code runs in the browser and must not leak a DSN that allows unrestricted event submission.
- Server‑side code runs on your Node.js (or similar) backend and should integrate with existing logging.
- You want end‑to‑end visibility without paying twice for the same error.
Supported options comparison
| Option | Where it runs | What it captures | Setup effort | Pros | Cons |
|---|---|---|---|---|---|
| Client‑side SDK only | Browser (e.g., @sentry/browser) | Uncaught exceptions, promise rejections, user actions, breadcrumbs | Low – add script or npm init | Full browser context (URL, UA, screen), no extra infrastructure | No visibility into server errors; DSN exposed publicly |
| Server‑side SDK only | Node.js backend (e.g., @sentry/node) | Errors during request handling, uncaught process exceptions | Low – middleware init | Can reuse existing logging, DSN kept secret | Misses client‑side bugs; lacks user‑agent breadcrumbs |
| Hybrid (both SDKs) | Browser + Node.js | All client errors + all server errors | Medium – two initializations, DSN management | End‑to‑end trace, separate contexts, can sample independently | Risk of duplicate events if same DSN used without deduplication; slightly more config |
Trade‑offs
If you only need to monitor the UI (e.g., a static site) the client‑only option is simplest and avoids exposing a backend DSN. For APIs or server‑rendered pages where backend faults are critical, server‑only may suffice. Most full‑stack apps benefit from the hybrid approach because it gives you:
- Client stack traces with breadcrumbs that show user steps leading to an error.
- Server stack traces tagged with request IDs, hostnames, and any custom logs you already emit.
- Ability to apply different sample rates: you might sample client errors at 10% and server errors at 100% (or vice‑versa) to stay within Sentry’s quota.
The hybrid approach requires careful DSN handling to prevent the same error from being reported twice (e.g., a thrown exception that is caught and re‑thrown on the server). Enable Sentry’s built‑in deduplication (debug: true to see duplicates) or use separate DSNs for client and server if your project allows scoped keys.
Concrete implementation (hybrid)
Below is a minimal, non‑tested example showing how to initialize both SDKs in a typical React/Express stack. Adjust versions to match your project.
1. Client‑side (React)
// src/sentryClient.js
import * as Sentry from '@sentry/browser';
Sentry.init({
dsn: 'https://@o0.ingest.sentry.io/0',
tracesSampleRate: 0.1, // adjust as needed
// optional: attach release, environment
});
export default Sentry;
Import this file early in your app (e.g., in index.js) so that uncaught exceptions are captured.
2. Server‑side (Express)
// server/sentryServer.js
const Sentry = require('@sentry/node');
Sentry.init({
dsn: 'https://@o0.ingest.sentry.io/0',
tracesSampleRate: 0.5, // maybe higher for backend
// attach request handler middleware
});
const express = require('express');
const app = express();
app.use(Sentry.Handlers.requestHandler());
// routes...
app.use(Sentry.Handlers.errorHandler());
module.exports = app;
Place the server init before defining routes so that the request handler can attach Sentry to the request lifecycle.
3. Validation steps
- Trigger a known client error (e.g.,
throw new Error('test client')) in the browser. Open Sentry → Events and verify the event includesbrowsercontext,url, and breadcrumbs if any. - Trigger a server error (e.g., a route that throws). Confirm the event shows
servercontext,hostname,request.id(if you set it), and lacks client‑side breadcrumbs. - Check the project’s
Settings → Client Keys (DSN)to ensure the client DSN is a scoped key with limited permissions if you need to restrict who can submit events. - Review
Settings → Rate Limitsand your sample rates to ensure the volume of test events matches expectations; adjusttracesSampleRateif you see excessive events.
Limitations and practical checks
- DSN exposure: The client DSN is visible to anyone viewing page source. If you need to restrict event submission, use a scoped key with allowed origins or place a proxy that forwards events after authentication.
- Duplicate events: If an error is caught on the client and re‑thrown on the server (or vice‑versa) with the same DSN, you may see two events. Enable
debug: truetemporarily to see duplicate warnings in the console, or use separate DSNs. - Performance: Client SDK sends payloads asynchronously; impact is negligible. Server SDK adds a small synchronous overhead during request handling proportional to the sampling and enrichment work.
- Version assumptions: Examples assume
@sentry/browser@7.xand@sentry/node@7.x. Older versions may have different init signatures.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.