How to estimate session replay storage cost before turning it on
Back-of-envelope math on rrweb payloads, retention, sample rate, and egress turned into a one-screen estimator.

You flip the "Session Replay" toggle in your SDK, and for the first 24 hours, it's pure magic. You can see exactly where users are getting stuck, which buttons they're rage-clicking, and why that obscure checkout bug only happens on Safari. Then the billing alert hits. Because you're recording 100% of sessions on a high-interaction Single Page Application (SPA), you've just committed to a storage bill that scales linearly with your success, often at a 10x markup over the raw costs of S3 or Cloudflare R2.
Most session replay pricing is intentionally opaque. It's hidden behind "units," "credits," or "sessions" that mask the underlying storage reality. But as a developer, you shouldn't be guessing. The physics of session replay data—specifically data generated by rrweb, the industry standard—are predictable. If you understand how a replay is constructed, you can use a simple "back-of-the-envelope" formula to predict your GB-per-month before you blow your budget.
The Physics of a Replay: Snapshots vs. Mutations
To estimate cost, you first have to understand that a "session" isn't a fixed-size video file. It's a stream of serialized DOM changes. When you use a tool like GlitchReplay or any Sentry-compatible SDK, the underlying technology is almost certainly rrweb. This library doesn't record pixels; it records the structure of your HTML and every single change that happens to it.
The Initial Full Snapshot (The Heavy Lift)
When a recording starts, rrweb takes a "Full Snapshot." This is a complete serialization of the current DOM tree. If your page is a complex React dashboard with thousands of nodes, this snapshot can be heavy. A "clean" landing page might yield a 50KB gzipped snapshot, while a heavy enterprise tool could easily hit 500KB or more for the first event alone. This is the "base tax" you pay for every single session recorded.
Incremental Mutations (The Long Tail)
Once the initial snapshot is captured, the recorder switches to "Incremental Mutations." Instead of sending the whole page again, it only sends the diffs: a user clicked a button, a class name changed, or a new <div> was appended to a list. These events are usually tiny—often less than 1KB. However, they happen constantly. Mouse movements, scroll events, and input changes add up over a five-minute session. In a high-frequency interaction environment, these tiny mutations can eventually dwarf the size of the initial snapshot.
Why SPAs produce 5x more data than static sites
On a static site, a user reads, scrolls, and clicks a link (which starts a new session or page view). On an SPA, the user stays on the "same" page while the entire DOM is ripped out and replaced during navigation. Because the recorder doesn't necessarily know that a "page change" happened in the same way a browser does, it often has to take new full snapshots to ensure the state is consistent, or it transmits a massive volume of childList mutations. This is why cost-predictability is harder for modern React or Vue apps than for traditional server-rendered sites.
{
"type": 3,
"data": {
"source": 0,
"texts": [],
"attributes": [
{
"id": 105,
"attributes": {
"class": "button-active"
}
}
],
"removals": [],
"adds": []
},
"timestamp": 1682515200000
}The snippet above represents a standard rrweb incremental mutation. It's lightweight, but multiply this by 60 interactions per minute, and you start to see the data stream take shape.
Calculating your Average Payload Size (APS)
You don't have to guess your data consumption. You can measure it in your browser right now. Average Payload Size (APS) is the most critical variable in your cost equation. To find it, open your browser's Network tab, filter for XHR/Fetch requests, and look for the outgoing packets to your replay ingestion endpoint (usually containing /envelope/ or /session-replay/).
Measuring gzipped vs. raw payloads
Almost all replay SDKs compress data before sending it. You want to look at the "Transferred" size, not the "Resource" size. If you see a request that is 20KB transferred but 150KB uncompressed, the 20KB is what hits your storage bill (and your user's data plan). If you're building your own ingestion or using a transparent provider, you'll find that gzipping rrweb JSON is incredibly efficient—often achieving 80-90% compression because the DOM structure is highly repetitive.
The "Interaction Factor": How mouse movements and scrolls add up
By default, most recorders capture mouse movements at a specific sample rate (e.g., every 50ms). If you have a "lean" app where users mostly read text, your APS will be low. If you have a "noisy" app (like a drawing tool, a map, or a complex drag-and-drop interface), your APS will skyrocket. When calculating your estimate, record a session of yourself actually *using* the app as a power user would, then divide the total transferred bytes by the number of minutes spent.
Media and Assets: Are you capturing styles or just DOM?
A common misconception is that session replays store images and CSS files. In reality, most tools just store the *links* to those assets. When you watch the replay, your browser fetches the images from your own CDN. However, some configurations (especially those designed to bypass CORS issues) will "inline" CSS or assets into the replay stream. This will balloon your storage costs instantly. Ensure you are only capturing the DOM structure unless you have a specific reason to inline styles.
// A quick way to check outgoing payload sizes in the console
const entries = performance.getEntriesByType('resource');
const replayRequests = entries.filter(e => e.name.includes('envelope'));
const totalBytes = replayRequests.reduce((sum, e) => sum + e.transferSize, 0);
console.log(`Total Replay Bytes Sent: ${(totalBytes / 1024).toFixed(2)} KB`);The Variables that Break the Budget
Once you have your APS, you need to look at the three levers that actually control the final invoice. This is where most "prosumer" tools make their margin—by betting you won't touch these defaults.
Total Monthly Sessions (The baseline)
If you have 1,000,000 monthly visitors and you record 100% of them, and your APS is 200KB per session, you are looking at 200GB of raw data. At raw S3 prices, that's negligible. At SaaS "unit" prices, that could be $500 to $2,000 depending on the vendor. The baseline is your traffic, and it's the hardest variable to change without losing visibility.
Retention Period: Why 30 days vs 90 days is a 3x multiplier
Storage is cumulative. If you keep data for 90 days, you are paying for three months of "success" at all times. Most developers find that they rarely watch a replay older than 14 days—usually, by then, the code has changed so much that the replay is no longer an accurate representation of the current bug. Reducing retention is the fastest way to slash a storage bill without touching your sampling rate.
The Power of Sampling: When 5% is better than 100%
This is the most underutilized tool in the developer's belt. Do you really need to see 10,000 people successfully log in? Or do you only need to see the 500 who failed? Sampling allows you to capture a statistically significant portion of your traffic for "vibe checks" while keeping costs low. A 5% sampling rate gives you 100% of the insights into common UX friction points at 1/20th of the cost.
Compare these two scenarios:
- Scenario A: 100k sessions, 100% capture, 90-day retention = 60GB stored.
- Scenario B: 1M sessions, 10% capture, 30-day retention = 20GB stored.
Scenario B gives you the same amount of "useful" data from a much larger pool of users, but results in a bill that is 66% lower.
Beyond Storage: Ingestion and Egress
When you look at a vendor's pricing, you aren't just paying for the "hard drive" space. You are paying for the compute power required to receive that data and the bandwidth required to serve it back to you. These "hidden" costs are often used to justify the high markups.
Ingestion overhead and API worker costs
Every time an SDK sends a packet, a server has to receive it, validate the API key, check rate limits, and write it to a database. On high-traffic sites, this "ingestion" layer is incredibly expensive to maintain. This is why many vendors charge per "event" rather than per GB—they are charging you for the number of times their API has to wake up and do work.
Egress: What happens when you actually want to watch the replays?
Cloud providers like AWS charge "Egress fees" to move data out of their network. If you store 1TB of replays and your team watches them all, the vendor has to pay AWS to send that TB to your browser. Many SaaS companies bake a massive buffer into their pricing to cover these egress spikes. If you are self-hosting on S3, you need to account for the fact that every time you watch a replay, you're adding a few cents to your AWS bill.
The "Cloudflare Advantage": Why flat-rate storage is changing the math
The landscape is shifting because of providers like Cloudflare and their R2 storage. R2 has zero egress fees. This means the "cost of watching" has dropped to zero. Tools built on this modern stack, like GlitchReplay, can afford to offer much more aggressive pricing because they aren't being taxed by their own infrastructure provider every time you click "Play." When choosing a tool, ask if they charge for "seats" or "viewing time"—if they do, they're likely passing on old-school egress costs to you.
Optimization Strategies for High-Traffic Apps
If you have a high-traffic app, you shouldn't just "turn on" replays and hope for the best. You should implement a strategy that maximizes ROI. You want the highest possible visibility into errors with the lowest possible storage of "happy paths."
Error-only Replays: The highest ROI sampling strategy
Most Sentry-compatible SDKs allow you to set two different sampling rates: one for general sessions and one for sessions that encounter an error. This is the "gold standard" for cost-effective debugging. You can set your general sampling to 0% and your error sampling to 100%. This means you store *nothing* until something breaks. When an error occurs, the SDK "backfills" the last minute of activity from the local buffer and starts recording the rest of the session.
Scrubbing PII to reduce payload size (and liability)
Scrubbing PII (Personally Identifiable Information) isn't just about security; it's about data weight. When you mask all text inputs, you replace varied, unique strings with repetitive characters like "***". Because compression algorithms (like Gzip or Brotli) thrive on repetition, a masked session is often 10-15% smaller than an unmasked one. For more on this, check out our PII scrubbing guide.
Triggering capture based on specific user actions
You don't have to rely on random sampling. You can trigger recording programmatically. If you know that your "Billing" page is where people struggle, you can call SDK.startRecording() only when a user hits that specific route. This ensures every byte you pay for is "high-value" data.
// Optimal SDK Configuration for Budget-Conscious Teams
Sentry.init({
dsn: "your-dsn",
replaysSessionSampleRate: 0.05, // Record 5% of all users for UX research
replaysOnErrorSampleRate: 1.0, // Record 100% of users who see a crash
maskAllText: true,
maskAllInputs: true,
});The "Back of Envelope" Formula
Now, let's put it all together. To estimate your monthly storage, use this equation:
(Total Monthly Sessions × Sample Rate) × (Avg Session Length in Mins × Bytes Per Min) × (Retention in Days / 30)
Benchmarking against industry averages
If you don't want to measure your own app yet, you can use these "safe" benchmarks for gzipped rrweb data:
- Static/Low Interaction: 50KB - 100KB per minute
- Standard SaaS/Dashboard: 150KB - 300KB per minute
- High Interaction (Editor/Game/Map): 500KB - 1MB+ per minute
Example Scenario
Let's say you run a standard SaaS app with 500,000 sessions per month. You decide to sample 10% of sessions for 30 days. Your average user stays for 3 minutes.
(500,000 × 0.10) × (3 mins × 200KB) = 50,000 sessions × 600KB = 30,000,000KB ≈ 30GB per month.
At raw storage prices ($0.015/GB on R2), your storage cost is $0.45. If a vendor is charging you $200 for this same "tier," you are paying a 400x markup for the ingestion and UI layer. This is why we built GlitchReplay with flat-rate pricing—because we know the "math of the cloud" has made the old unit-based pricing models obsolete.
Building a One-Screen Estimator
We know that doing this math by hand is a chore. That's why we built the Replay Storage Estimator. You can plug in your traffic, your estimated session length, and your retention needs to see exactly how much data you'll be generating. It even allows you to compare costs across major vendors vs. raw storage costs.
Stop guessing what your monthly bill will be. Use our tool to model your traffic and retention before you buy, and remember: you don't need to record everything to see everything. Smart sampling and a clear understanding of your payload size are the only things standing between you and a "surprise" four-figure bill.
GlitchReplay is Sentry-SDK compatible, includes session replay and security signals, and never charges per event. Free to start, five minutes to first event.