When Your Database Takes 9 Seconds to Say Hello: A Session Replay Story
-
You shipped a feature. Users loved it. Then one user casually mentioned it takes "forever" to load. You check your metrics. Response times look fine. You check your logs. Everything returned 200. You check your monitoring dashboard. Green lights everywhere.
So you shrug and move on. Mistake.
Three weeks later, you are staring at a 23% drop in user engagement. Your product manager wants answers. Your engineering lead wants answers. Your CEO wants answers. And you have nothing but a hunch that "something feels slow."
Here is what actually happened: your database connection pooling silently died. Requests that should take 50 milliseconds were taking 9 seconds. But because you were only logging aggregate metrics, you missed it entirely. By the time you noticed, your users had already decided your product was broken.
Session Replay would have caught this on day one. Let me show you how.
The Problem with Traditional Monitoring
Most monitoring setups track two things:
1. Did the request succeed?
2. How long did it take on average?
This is fine until it is not. Because averages lie. A p50 of 200ms looks great. A p99 of 8 seconds is a disaster. And when your monitoring only shows you the happy path, you miss the disasters entirely.
Traditional application performance monitoring gives you numbers. Session Replay gives you the movie. You see the exact sequence of events that led to the problem. You see what the user saw. You see what your code did. You see where time disappeared.
No guessing. No theorizing. Just facts.
What We Found in OpenBuilder
I recently analyzed Session Replay data from one of our internal projects, [OpenBuilder](https://buildwithcode.sentry.io/projects/openbuilder/). It is a code generation tool we use for rapid prototyping. Users describe what they want to build, and the system generates working code.
The replays told a story. And it was not a happy one.
Build Operations Taking 5+ Minutes
The first thing that jumped out: build enhancement requests were taking anywhere from 80 to 318 seconds. Over five minutes. For a single enhancement.
Here is replay [b44f8c8405094c4aa34dad7f1e768206](https://buildwithcode.sentry.io/replays/b44f8c8405094c4aa34dad7f1e768206/) showing a 318-second build operation. The user clicked "Enhance Build." Then waited. And waited. And eventually gave up and clicked again.
We found multiple build operations marked as cancelled in the traces. Users were not canceling because they changed their minds. They were canceling because they thought the system was broken. Spoiler: they were right.
build.enhancement
span.duration: 318392ms
span.status: unknown
traceid: bf7f82adc83f40debf3861a7f2ec3179
This is not a bug you catch with error tracking. The request succeeded. The status was "unknown" not "error." The system returned a valid response. But the user experience was terrible.
Database Connections Taking 9 Seconds
The second issue was even worse. PostgreSQL connection operations were taking 2.7 to 9.3 seconds. Just to establish a connection.
Look at replay [65a20d28e00c4f81bfa50373592b9b44](https://buildwithcode.sentry.io/replays/65a20d28e00c4f81bfa50373592b9b44/). The user loaded their project list. The page sat there. Loading spinner. Nothing. Then, nine seconds later, the data finally appeared.
pg.connect
span.duration: 9311ms
transaction: GET /api/projects
db.system: postgresql
This hit every critical endpoint:
/api/projects - 9.3 seconds to list projects
/api/projects/[id]/messages - 8.5 seconds to load messages
/api/projects/[id] - 8.4 seconds to fetch project details
Every page load. Every interaction. Delayed by connection pooling that had quietly failed.
Our metrics showed p50 latency of 250ms. But Session Replay showed us the p99: users waiting nearly 10 seconds for basic operations. Metrics said everything was fine. Users said the product was broken. Users were right.
The Waterfall Effect Nobody Saw Coming
Here is where it gets worse. These two problems compounded each other.
A user would load a project. That triggered:
1. Database connection (9 seconds)
2. Fetch project metadata (3 seconds)
3. Load associated messages (8 seconds)
4. Check GitHub integration status (2.7 seconds)
Total time: 22+ seconds. For one page load.
But because each operation technically succeeded, our error tracking saw nothing. Our APM showed healthy aggregate metrics. And our dashboards stayed green while our users quietly rage-quit.
Session Replay [608ba2acb0b5469b8ab43d95e23008d5](https://buildwithcode.sentry.io/replays/608ba2acb0b5469b8ab43d95e23008d5/) captured the entire sequence. We could see the user click. We could see each API call queue up. We could see the loading states stack on top of each other. We could see the exact moment the user gave up and closed the tab.
What Makes Session Replay Different
Traditional monitoring tells you something broke. Session Replay tells you why users care.
Here is what we learned from just 10 replay sessions:
Build performance was unusable
Longest operation: 318 seconds
Multiple cancelled operations
No progress indicators for long-running tasks
Database connections were failing silently
Connection pool exhaustion
9+ second delays on basic queries
Cascading failures across the app
User experience was degrading incrementally
No single catastrophic failure
Slow accumulation of small delays
Death by a thousand cuts
None of this showed up in our dashboards. None of this triggered alerts. But Session Replay caught it all because it recorded what actually happened, not what we thought should happen.
How to Actually Use Session Replay
Session Replay is not a replacement for logs or metrics. It is the missing piece that connects technical data to user experience.
Link Replays to Performance Traces
Every slow database query in OpenBuilder had a replay ID attached:
import as Sentry from "@sentry/node";
const transaction = Sentry.startTransaction({
name: "GET /api/projects",
op: "http.server",
});
// Sentry automatically links the replay
const span = transaction.startChild({
op: "db.query",
description: "pg.connect",
});
await pool.connect();
span.finish();
transaction.finish();
Now when we see a slow query, we can jump directly to the replay and watch it happen in context. No reproduction steps needed. No "can you send me your environment." Just click and watch.
Filter by Performance Issues
In Sentry, you can filter replays by span duration:
has:replayId AND span.duration:>2000
This surfaces every replay where any operation took longer than 2 seconds. For OpenBuilder, this immediately showed us:
30 build operations over 80 seconds
20 database connections over 2.7 seconds
Multiple cancelled operations
We went from "users say it is slow" to "here are the exact sessions where it was slow and here is what caused it" in about five minutes.
Track Rage Clicks and Dead Clicks
Replay [a683ec7ecbe942c28c7d267ff07349c3](https://buildwithcode.sentry.io/replays/a683ec7ecbe942c28c7d267ff07349c3/) showed something interesting: a user clicked the "Enhance Build" button seven times in 30 seconds.
This was not a bug. The button worked. The request went through. But from the user's perspective, nothing happened. So they clicked again. And again. And again.
Session Replay automatically flags this as a "rage click." It tells you exactly where users are getting frustrated, even when the code is technically working.
Catch Silent Failures
Remember those cancelled build operations? They did not throw errors. They did not fail. They just... stopped. And returned nothing.
build.enhancement
span.duration: 185333ms
span.status: cancelled
traceid: e56c6dc2a23e4326a68fc70217e83924
Session Replay showed us the pattern: user clicks button, loading state appears, 3+ minutes pass, user clicks cancel, nothing happens. The operation stops but there is no error. No feedback. Just silence.
You cannot fix what you cannot see. And you cannot see what traditional monitoring does not track.
What Good Looks Like
After adding Session Replay, here is what our debugging workflow became:
1. User reports slowness → Search replays by user ID
2. Performance alert fires → Filter replays by trace ID
3. Unusual metric spike → Watch replays from that time window
4. Feature feels broken → Look for rage clicks and dead clicks
Instead of asking users to reproduce issues or digging through logs trying to piece together context, we just watch what happened. Then we fix it.
For OpenBuilder specifically, the replay data led to three immediate fixes:
Upgrade database connection pooling
Increased pool size from 10 to 50
Added connection timeout monitoring
Set up alerts for pool exhaustion
Add progress indicators for long operations
Show build progress in real-time
Display estimated time remaining
Let users cancel gracefully
Optimize build operations
Move heavy processing to background jobs
Stream results as they become available
Cache common enhancement patterns
We went from 318-second builds to sub-60-second builds. We went from 9-second database connections to sub-100ms connections. And we went from users rage-clicking to users shipping features.
All because we could finally see what they were seeing.
The Thing Nobody Tells You About Performance Issues
Here is the uncomfortable truth: your monitoring is probably lying to you.
Not intentionally. But aggregate metrics hide outliers. Averages smooth over disasters. And green dashboards make you think everything is fine when users are actually suffering.
You need to see the variance. You need to see the p99. You need to see what happens when things go wrong. And you need to see it in context, with the full user journey, not just isolated data points.
Session Replay does that. It captures the movie, not just the summary statistics.
For OpenBuilder, we had 10 replay sessions with performance issues. That represented 10 real users who experienced our product at its worst. Some clicked away. Some rage-clicked. Some gave up entirely. And we would have missed all of them if we were only looking at our dashboards.
So stop guessing. Stop asking users to reproduce issues. Stop staring at aggregate metrics wondering why engagement is dropping.
Just watch what actually happened.
Get Started
Session Replay is available in Sentry for all plans. To enable it:
1. Install the Sentry SDK (if you have not already)
2. Add the Replay integration to your config
3. Set a sample rate (start with 10% of sessions)
import as Sentry from "@sentry/browser";
Sentry.init({
dsn: "YOURDSN",
integrations: [
Sentry.replayIntegration({
maskAllText: false,
blockAllMedia: false,
}),
],
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
});
Then link replays to your backend traces:
import as Sentry from "@sentry/node";
Sentry.init({
dsn: "YOURDSN",
tracesSampleRate: 1.0,
});
That is it. Sentry automatically connects frontend replays to backend traces. When a slow query happens, you will see it in context with the full user session.
Check out the [Session Replay docs](https://docs.sentry.io/product/session-replay/) to learn more, join the discussion in [Discord](https://discord.com/invite/sentry), or if you are new to Sentry, you can [get started for free](https://sentry.io/pricing/).
Now go watch some replays. Your dashboards have been lying to you.

