Revenue Forecasting for E-Commerce: How to Handle Seasonal Patterns
By MCP Analytics Team | Published , updated
If you run an e-commerce store, your revenue chart probably looks like a mountain range. Black Friday towers over everything. December drops sharply after the holiday shipping cutoff. January flatlines. Summer might dip or surge depending on your category. Back-to-school brings a bump. Then the cycle repeats.
This is seasonality, and it is a common reason that naive revenue forecasts miss for e-commerce businesses. A simple linear trend drawn through twelve months of data will overestimate your January and underestimate your November.
Statistical methods for seasonal time series have existed for decades. The example below uses simulated monthly revenue to show a seasonal forecast and its error on later data.
Worked Example (Simulated): Seasonal Model or Straight Trend?
Question: Does a model that learns a repeating month pattern forecast the next year better than a straight trend in this simulated store?
Inputs: Simulated data, seed 17. The script makes 48 months of revenue. Revenue rises 1% a month, each month has a set seasonal factor built into the script (0.72 to 1.42, lowest in month 1, highest in month 11), and small random noise is added. It uses the first 36 months to fit the models and the next 12 months to check them.
Method: The seasonal model learns a factor for each month, removes those factors to fit a straight trend, then adds the factors back for its forecast. The other model fits a straight trend to the raw sales. MAPE means the average percent gap between forecast and actual sales; lower is better.
import numpy as np
# Simulated monthly revenue, fixed seed. The first 36 months train the model;
# the next 12 months form a holdout year.
rng = np.random.default_rng(17)
months = np.arange(48)
season = np.array([0.72, 0.76, 0.82, 0.88, 0.94, 0.98,
1.00, 1.02, 1.08, 1.18, 1.42, 1.20])
trend = 10000 * (1.01 ** months)
revenue = trend * season[months % 12] * rng.normal(1.0, 0.035, size=48)
train_x = months[:36]
train_y = revenue[:36]
# Estimate month factors from the first three years, then fit a straight
# line to revenue after removing those factors.
base = np.array([train_y[train_x % 12 == m].mean() for m in range(12)])
season_index = base / base.mean()
deseasoned = train_y / season_index[train_x % 12]
coef = np.polyfit(train_x, deseasoned, 1)
future_x = months[36:]
seasonal_forecast = np.polyval(coef, future_x) * season_index[future_x % 12]
trend_only_forecast = np.polyval(np.polyfit(train_x, train_y, 1), future_x)
actual = revenue[36:]
seasonal_mape = np.mean(np.abs((actual - seasonal_forecast) / actual)) * 100
trend_mape = np.mean(np.abs((actual - trend_only_forecast) / actual)) * 100
peak_month = int(np.argmax(season_index)) + 1
low_month = int(np.argmin(season_index)) + 1
print(f"Training months: {len(train_y)}; holdout months: {len(actual)}")
print(f"Estimated lowest month: {low_month}; peak month: {peak_month}")
print(f"Seasonal model holdout MAPE: {seasonal_mape:.1f}%")
print(f"Trend-only holdout MAPE: {trend_mape:.1f}%")
print(f"Next-year forecast total: ${seasonal_forecast.sum():,.0f}")
print(f"Next-year forecast low month: ${seasonal_forecast.min():,.0f}; "
f"high month: ${seasonal_forecast.max():,.0f}")
Printed output:
Training months: 36; holdout months: 12
Estimated lowest month: 1; peak month: 11
Seasonal model holdout MAPE: 4.2%
Trend-only holdout MAPE: 19.7%
Next-year forecast total: $175,257
Next-year forecast low month: $9,428; high month: $21,414
Result: The month pattern is built into the simulated data, so the seasonal model is expected to win and to find months 1 and 11. It did: its lowest month is 1 and its peak is 11. On the 12 held-out months, its MAPE was 4.2%, compared with 19.7% for the trend-only model. Its next-year forecast total was $175,257, with a low month of $9,428 and a high month of $21,414. In this made-up example, a shop could plan for more stock and cash near the forecast peak.
Limit: This is simulated data with a set month pattern, and the trend-only model cannot represent seasons. It does not show how well the method will work for a real shop or for a season that changes.
Sources
- Hyndman R, Athanasopoulos G. Forecasting: Principles and Practice, 3rd ed. (fpp3), on time series decomposition. https://otexts.com/fpp3/
- Taylor S, Letham B (2018). Forecasting at scale. The American Statistician. doi 10.1080/00031305.2017.1380080
Why Seasonality Breaks Simple Forecasts
A simple forecast: "revenue grew 15% last year, so next month should be 15% above this month last year": works reasonably well for businesses with flat seasonal profiles. Banks, utilities, B2B SaaS with annual contracts. Revenue is relatively stable month to month.
To see where your own measure is heading, with a likely range, try the free forecasting tool.
E-commerce is different. A store selling gifts may earn much of its revenue in November and December. A store selling outdoor gear may see summer revenue well above winter revenue. A fashion retailer may have several seasonal cycles aligned with collection drops.
Simple growth-rate forecasts fail here because they treat every month the same. What you actually need is a model that separates three distinct components:
- Trend: The underlying direction of your business, stripped of seasonal noise. Are you growing 2% per month or 8%? This is different from raw month-over-month growth, which bounces wildly with the seasons.
- Seasonality: The repeating pattern within each year. Which months are peaks? Which are valleys? How large is the swing? Is the pattern multiplicative (peaks grow proportionally with the trend) or additive (peaks are a fixed dollar amount above baseline)?
- Residuals: Everything else: one-time promotions, supply chain disruptions, viral moments, competitor actions. The stuff that no model can predict but that you need to account for in your confidence intervals.
Seasonal decomposition is one way to split a time series into trend, seasonal, and residual parts (Hyndman and Athanasopoulos, fpp3).
Detecting Your Seasonal Pattern
Before you forecast, you need to understand your specific seasonal profile. Not every e-commerce business has the same pattern. Here's what to look for:
Weekly Seasonality
Most e-commerce stores see consistent day-of-week patterns. Mondays might be strong (people shopping at work), weekends might dip or spike depending on category. This matters when you're forecasting daily revenue. If your model doesn't account for weekly cycles, every Monday forecast will be wrong.
Annual Seasonality
The big swings. Holiday season (November-December), Valentine's Day, Mother's Day, back-to-school, Prime Day effects. Your annual pattern depends entirely on what you sell. A chocolate store has a completely different profile than a lawn mower store.
Holiday Spikes vs. Seasonal Waves
There's an important distinction between smooth seasonal waves (summer is generally higher than winter) and sharp holiday spikes (Black Friday is a single extreme day). Smooth waves are handled well by standard seasonal components. Sharp spikes need explicit holiday modeling. A point-event that is modeled separately from the seasonal curve.
How to check your seasonal pattern: For your own store, plot revenue over time and check whether the same pattern repeats. The example above uses simulated monthly data. If certain days are much higher than surrounding days, those are holiday effects that need special treatment.
Two Approaches That Work
ARIMA with Seasonal Components (SARIMA)
ARIMA (AutoRegressive Integrated Moving Average) is the classical approach to time series forecasting. Its seasonal variant, SARIMA, adds parameters that capture repeating patterns at fixed intervals: weekly, monthly, or yearly cycles.
SARIMA works well when:
- Your seasonal pattern is regular and consistent year over year
- Your data cover several full seasonal cycles
- The pattern doesn't change much in shape, Christmas is big, but it's roughly the same proportion of annual revenue each year
SARIMA struggles when holidays fall on different dates each year (Easter, Lunar New Year), when your business is changing the shape of its seasonal pattern (adding a new product category that peaks at a different time), or when external events create non-repeating disruptions.
Prophet
Prophet is described in Taylor and Letham (2018), Forecasting at Scale. It is a different method from SARIMA, and the paper is the place to read what it does.
Practical Considerations for E-Commerce Forecasting
Multiplicative vs. Additive Seasonality
If your November spike was $50K above baseline when you were a $500K/year business, and now it's $100K above baseline as a $1M/year business, your seasonality is multiplicative: peaks scale with business size. Many growing businesses have multiplicative seasonality. If the spike stays at roughly $50K regardless of business size, it's additive.
Getting this wrong leads to systematic forecast errors. A multiplicative model on an additive pattern will overestimate your peaks. An additive model on a multiplicative pattern will underestimate them.
Handling Promotions and Sales Events
Your annual Prime Day promotion is not the same as Amazon's Prime Day. Your store-specific events (anniversary sales, flash sales, influencer drops) create spikes that the seasonal model can't predict because they're not at consistent dates. Two options:
- Model them as known future events: If you know when your next major promotion will run, include it as a known future event in the model.
- Exclude them and add manually: Run the forecast on "organic" revenue (without promotion spikes), then layer in your planned promotional impact based on historical lift percentages.
New Product Launches
A forecast based on 2024 and 2025 data knows nothing about the product line you're launching in Q3 2026. Time series models are backward-looking by design. For new product revenue, you need a separate estimate (market sizing, pre-order data, analogous product performance) that you add on top of the time series forecast for existing products.
The Bottom Line for E-Commerce Forecasting
Use seasonal decomposition to separate trend from seasonal patterns. Choose SARIMA if your patterns are regular, and check holiday handling in any method you pick. Either way, look at the decomposition plot before trusting the forecast number. It tells you whether the model actually captured your seasonal pattern or is just drawing a line through noise.
Working on this for your business? See the revenue forecasting tool.
Your turn
Bring your own data and the question you actually need answered.
MCP AnalyticsData science by email Send us your data and your question, and we will reply. ds@mcpanalytics.ai
Frequently Asked Questions
How much historical data do I need to forecast seasonal e-commerce revenue?
Enough to cover several full seasonal cycles. Seasonal models need to see the pattern repeat to tell a seasonal effect from a one-time anomaly, and more cycles let the model show whether the pattern is growing, shrinking, or stable.
Should I remove outlier days like Black Friday from my forecast data?
No. Removing them throws away your most important data points. Use a forecasting method that handles holidays explicitly, with the holiday dates given to the model. The goal is to model the spike, not pretend it doesn't exist.
Can I forecast revenue for a new product category with no sales history?
Not with time series methods alone. You need analogous data, such as sales patterns from a similar product category in your store. Use those as a proxy series and adjust based on your expected market share. Forecast intervals on such a proxy series will be wide.
How does MCP Analytics handle e-commerce seasonality?
MCP Analytics offers both ARIMA and Prophet forecasting modules. Upload your daily or weekly revenue CSV to get a forecast with confidence intervals.
← Revenue Forecasting · Time Series Forecasting · CSV Analysis