ds@mcpanalytics.aiEmail your data and your question and get an answer about your own data, with the method shown.Email your data and question. Get an answer.

Support Ticket Volume Forecasting

By MCP Analytics Team | Published , updated

Your support team is either understaffed or overstaffed right now. You just don't know which. Understaffing means SLA breaches, burned-out agents, and customers waiting too long. Overstaffing means wasted budget you could spend elsewhere. Your helpdesk export may help you estimate future ticket volume and the range of likely results. This analysis turns that history into a defensible forecast with prediction intervals you can hand to your VP when requesting headcount.

Worked Example (Simulated): Forecasting Next Week's Tickets

Question: Can past daily counts help plan shifts for the coming week?

Inputs: Simulated data, seed 17. The script makes 120 daily counts, from 2025-01-01 through 2025-04-30. It builds in a base of 32 tickets, a rise of 0.12 tickets per day, a weekday cycle, and random noise with a standard deviation of 4. It uses 105 days to fit the forecast and 15 days to compare forecasts with later counts.

Method: For each day of the week, the script takes the mean count from the fit set. It compares that forecast with a simple baseline: the mean count from the last 7 days. It measures mean absolute error (MAE), the average size of the miss, on the 15 later days. It then forecasts the next 7 days and prints, beside each forecast, the level the script's own rule gives for that day before noise.

from datetime import date, timedelta
from random import Random
from statistics import mean

SEED = 17
N_DAYS = 120
TRAIN_DAYS = 105
START = date(2025, 1, 1)
WEEKDAY_EFFECT = [-3, 1, 3, 2, 0, -4, -5]
TREND = 0.12

rng = Random(SEED)
counts = []
for t in range(N_DAYS):
    weekday_effect = WEEKDAY_EFFECT[(START + timedelta(days=t)).weekday()]
    count = round(32 + TREND * t + weekday_effect + rng.gauss(0, 4))
    counts.append(max(0, count))

train = counts[:TRAIN_DAYS]
holdout = counts[TRAIN_DAYS:]
weekday_means = {
    weekday: mean(
        train[t]
        for t in range(TRAIN_DAYS)
        if (START + timedelta(days=t)).weekday() == weekday
    )
    for weekday in range(7)
}
weekday_predictions = [
    weekday_means[(START + timedelta(days=TRAIN_DAYS + i)).weekday()]
    for i in range(len(holdout))
]
baseline_value = mean(train[-7:])
baseline_predictions = [baseline_value] * len(holdout)
mae_weekday = mean(
    abs(actual - predicted)
    for actual, predicted in zip(holdout, weekday_predictions)
)
mae_baseline = mean(
    abs(actual - predicted)
    for actual, predicted in zip(holdout, baseline_predictions)
)

future_days = [START + timedelta(days=N_DAYS + i) for i in range(7)]
future_predictions = [weekday_means[day.weekday()] for day in future_days]
# What the rule that made the data gives for those days, before noise.
future_built_in = [
    32 + TREND * (N_DAYS + i) + WEEKDAY_EFFECT[day.weekday()]
    for i, day in enumerate(future_days)
]

print(f"Simulated data, seed {SEED}")
print(
    f"Input: {N_DAYS} daily counts from {START} through "
    f"{START + timedelta(days=N_DAYS - 1)}"
)
print(
    f"Method: weekday mean; train={TRAIN_DAYS} days; "
    f"holdout={len(holdout)} days"
)
print(f"Holdout MAE, weekday mean: {mae_weekday:.2f} tickets/day")
print(
    "Holdout MAE, trailing 7-day mean baseline: "
    f"{mae_baseline:.2f} tickets/day"
)
print("Next 7 dates: weekday-mean forecast, built-in level (no noise)")
for day, prediction, built_in in zip(
    future_days, future_predictions, future_built_in
):
    print(f"{day}: {prediction:.1f}, {built_in:.1f}")
print(f"Peak forecast: {max(future_predictions):.1f} tickets/day")

Printed output:

