Capacity Planning From Real-User Data: Sizing Ahead of Next Quarter's Traffic
Your analytics already show next quarter's infra needs. Here's how to extract traffic curves, predict peaks, and right-size before you get paged.
The Slack message came in at 11:47pm on a Tuesday. "Site's slow. Dashboard shows 503s spiking." I pulled up the infrastructure console. CPU at 94% across all API nodes. Memory pressure forcing aggressive garbage collection. Auto-scaling had kicked in but the new nodes weren't warm yet — and traffic was still climbing.
We'd grown 40% that quarter. I knew we'd grown 40% that quarter. Our analytics dashboard showed it clearly. But somehow, nobody had asked the obvious question: if traffic grew 40% last quarter, what happens when it grows another 40% this quarter?
Embarrassing.
The data was right there — we just didn't connect the dots between analytics traffic curves and infrastructure capacity. Look, I've been doing this for years and I still made that mistake. So no judgment if you're in the same boat.
What You'll Have by the End
A working capacity planning workflow that:
- Extracts traffic patterns from your existing RUM and analytics data
- Identifies weekly cycles, monthly patterns, and growth trends
- Forecasts next quarter's peak load with reasonable confidence
- Translates pageviews and requests into actual infrastructure requirements
- Gives you a number to hand to your platform team (or plug into your auto-scaling config)
We'll build this using JustAnalytics data, but the approach works with any analytics platform that exports raw traffic metrics. The goal is connecting what you already measure — pageviews, sessions, API calls — to what you actually need: CPU, memory, and connection pool capacity.
Prerequisites
Before we start:
- At least 30 days of traffic data (90+ days is better for capturing monthly patterns)
- Access to your analytics dashboard with hourly or daily granularity exports
- Basic familiarity with spreadsheets or a scripting language for the math
- Knowledge of your current infrastructure's capacity limits (or willingness to load test to find them)
If you're running JustAnalytics, the Pro plan ($49/month) includes the data export and API access you'll need. The Free tier (100K events/month) works for smaller sites but may not have enough volume for reliable patterns.
Step 1: Export Your Traffic Baseline
First, pull your historical traffic data. You need hourly or daily granularity — weekly aggregates hide the spikes that matter.
In JustAnalytics, navigate to Analytics > Traffic > Export. Select the last 90 days minimum. Export as CSV with these columns:
- Timestamp (hourly buckets)
- Pageviews
- Unique sessions
- API requests (if you're tracking server-side events)
Here's what the raw data looks like:
timestamp,pageviews,sessions,api_requests
2026-05-22T00:00:00Z,1247,423,8934
2026-05-22T01:00:00Z,892,287,6421
2026-05-22T02:00:00Z,456,142,3201
...
The API requests column is gold for capacity planning. Pageviews tell you user activity. API requests tell you server load. One pageview might trigger 3-15 API calls depending on your architecture. (Ours triggers 7 on average. I counted.)
If you're using OpenTelemetry for tracing, you can pull request counts directly from span data. Our distributed tracing guide covers that setup.
Step 2: Identify Your Traffic Patterns
Traffic isn't random. It follows predictable cycles that repeat weekly and monthly. Finding these patterns is the core of forecasting.
Weekly patterns: Most B2B SaaS sees peaks Tuesday-Thursday, with 30-50% drops on weekends. Consumer products often flip that. Your pattern is specific to your users — don't assume.
Daily patterns: When are your peaks? Enterprise tools often see morning spikes when people start work. Consumer apps might peak evenings. International products have multiple peaks across timezones.
Monthly patterns: End-of-month is common for business tools. Beginning-of-month for payroll-adjacent products. Look for these in your 90-day export.
Calculate these in a spreadsheet:
Peak hour / Average hour = Hourly peak factor
Peak day / Average day = Daily peak factor
Peak week / Average week = Weekly peak factor
For our API:
- Hourly peak factor: 2.3x (Tuesday 10am vs 3am)
- Daily peak factor: 1.4x (Wednesday vs Sunday)
- Monthly peak factor: 1.2x (last week of month vs first week)
These factors compound. A monthly peak on the peak day at peak hour is 2.3 × 1.4 × 1.2 = 3.9x your average load. If your infrastructure only handles 2x average, you're gonna have a bad time.
(Ask me how I know.)
Step 3: Calculate Your Growth Rate
Pull up your monthly totals for the last 6-12 months. Calculate month-over-month growth:
Growth rate = (This month - Last month) / Last month × 100
Don't use a single month — that's noise. Average across 3-6 months to smooth out anomalies:
Month 1: 45,000 requests
Month 2: 51,000 requests (+13.3%)
Month 3: 56,000 requests (+9.8%)
Month 4: 64,000 requests (+14.3%)
Month 5: 72,000 requests (+12.5%)
Month 6: 79,000 requests (+9.7%)
Average MoM growth: 11.9%
That 11.9% compounded over three months means next quarter ends at roughly 1.4x current load. Your peak hour next quarter? 79,000 × 1.4 × 2.3 (hourly factor) × 1.2 (monthly factor) = ~306,000 requests/hour.
Can your infrastructure handle 306K requests per hour? If you don't know, you're about to find out the hard way.
Step 4: Translate Traffic to Infrastructure Units
Requests per hour is abstract. You need to map it to CPU cores, memory, and connection pools. This requires knowing your current capacity.
Option A: You already know your limits. Maybe you've load tested. Maybe you've been paged when traffic hit X and know that's your ceiling. Use that number.
Option B: You need to find your limits. Set up a staging environment that mirrors production. Run a load test ramping up requests until latency degrades or errors spike. That's your capacity ceiling.
For our API (Node.js, 4 CPU cores per container, 8GB memory):
- Comfortable throughput: 450 requests/second (27,000/minute, 1.62M/hour)
- Degraded but functional: 600 requests/second
- Falling over: 750+ requests/second
At 306K requests/hour next quarter, we need 306,000 ÷ 27,000 = ~11-12 containers at comfortable load. We currently run 8. That's a 50% infrastructure increase needed before Q4.
Map out the same math for databases, caches, and external services. A common mistake — and I've made it twice, which is twice too many — is scaling compute but not databases. Your API pods handle the load beautifully until they all hammer a single PostgreSQL instance that can't keep up. Suddenly you've got 12 containers all waiting on 50 database connections. Fun times.
If you're running SLOs, the error-budget approach ties directly into capacity planning. When you're burning budget faster than expected, capacity constraints are often the cause. Our SLO error budget guide walks through that connection.
Step 5: Build the Forecast Model
Now we combine everything into a forecast. This is simpler than it sounds.
Forecasted peak load = Current average × Growth factor × Peak factors × Buffer
Where:
- Growth factor = (1 + monthly_growth_rate) ^ months_ahead
- Peak factors = hourly_peak × daily_peak × monthly_peak
- Buffer = 1.2 (20% headroom for organic spikes)
For our API forecasting 3 months ahead:
- Current average: 45,000 requests/hour
- Growth factor: (1 + 0.119)^3 = 1.40
- Peak factors: 2.3 × 1.4 × 1.2 = 3.86
- Buffer: 1.2
Forecasted peak: 45,000 × 1.40 × 3.86 × 1.2 = 292,000 requests/hour
That's our target capacity. Divide by comfortable throughput per unit to get infrastructure requirements.
Plug this into a spreadsheet that updates monthly as new data comes in. Better yet, automate it. We run a weekly cron that pulls the last 90 days, recalculates the forecast, and posts to Slack if the forecast exceeds current capacity by more than 30%. If you're tracking cron jobs, JustAnalytics' heartbeat monitoring catches when these automation scripts silently fail.
Step 6: Set Up Monitoring for Early Warning
Forecasting isn't enough. You need real-time signals when traffic deviates from your model.
Create alerts for:
Traffic volume anomalies: Alert when hourly traffic exceeds 150% of the same hour last week. This catches unexpected spikes before they become incidents.
# JustAnalytics alert configuration
alerts:
- name: "Traffic Volume Spike"
metric: "analytics.requests.hourly"
condition: "value > baseline_same_hour_last_week * 1.5"
severity: warning
channels: ["slack-platform"]
Growth rate acceleration: Alert when 7-day rolling growth exceeds your model assumptions. If you forecasted 12% MoM and you're tracking 25%, your capacity math is already wrong.
Resource utilization trending: Alert when average CPU (not peak) exceeds 60%. This gives you weeks to respond, not minutes.
The point is catching divergence from your forecast before it becomes an incident. Reactive capacity planning — scaling when you're already overloaded — is expensive and stressful.
Common Errors and How to Fix Them
Error: "My traffic data has gaps"
Missing hours or days throw off pattern detection. Fill small gaps with interpolation (average of surrounding data points). For larger gaps, exclude that period from baseline calculations entirely. One week of missing data won't destroy your forecast. Three weeks will.
Error: "Growth rate is negative or wildly variable"
Product changes, marketing campaigns, and seasonal effects create noise. Focus on underlying organic growth by excluding obvious anomaly periods. If you launched a major feature in month 3 that caused a spike, exclude that month from growth calculations. You want the sustainable trend, not the launch bump.
Error: "Peak factors seem too high"
Double-check you're not including anomalous spikes (DDoS attempts, bot traffic, one viral moment). Filter to legitimate traffic before calculating patterns. If your Tuesday peaks are driven by a single enterprise customer running batch jobs, factor that out — their traffic is predictable separately.
Error: "Forecast doesn't match reality"
Re-forecast monthly. Growth rates change. User behavior shifts. A model built on Q1 data may not reflect Q3 reality. Treat your forecast as a hypothesis and validate against actual traffic each month. Adjust parameters when predictions drift more than 20% from observed values.
The Bridge Between Analytics and Infrastructure
Here's the thing nobody talks about: most teams run analytics and infrastructure monitoring as completely separate disciplines. The marketing team watches pageviews. The platform team watches CPU graphs. Nobody connects them.
But your analytics data is a leading indicator for infrastructure needs. Traffic trends show up in analytics weeks before they stress your servers. The pageview spike today becomes the 503 next month.
JustAnalytics bridges this by putting web analytics, APM, and uptime monitoring in the same platform. Your traffic dashboard is one click from your service map is one click from your error rates. We built it this way specifically because we got tired of context-switching between tools during capacity planning sessions.
For teams using separate tools — GA4 for analytics, Datadog for APM, whatever for infra — you can still do this. It just requires manual data stitching. Export from each, normalize timestamps, correlate in a spreadsheet. It works. It's tedious. Honestly, it's annoying enough that I refused to do it more than once before we built the integrated approach. Your call.
If your infra runs on Kubernetes with auto-scaling, DevOS can automate the scaling policy adjustments based on your traffic forecasts. The workflow is: RUM data → forecast → scaling policy update → no manual intervention.
What This Won't Tell You
Capacity planning from RUM data has limits.
It won't catch artificial traffic. Bot attacks, scrapers, and click fraud look like real traffic in your analytics. If 20% of your "users" are bots, you're planning capacity for fake load. That's a problem ClickzProtect addresses on the paid traffic side, but organic bot traffic needs separate filtering.
It won't predict product-driven spikes. A new feature launch, a pricing change, or a viral marketing campaign can 10x your traffic overnight. No historical model predicts those. Build buffer into your capacity plan and maintain the ability to scale quickly.
It won't optimize costs. Knowing you need 12 containers doesn't tell you whether 12 small containers beat 4 large ones, or whether spot instances make sense, or whether your CDN config is efficient. That's a different discipline.
It won't replace load testing. Forecasting tells you when you'll need capacity. Load testing tells you whether your system actually handles that capacity. You need both. A forecast that says "300K requests/hour" is useless if you've never validated your system handles 300K requests/hour.
I wish I could give you a shortcut here. I can't. Do the load tests.
Next Steps
Once your basic forecast is running:
-
Automate the data pipeline. Pull traffic data daily via API. Recalculate forecasts weekly. Post updates to a team channel.
-
Build scenario models. What if growth doubles? What if a major customer churns? Run the math on best-case and worst-case scenarios, not just expected case.
-
Tie capacity to budget. Forecasted containers × cost per container × months = infrastructure budget. Now your capacity plan feeds into finance planning.
-
Create a capacity review ritual. Monthly review of forecast vs. actual. Quarterly re-baseline of growth assumptions. Annual capacity roadmap aligned to product roadmap.
The goal isn't perfect prediction. (Perfect prediction is a myth. Anyone selling you "accurate forecasting" is lying.) It's informed decision-making. Knowing you'll probably need 50% more capacity next quarter lets you plan, budget, and procure. Knowing you'll "need more eventually, I guess" doesn't.
Your RUM data already contains next quarter's infrastructure requirements. You just have to extract them.
Stop guessing. Start calculating.
Frequently Asked Questions
How accurate is RUM-based capacity forecasting compared to synthetic load testing?
RUM-based forecasting reflects actual user behavior, including traffic spikes from organic events your synthetic tests miss — product launches, viral posts, seasonal patterns. Synthetic tests validate max throughput but can't predict when that throughput will be needed. Combine both: use RUM data to forecast when you'll hit capacity, then validate with load tests that simulate those predicted peaks.
What's the minimum historical data needed for reliable traffic forecasting?
Three months covers most weekly and monthly patterns. Twelve months captures seasonal variation like Black Friday or end-of-quarter spikes. For new products without history, use industry benchmarks and similar-stage companies as proxies, then adjust as real data accumulates. Even 30 days of data beats guessing.
Should I size for peak traffic or average traffic?
Neither in isolation. Size your baseline for P75 sustained load with auto-scaling headroom for peaks. If your P99 traffic is 4x your P50, provisioning for P99 constantly wastes money. But provisioning only for P50 means you'll shed load during normal peaks. The sweet spot is baseline at P75, auto-scale triggers at P90, with hard capacity at P99.
How do I account for traffic growth when forecasting?
Calculate your month-over-month growth rate from historical RUM data, then compound it forward. If you're growing 15% MoM, next quarter's peak is roughly 1.5x today's peak. Add a 20% buffer for organic spikes and you've got your target capacity. Re-forecast quarterly as growth rates shift.
Try JustAnalytics
All-in-one observability in one under-5KB script: cookieless analytics + error tracking + APM + session replay + uptime + structured logs. Replaces GA4 + Sentry + Datadog + Pingdom + LogRocket. Free tier (100K events/mo), Pro $49/month ($39 annual).
Author at JustAnalytics.