| name | sentry-setup-tracing |
| description | Setup Sentry Tracing (Performance Monitoring) in any project. Use this when asked to add performance monitoring, enable tracing, track transactions/spans, or instrument application performance. Supports JavaScript, TypeScript, Python, Ruby, React, Next.js, and Node.js. |
Setup Sentry Tracing
This skill helps configure Sentry's Tracing (Performance Monitoring) to track application performance, measure latency, and create distributed traces across services.
When to Use This Skill
Invoke this skill when:
- User asks to "setup tracing" or "enable performance monitoring"
- User wants to "track transactions" or "measure latency"
- User requests "distributed tracing" or "span instrumentation"
- User mentions tracking API response times or page load performance
- User asks about
tracesSampleRate or custom spans
Platform Detection
Before configuring, detect the project's platform:
JavaScript/TypeScript
Check package.json for:
@sentry/nextjs - Next.js
@sentry/react - React
@sentry/node - Node.js
@sentry/browser - Browser/vanilla JS
@sentry/vue - Vue
@sentry/angular - Angular
@sentry/sveltekit - SvelteKit
Python
Check for sentry-sdk in requirements
Ruby
Check for sentry-ruby in Gemfile
Core Concepts
Explain these concepts to the user:
| Concept | Description |
|---|
| Trace | Complete journey of a request across services |
| Transaction | Single instance of a service being called (root span) |
| Span | Individual unit of work within a transaction |
| Sample Rate | Percentage of transactions to capture (0-1) |
JavaScript/TypeScript Configuration
Step 1: Locate Sentry Init
Find the Sentry.init() call:
- Next.js:
instrumentation-client.ts, sentry.server.config.ts, sentry.edge.config.ts
- React:
src/index.tsx or entry file
- Node.js: Entry point or config file
- Vue/Angular: Main app initialization
Step 2: Enable Tracing
Browser/React - Add browserTracingIntegration
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "YOUR_DSN_HERE",
integrations: [Sentry.browserTracingIntegration()],
tracesSampleRate: 1.0,
tracePropagationTargets: [
"localhost",
/^https:\/\/yourserver\.io\/api/,
],
});
Next.js - Configure All Init Files
Client (instrumentation-client.ts):
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: "YOUR_DSN_HERE",
tracesSampleRate: 1.0,
});
Server (sentry.server.config.ts):
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: "YOUR_DSN_HERE",
tracesSampleRate: 1.0,
});
Edge (sentry.edge.config.ts):
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: "YOUR_DSN_HERE",
tracesSampleRate: 1.0,
});
Next.js 14+ App Router Requirement:
For distributed tracing in App Router, add trace data to root layout metadata:
import * as Sentry from "@sentry/nextjs";
export async function generateMetadata() {
return {
other: {
...Sentry.getTraceData(),
},
};
}
Node.js
const Sentry = require("@sentry/node");
Sentry.init({
dsn: "YOUR_DSN_HERE",
tracesSampleRate: 1.0,
});
Step 3: Configure Sampling
Option A: Uniform Sample Rate (Simple)
Sentry.init({
tracesSampleRate: 0.2,
});
Option B: Dynamic Sampling (Advanced)
Sentry.init({
tracesSampler: ({ name, attributes, parentSampled }) => {
if (name.includes("healthcheck")) {
return 0;
}
if (name.includes("auth")) {
return 1;
}
if (name.includes("comment")) {
return 0.01;
}
if (typeof parentSampled === "boolean") {
return parentSampled;
}
return 0.5;
},
});
Note: If both tracesSampleRate and tracesSampler are set, tracesSampler takes precedence.
Browser Tracing Integration Options
The browserTracingIntegration() accepts many configuration options:
Sentry.init({
integrations: [
Sentry.browserTracingIntegration({
tracePropagationTargets: ["localhost", /^https:\/\/api\./],
beforeStartSpan: (context) => {
return {
...context,
name: context.name.replace(/\/users\/\d+/, "/users/:id"),
};
},
shouldCreateSpanForRequest: (url) => {
return !url.includes("healthcheck");
},
idleTimeout: 1000,
finalTimeout: 30000,
childSpanTimeout: 15000,
instrumentNavigation: true,
instrumentPageLoad: true,
enableLongTask: true,
enableInp: true,
interactionsSampleRate: 1.0,
}),
],
});
Python Configuration
Step 1: Enable Tracing
import sentry_sdk
sentry_sdk.init(
dsn="YOUR_DSN_HERE",
traces_sample_rate=1.0,
)
Step 2: Configure Sampling
Uniform Rate
sentry_sdk.init(
dsn="YOUR_DSN_HERE",
traces_sample_rate=0.2,
)
Dynamic Sampling
def traces_sampler(sampling_context):
transaction_name = sampling_context.get("transaction_context", {}).get("name", "")
if "healthcheck" in transaction_name:
return 0
if "auth" in transaction_name:
return 1.0
if sampling_context.get("parent_sampled") is not None:
return sampling_context["parent_sampled"]
return 0.5
sentry_sdk.init(
dsn="YOUR_DSN_HERE",
traces_sampler=traces_sampler,
)
Ruby Configuration
Enable Tracing
Sentry.init do |config|
config.dsn = "YOUR_DSN_HERE"
config.traces_sample_rate = 1.0
end
Dynamic Sampling
Sentry.init do |config|
config.dsn = "YOUR_DSN_HERE"
config.traces_sampler = lambda do |sampling_context|
transaction_name = sampling_context[:transaction_context][:name]
return 0 if transaction_name.include?("healthcheck")
return 1.0 if transaction_name.include?("auth")
0.5
end
end
Custom Instrumentation
JavaScript Custom Spans
Using startSpan (Recommended)
const result = Sentry.startSpan(
{ name: "expensive-calculation", op: "function" },
() => {
return calculateSomething();
}
);
const result = await Sentry.startSpan(
{ name: "fetch-user-data", op: "http.client" },
async () => {
const response = await fetch("/api/user");
return response.json();
}
);
const result = await Sentry.startSpan(
{
name: "process-order",
op: "task",
attributes: {
"order.id": orderId,
"order.amount": amount,
},
},
async () => {
return processOrder(orderId);
}
);
Nested Spans
await Sentry.startSpan({ name: "checkout-flow", op: "transaction" }, async () => {
await Sentry.startSpan({ name: "validate-cart", op: "validation" }, async () => {
await validateCart();
});
await Sentry.startSpan({ name: "process-payment", op: "payment" }, async () => {
await processPayment();
});
await Sentry.startSpan({ name: "send-confirmation", op: "email" }, async () => {
await sendConfirmationEmail();
});
});
Manual Span Control
function middleware(req, res, next) {
return Sentry.startSpanManual({ name: "middleware", op: "middleware" }, (span) => {
res.once("finish", () => {
span.setStatus({ code: res.statusCode < 400 ? 1 : 2 });
span.end();
});
return next();
});
}
Inactive Spans (Browser)
let checkoutSpan;
function onStartCheckout() {
checkoutSpan = Sentry.startInactiveSpan({ name: "checkout-flow" });
Sentry.setActiveSpanInBrowser(checkoutSpan);
}
function onCompleteCheckout() {
checkoutSpan?.end();
}
Python Custom Spans
Using Decorator (Simplest)
import sentry_sdk
@sentry_sdk.trace
def expensive_function():
return do_work()
@sentry_sdk.trace(op="database", name="fetch-users")
def fetch_users():
return db.query(User).all()
Using Context Manager
import sentry_sdk
def process_order(order_id):
with sentry_sdk.start_span(name="process-order", op="task") as span:
span.set_data("order.id", order_id)
with sentry_sdk.start_span(name="validate-order", op="validation"):
validate(order_id)
with sentry_sdk.start_span(name="charge-payment", op="payment"):
charge(order_id)
return {"success": True}
Manual Transaction
import sentry_sdk
with sentry_sdk.start_transaction(op="task", name="batch-process") as transaction:
for item in items:
with sentry_sdk.start_span(name=f"process-item-{item.id}"):
process(item)
transaction.set_tag("items_processed", len(items))
Centralized Configuration
sentry_sdk.init(
dsn="YOUR_DSN_HERE",
traces_sample_rate=1.0,
functions_to_trace=[
{"qualified_name": "myapp.services.process_order"},
{"qualified_name": "myapp.services.send_notification"},
],
)
Distributed Tracing
How It Works
Sentry propagates trace context via HTTP headers:
sentry-trace: Contains trace ID, span ID, sampling decision
baggage: Contains additional trace metadata
Configure Trace Propagation Targets
Only URLs matching these patterns receive trace headers:
Sentry.init({
tracePropagationTargets: [
"localhost",
"https://api.yourapp.com",
/^https:\/\/.*\.yourapp\.com\/api/,
],
});
Server-Side Rendering (Meta Tags)
For SSR apps, inject trace data in HTML:
const traceData = Sentry.getTraceData();
The browser SDK automatically reads these and continues the trace.
Manual Propagation
For non-HTTP channels (WebSockets, message queues):
const traceData = Sentry.getTraceData();
sendMessage({
...payload,
_traceHeaders: traceData,
});
Sentry.continueTrace(
{
sentryTrace: message._traceHeaders["sentry-trace"],
baggage: message._traceHeaders["baggage"],
},
() => {
processMessage(message);
}
);
Common Operation Types
Use consistent op values for better organization:
| Operation | Use Case |
|---|
http.client | Outgoing HTTP requests |
http.server | Incoming HTTP requests |
db | Database operations |
db.query | Database queries |
cache | Cache operations |
task | Background tasks |
function | Function execution |
ui.render | UI rendering |
ui.action | User interactions |
serialize | Serialization |
middleware | Middleware execution |
What Gets Automatically Traced
Browser (with browserTracingIntegration)
- Page loads
- Navigation/route changes
- XHR/fetch requests
- Long tasks
- Interaction to Next Paint (INP)
Next.js
- API routes
- Server components
- Page renders
- Data fetching
Node.js (with framework integrations)
- HTTP requests (Express, Fastify, etc.)
- Database queries (with ORM integrations)
- External API calls
Python (with framework integrations)
- Django views, middleware, templates
- Flask routes
- FastAPI endpoints
- SQLAlchemy queries
- Celery tasks
Disabling Tracing
Important: Setting tracesSampleRate: 0 does NOT disable tracing - it still processes traces but never sends them.
To fully disable tracing, omit both sampling options:
Sentry.init({
dsn: "YOUR_DSN_HERE",
});
Production Sampling Recommendations
| Traffic Level | Recommended Rate |
|---|
| Development/Testing | 1.0 (100%) |
| Low traffic (<1K req/min) | 0.5 - 1.0 |
| Medium traffic (1K-10K req/min) | 0.1 - 0.5 |
| High traffic (>10K req/min) | 0.01 - 0.1 |
Use dynamic sampling to capture more of important transactions:
tracesSampler: ({ name }) => {
if (name.includes("checkout") || name.includes("payment")) {
return 1.0;
}
return 0.1;
},
Verification Steps
After setup, verify tracing is working:
JavaScript
await Sentry.startSpan(
{ name: "test-transaction", op: "test" },
async () => {
console.log("Tracing test");
await new Promise(resolve => setTimeout(resolve, 100));
}
);
Python
with sentry_sdk.start_transaction(op="test", name="test-transaction"):
print("Tracing test")
Check in Sentry:
- Go to Performance section
- Look for your test transaction
- Verify spans appear in the trace waterfall
Common Issues and Solutions
Issue: Transactions not appearing
Solutions:
- Verify
tracesSampleRate > 0 or tracesSampler returns > 0
- Check DSN is correct
- For browser: Ensure
browserTracingIntegration() is added
- Wait a few minutes for data to process
Issue: Distributed traces not connected
Solutions:
- Check
tracePropagationTargets includes your API URLs
- Verify CORS allows
sentry-trace and baggage headers
- For SSR: Ensure trace meta tags are rendered
Issue: Too many transactions (high volume)
Solutions:
- Lower
tracesSampleRate
- Use
tracesSampler to filter by transaction name
- Use
shouldCreateSpanForRequest to skip health checks
Issue: Spans not nested correctly
Solutions:
- Ensure parent span is still active when creating child
- Use
startSpan callback pattern (not manual)
- For browser: Consider
parentSpanIsAlwaysRootSpan: false
Summary Checklist
## Sentry Tracing Setup Complete
### Configuration Applied:
- [ ] `tracesSampleRate` or `tracesSampler` configured
- [ ] Browser: `browserTracingIntegration()` added
- [ ] `tracePropagationTargets` configured for APIs
- [ ] Next.js App Router: `getTraceData()` in metadata
### Sampling Strategy:
- [ ] Development: 100% sampling for testing
- [ ] Production: Appropriate rate based on traffic
### Custom Instrumentation (if applicable):
- [ ] Critical paths instrumented with custom spans
- [ ] Consistent `op` values used
### Next Steps:
1. Trigger some requests in your application
2. Check Sentry > Performance for transactions
3. Review trace waterfalls for span hierarchy
4. Adjust sampling rates based on volume
Quick Reference
| Platform | Enable Tracing | Custom Span |
|---|
| JS/Browser | tracesSampleRate + browserTracingIntegration() | Sentry.startSpan() |
| Next.js | tracesSampleRate (auto-integrated) | Sentry.startSpan() |
| Node.js | tracesSampleRate | Sentry.startSpan() |
| Python | traces_sample_rate | @sentry_sdk.trace or start_span() |
| Ruby | traces_sample_rate | start_span() |
| Sampling Option | Purpose |
|---|
tracesSampleRate | Uniform percentage (0-1) |
tracesSampler | Dynamic function (takes precedence) |