Simulated data, seed 17
Input: 120 daily counts from 2025-01-01 through 2025-04-30
Method: weekday mean; train=105 days; holdout=15 days
Holdout MAE, weekday mean: 6.27 tickets/day
Holdout MAE, trailing 7-day mean baseline: 3.40 tickets/day
Next 7 dates: weekday-mean forecast, built-in level (no noise)
2025-05-01: 39.4, 48.4
2025-05-02: 36.1, 46.5
2025-05-03: 35.8, 42.6
2025-05-04: 34.6, 41.8
2025-05-05: 35.6, 43.9
2025-05-06: 39.7, 48.0
2025-05-07: 39.9, 50.1
Peak forecast: 39.9 tickets/day

Result: The weekday forecast had a mean absolute error of 6.27 tickets per day. The recent-mean baseline had an error of 3.40. The weekday forecast lost on this holdout, and that is expected here. The script builds in a rise of 0.12 tickets per day. The weekday mean ignores that rise, so its forecasts lag. The recent mean follows the rise. For the same reason the next 7 forecasts (34.6 to 39.9) sit below the built-in level for those days (41.8 to 50.1). A forecast should be checked against a simple baseline before it is used to plan shifts.

Limit: These counts are simulated. A real helpdesk may not look like this, and one holdout does not show how a method will do on future data.

Sources: Hyndman and Athanasopoulos, Forecasting: Principles and Practice (3rd ed.), a textbook that covers simple baseline forecasts and forecast error measures.

Why Ticket Volume Forecasting Matters

Support operations run on a knife edge. Every agent-hour you over-schedule is money wasted. Every hour you under-schedule raises the risk of an SLA breach.

To see where your own measure is heading, with a likely range, try the free forecasting tool.

The problem isn't a lack of data. Zendesk, Freshdesk, Jira Service Management, and every other helpdesk tool can export daily ticket counts going back months or years. The problem is turning that data into a forecast that's more than "last month plus 10%." A forecast can help show patterns in past counts, but it may miss changes. Compare its error with a simple baseline on later data. A forecast that gives a range of likely outcomes, not a single number, helps you plan for a bad case.

When to Use Ticket Volume Forecasting

This analysis works best for teams handling a steady ticket stream. A high ticket count alone does not ensure an accurate forecast. Check the model's error on later counts before using it to plan staffing.

What Data Do You Need?

A basic file can have a date and a ticket count for each day or week.

Where to get it

Required columns

How much history?

If you're tracking ticket volume by category or channel (billing vs. technical, email vs. chat), you can run separate forecasts for each. This is especially valuable if different channels have different seasonality: chat might spike during business hours while email accumulates overnight.

How to Read the Report

Forecast chart: the centerpiece of the report. Your historical data appears as a solid line, then extends into the future with predictions surrounded by two shaded bands. The darker band is the 80% prediction interval (if the model's assumptions hold, about 4 out of 5 times actual volume will land inside this range). The lighter band is the 95% interval. For staffing, plan capacity for the upper edge of the 80% band. That covers most scenarios without over-investing in headcount for the extreme tail.

Seasonal decomposition: breaks your ticket data into three layers: trend (are tickets growing over time?), seasonal (which days or months are consistently high or low?), and residual (random noise the model can't explain). The seasonal component is gold for scheduling. If the model shows Mondays are 35% above average and Fridays are 20% below, that's a permanent staffing pattern you should bake into your schedules.

Model diagnostics: the report runs the Ljung-Box test on residuals to verify the model isn't missing important patterns. For practical purposes, look at the MAPE (Mean Absolute Percentage Error) as a rough guide. Check forecast error on data the model did not use, and compare it with a simple baseline. A high error suggests your ticket volume has high randomness, so the exact numbers have wider uncertainty.

AI insights: plain-language interpretation of the forecast, highlighting growth rate, seasonal peaks, and any trend changes. This is the section you paste into a slide when presenting to leadership.

What to Do With the Results

Immediate

Strategic

When to Use Something Else

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