sentry-performance-tracing
Set up performance monitoring and distributed tracing with Sentry. Use when implementing performance tracking, tracing requests, or monitoring application performance. Trigger with phrases like "sentry performance", "sentry tracing", "sentry APM", "monitor performance sentry".
Best use case
sentry-performance-tracing is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Set up performance monitoring and distributed tracing with Sentry. Use when implementing performance tracking, tracing requests, or monitoring application performance. Trigger with phrases like "sentry performance", "sentry tracing", "sentry APM", "monitor performance sentry".
Teams using sentry-performance-tracing should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/sentry-performance-tracing/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How sentry-performance-tracing Compares
| Feature / Agent | sentry-performance-tracing | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Set up performance monitoring and distributed tracing with Sentry. Use when implementing performance tracking, tracing requests, or monitoring application performance. Trigger with phrases like "sentry performance", "sentry tracing", "sentry APM", "monitor performance sentry".
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
AI Agents for Coding
Browse AI agent skills for coding, debugging, testing, refactoring, code review, and developer workflows across Claude, Cursor, and Codex.
Best AI Skills for Claude
Explore the best AI skills for Claude and Claude Code across coding, research, workflow automation, documentation, and agent operations.
ChatGPT vs Claude for Agent Skills
Compare ChatGPT and Claude for AI agent skills across coding, writing, research, and reusable workflow execution.
SKILL.md Source
# Sentry Performance Tracing
## Overview
Sentry performance monitoring captures distributed traces across your application stack, measuring latency, identifying bottlenecks, and tracking Web Vitals. The v8 SDK uses a span-based API where `Sentry.startSpan()` replaces the deprecated `startTransaction()`. Auto-instrumentation covers HTTP, database queries, and framework routes out of the box. Manual spans let you measure business-critical operations. Combined with profiling (`profilesSampleRate`), you get function-level flamegraphs attached to traces.
## Prerequisites
- Sentry SDK v8+ installed (`@sentry/node` >= 8.0.0 or `sentry-sdk` >= 2.0.0)
- `tracesSampleRate > 0` set in `Sentry.init()` — performance data is not collected at zero
- Performance monitoring enabled in your Sentry project settings (Settings > Performance)
- For distributed tracing: all participating services must have Sentry SDK initialized
## Instructions
### Step 1 — Configure Tracing and Profiling in SDK Init
Set `tracesSampleRate` to control what percentage of requests generate traces. Use `tracesSampler` for dynamic, per-endpoint sampling. Add `profilesSampleRate` to attach function-level flamegraphs to sampled transactions.
**TypeScript (`@sentry/node`):**
```typescript
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.2, // 20% of transactions in production
// Profiling — profiles 10% of sampled transactions
profilesSampleRate: 0.1,
// Dynamic sampling overrides tracesSampleRate when defined
tracesSampler: (samplingContext) => {
const { name, attributes } = samplingContext;
// Drop health checks entirely — no trace data
if (name === 'GET /health') return 0;
// Always trace payment flows
if (name?.includes('/api/payment')) return 1.0;
// Higher sampling for API routes
if (name?.startsWith('GET /api/') || name?.startsWith('POST /api/')) return 0.2;
// Default: 5% for everything else
return 0.05;
},
});
```
**Python (`sentry-sdk`):**
```python
import os
import sentry_sdk
sentry_sdk.init(
dsn=os.environ["SENTRY_DSN"],
traces_sample_rate=0.2, # 20% of transactions
profiles_sample_rate=0.1, # 10% of sampled transactions get profiled
# Dynamic sampling via traces_sampler (overrides traces_sample_rate)
traces_sampler=lambda ctx: (
0.0 if ctx.get("transaction_context", {}).get("name") == "GET /health"
else 1.0 if "/api/payment" in ctx.get("transaction_context", {}).get("name", "")
else 0.2
),
)
```
**Key decisions:**
- Start at `tracesSampleRate: 0.2` and adjust based on volume and budget
- `tracesSampler` takes priority when defined — `tracesSampleRate` becomes the fallback
- `profilesSampleRate` is relative to sampled transactions (0.1 means 10% of the 20% that are sampled)
- Return `0` from `tracesSampler` to explicitly drop a transaction, not `false`
### Step 2 — Create Custom Spans for Business Logic
Auto-instrumentation covers HTTP and database calls, but business-critical operations need manual spans. The v8 API provides three span creation methods for different use cases.
**`Sentry.startSpan()` — auto-ending spans (most common):**
```typescript
import * as Sentry from '@sentry/node';
const result = await Sentry.startSpan(
{
name: 'order.process',
op: 'task',
attributes: {
'order.id': orderId,
'order.items': items.length,
},
},
async (span) => {
// Nested spans automatically become children of the parent
const validated = await Sentry.startSpan(
{ name: 'order.validate', op: 'validation' },
async () => validateOrder(order)
);
const charged = await Sentry.startSpan(
{ name: 'payment.charge', op: 'http.client' },
async () => chargePayment(order.total)
);
// Set span status based on outcome
if (!charged.success) {
span.setStatus({ code: 2, message: 'payment_failed' });
}
// Add custom measurements visible in Performance dashboard
Sentry.setMeasurement('order.item_count', items.length, 'none');
Sentry.setMeasurement('order.total_cents', order.total, 'none');
return { validated, charged };
}
);
// Span automatically ends when callback resolves or rejects
```
**`Sentry.startSpanManual()` — for spans that cross callback boundaries:**
```typescript
Sentry.startSpanManual(
{ name: 'queue.process', op: 'queue.task' },
(span) => {
queue.on('message', async (msg) => {
try {
await processMessage(msg);
span.setStatus({ code: 1 }); // OK
} catch (error) {
span.setStatus({ code: 2, message: 'processing_failed' });
Sentry.captureException(error);
} finally {
span.end(); // REQUIRED — must call end() manually
}
});
}
);
```
**`Sentry.startInactiveSpan()` — background work without changing active context:**
```typescript
const span = Sentry.startInactiveSpan({
name: 'cache.warmup',
op: 'cache',
});
await warmCache(); // Other spans created here won't be children of this span
span.end();
```
**Span attributes and measurements:**
```typescript
await Sentry.startSpan(
{ name: 'search.query', op: 'db.query' },
async (span) => {
const start = Date.now();
const results = await searchIndex(query);
// Attributes — appear in span details, filterable in Sentry UI
span.setAttribute('search.query', query);
span.setAttribute('search.results_count', results.length);
span.setAttribute('search.index', indexName);
// Measurements — appear in Performance dashboard charts
Sentry.setMeasurement('search.duration_ms', Date.now() - start, 'millisecond');
Sentry.setMeasurement('search.result_count', results.length, 'none');
return results;
}
);
```
**Python equivalent:**
```python
import sentry_sdk
with sentry_sdk.start_span(op="task", name="process_order") as span:
span.set_data("order_id", order_id)
span.set_data("item_count", len(items))
with sentry_sdk.start_span(op="validation", name="validate_input"):
validate(input_data)
with sentry_sdk.start_span(op="http.client", name="charge_payment"):
result = charge(payment)
if not result.success:
span.set_status("internal_error")
```
### Step 3 — Enable Auto-Instrumentation and Distributed Tracing
SDK v8 auto-instruments most I/O without configuration. For distributed tracing across services, Sentry propagates `sentry-trace` and `baggage` headers automatically on HTTP calls. Custom propagation is needed only for non-HTTP transports (message queues, gRPC, etc.).
**Auto-instrumented integrations (Node.js v8):**
| Integration | What it traces | Enabled by |
|-------------|---------------|------------|
| `httpIntegration()` | All outbound HTTP/HTTPS requests | Default |
| `expressIntegration()` | Express route handlers and middleware | Default with Express |
| `fastifyIntegration()` | Fastify routes | Default with Fastify |
| `graphqlIntegration()` | GraphQL resolvers | Default with graphql |
| `mongoIntegration()` | MongoDB queries | Default with mongodb driver |
| `postgresIntegration()` | PostgreSQL queries (pg driver) | Default with pg |
| `mysqlIntegration()` | MySQL queries | Default with mysql2 |
| `redisIntegration()` | Redis commands | Default with ioredis/redis |
| `prismaIntegration()` | Prisma ORM queries | Default with @prisma/client |
**Express with custom middleware spans:**
```typescript
import express from 'express';
import * as Sentry from '@sentry/node';
const app = express();
// Sentry auto-instruments all Express routes
// Add custom spans for specific middleware:
app.use('/api', async (req, res, next) => {
await Sentry.startSpan(
{ name: 'middleware.auth', op: 'middleware' },
async () => {
req.user = await authenticateRequest(req);
}
);
next();
});
// Parameterized route names prevent cardinality explosion
// Sentry automatically uses '/api/users/:id' not '/api/users/12345'
app.get('/api/users/:id', async (req, res) => {
const user = await Sentry.startSpan(
{ name: 'db.getUser', op: 'db.query' },
() => db.users.findById(req.params.id)
);
res.json(user);
});
// Must be after all routes
Sentry.setupExpressErrorHandler(app);
```
**Django/Flask auto-instrumentation (Python):**
```python
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn=os.environ["SENTRY_DSN"],
integrations=[DjangoIntegration()],
traces_sample_rate=0.2,
profiles_sample_rate=0.1,
)
# All Django views, middleware, and template rendering are traced automatically
```
```python
# Flask equivalent
from sentry_sdk.integrations.flask import FlaskIntegration
sentry_sdk.init(
dsn=os.environ["SENTRY_DSN"],
integrations=[FlaskIntegration()],
traces_sample_rate=0.2,
)
```
```python
# FastAPI equivalent
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.starlette import StarletteIntegration
sentry_sdk.init(
dsn=os.environ["SENTRY_DSN"],
integrations=[FastApiIntegration(), StarletteIntegration()],
traces_sample_rate=0.2,
)
```
**Distributed tracing — custom header propagation:**
When Sentry cannot automatically propagate headers (non-HTTP transports, custom fetch wrappers), extract and inject manually:
```typescript
// Service A: Extract trace headers from the active span
const activeSpan = Sentry.getActiveSpan();
const traceHeaders = {
'sentry-trace': Sentry.spanToTraceHeader(activeSpan),
'baggage': Sentry.spanToBaggageHeader(activeSpan),
};
// Pass headers to downstream service via HTTP, message queue, etc.
await fetch('https://service-b.internal/api/process', {
headers: { ...traceHeaders, 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
// Service B: Sentry SDK automatically reads sentry-trace and baggage
// from incoming request headers and continues the same trace
```
**Browser Web Vitals (`@sentry/browser`):**
The browser SDK automatically captures Core Web Vitals when tracing is enabled:
- **LCP** (Largest Contentful Paint) — loading performance
- **INP** (Interaction to Next Paint) — responsiveness (replaced FID in 2024)
- **CLS** (Cumulative Layout Shift) — visual stability
- **TTFB** (Time to First Byte) — server response time
These appear in the **Web Vitals** tab of your Sentry Performance dashboard. No additional configuration beyond `tracesSampleRate > 0` in the browser SDK.
## Output
- Distributed traces visible in Sentry Performance > Trace View as span waterfalls
- Auto-instrumented spans for HTTP, database, and framework operations
- Custom spans with attributes measuring business-critical operations
- Profiling flamegraphs attached to sampled transactions
- Web Vitals (LCP, INP, CLS, TTFB) tracked for frontend performance
- Custom measurements charted in Performance dashboard
- Cross-service traces linked via `sentry-trace` and `baggage` headers
## Error Handling
| Error | Cause | Solution |
|-------|-------|----------|
| No transactions in Performance tab | `tracesSampleRate` is `0` or not set | Set `tracesSampleRate > 0` in `Sentry.init()` or define `tracesSampler` |
| Spans not nested correctly | Child span created outside parent callback | Call `Sentry.startSpan()` inside the parent `startSpan` callback to establish parent-child |
| High cardinality warning in Sentry UI | Dynamic values in span/transaction names | Use parameterized names (`/api/users/:id`) not literal values (`/api/users/12345`) |
| Distributed trace broken between services | `sentry-trace`/`baggage` headers not forwarded | Verify both headers are propagated in inter-service HTTP calls |
| `startSpanManual` span never ends | Missing `span.end()` call | Always call `span.end()` in a `finally` block |
| Profiling data missing | `profilesSampleRate` not set or `@sentry/profiling-node` not installed | Set `profilesSampleRate > 0` and install the profiling package |
| `tracesSampler` errors silently | Sampler function throws | Wrap sampler logic in try/catch, return a fallback rate |
| Performance data but no Web Vitals | Browser SDK not initialized or `tracesSampleRate` is 0 on client | Ensure `@sentry/browser` or `@sentry/react` is initialized with tracing |
## Examples
### TypeScript — Full Express API with Profiling
```typescript
import * as Sentry from '@sentry/node';
import express from 'express';
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.2,
profilesSampleRate: 0.1,
});
const app = express();
app.post('/api/orders', async (req, res) => {
const order = await Sentry.startSpan(
{ name: 'order.create', op: 'task', attributes: { 'order.source': 'api' } },
async (span) => {
const validated = await Sentry.startSpan(
{ name: 'order.validate', op: 'validation' },
() => validateOrder(req.body)
);
const saved = await Sentry.startSpan(
{ name: 'order.save', op: 'db.query' },
() => db.orders.create(validated)
);
await Sentry.startSpan(
{ name: 'notification.send', op: 'http.client' },
() => notifyWarehouse(saved.id)
);
Sentry.setMeasurement('order.total_cents', saved.total, 'none');
return saved;
}
);
res.status(201).json(order);
});
Sentry.setupExpressErrorHandler(app);
app.listen(3000);
```
### Python — FastAPI with Custom Spans
```python
import os
import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.starlette import StarletteIntegration
from fastapi import FastAPI
sentry_sdk.init(
dsn=os.environ["SENTRY_DSN"],
integrations=[FastApiIntegration(), StarletteIntegration()],
traces_sample_rate=0.2,
profiles_sample_rate=0.1,
)
app = FastAPI()
@app.post("/api/orders")
async def create_order(payload: OrderRequest):
with sentry_sdk.start_span(op="task", name="order.create") as span:
span.set_data("order_source", "api")
with sentry_sdk.start_span(op="validation", name="order.validate"):
validated = validate_order(payload)
with sentry_sdk.start_span(op="db.query", name="order.save"):
saved = await db.orders.create(validated)
with sentry_sdk.start_span(op="http.client", name="notification.send"):
await notify_warehouse(saved.id)
return {"id": saved.id, "status": "created"}
```
## Resources
- [Set Up Tracing — Node.js](https://docs.sentry.io/platforms/javascript/guides/node/tracing/)
- [Custom Instrumentation](https://docs.sentry.io/platforms/javascript/guides/node/tracing/instrumentation/custom-instrumentation/)
- [Distributed Tracing](https://docs.sentry.io/platforms/javascript/guides/node/tracing/distributed-tracing/)
- [Python Performance Monitoring](https://docs.sentry.io/platforms/python/tracing/)
- [Profiling — Node.js](https://docs.sentry.io/platforms/javascript/guides/node/profiling/)
- [Web Vitals](https://docs.sentry.io/product/insights/web-vitals/)
- [Performance Monitoring Product Guide](https://docs.sentry.io/product/performance/)
## Next Steps
- **Alerting on performance regressions**: Configure Performance Alerts in Sentry to trigger when p95 latency exceeds thresholds or throughput drops
- **Custom dashboards**: Build dashboards in Sentry using custom measurements (`Sentry.setMeasurement()`) to track business KPIs alongside latency
- **Span sampling in high-volume services**: Use `tracesSampler` to selectively trace slow endpoints at higher rates while keeping fast endpoints low
- **Connect to error tracking**: Errors captured with `Sentry.captureException()` inside a traced span automatically link to that trace in the Sentry UIRelated Skills
running-performance-tests
Execute load testing, stress testing, and performance benchmarking. Use when performing specialized testing. Trigger with phrases like "run load tests", "test performance", or "benchmark the system".
workhuman-performance-tuning
Workhuman performance tuning for employee recognition and rewards API. Use when integrating Workhuman Social Recognition, or building recognition workflows with HRIS systems. Trigger: "workhuman performance tuning".
wispr-performance-tuning
Wispr Flow performance tuning for voice-to-text API integration. Use when integrating Wispr Flow dictation, WebSocket streaming, or building voice-powered applications. Trigger: "wispr performance tuning".
windsurf-performance-tuning
Optimize Windsurf IDE performance: indexing speed, Cascade responsiveness, and memory usage. Use when Windsurf is slow, indexing takes too long, Cascade times out, or the IDE uses too much memory. Trigger with phrases like "windsurf slow", "windsurf performance", "optimize windsurf", "windsurf memory", "cascade slow", "indexing slow".
webflow-performance-tuning
Optimize Webflow API performance with response caching, bulk endpoint batching, CDN-cached live item reads, pagination optimization, and connection pooling. Use when experiencing slow API responses or optimizing request throughput. Trigger with phrases like "webflow performance", "optimize webflow", "webflow latency", "webflow caching", "webflow slow", "webflow batch".
vercel-performance-tuning
Optimize Vercel deployment performance with caching, bundle optimization, and cold start reduction. Use when experiencing slow page loads, optimizing Core Web Vitals, or reducing serverless function cold start times. Trigger with phrases like "vercel performance", "optimize vercel", "vercel latency", "vercel caching", "vercel slow", "vercel cold start".
veeva-performance-tuning
Veeva Vault performance tuning for REST API and clinical operations. Use when working with Veeva Vault document management and CRM. Trigger: "veeva performance tuning".
vastai-performance-tuning
Optimize Vast.ai GPU instance selection, startup time, and training throughput. Use when optimizing instance selection, reducing startup latency, or maximizing GPU utilization on rented hardware. Trigger with phrases like "vastai performance", "optimize vastai", "vastai slow", "vastai gpu utilization", "vastai throughput".
twinmind-performance-tuning
Optimize TwinMind transcription accuracy and speed with Ear-3 model configuration, audio quality tuning, and caching strategies. Use when implementing performance tuning, or managing TwinMind meeting AI operations. Trigger with phrases like "twinmind performance tuning", "twinmind performance tuning".
together-performance-tuning
Together AI performance tuning for inference, fine-tuning, and model deployment. Use when working with Together AI's OpenAI-compatible API. Trigger: "together performance tuning".
techsmith-performance-tuning
TechSmith performance tuning for Snagit COM API and Camtasia automation. Use when working with TechSmith screen capture and video editing automation. Trigger: "techsmith performance tuning".
stackblitz-performance-tuning
Optimize WebContainer boot time, file system mounts, and process spawning. Use when working with WebContainers or StackBlitz SDK. Trigger: "stackblitz performance".