This uses public data: daily Wikipedia pageviews for one article, as published in the Prophet repository's example datasets. It has no connection to any employer's systems or data.

Ad inventory is traffic. The impressions a publisher can sell next quarter depend on how many visits arrive, and direct-sales commitments need a forecast with an honest range around it. At Chegg I built seasonality-aware traffic and ad-inventory forecasts to support direct-sales commitments and revenue planning. This is a small, reproducible version of the same idea on public data.

The data

The series is daily pageviews of the "Peyton Manning" article on English Wikipedia, from December 10, 2007 to January 20, 2016. It is published on a log scale, so the analysis converts it back to daily views. It has everything that makes traffic forecasting hard: a strong weekly cycle, a yearly cycle tied to the NFL season, and news-driven spikes.

The setup

  • Holdout: the last 365 days, January 21, 2015 to January 20, 2016. The model never sees them.
  • Training window: the 3 years before that (1,092 days), recent enough to reflect current interest.
  • Model: least squares on log views, with a linear trend, day-of-week effects, and 6 pairs of yearly Fourier terms. Working in logs turns multiplicative seasonality ("weekends are much lower") into additive terms and keeps spikes from dominating the fit.
  • Interval: ±1.96 residual standard deviations on the log scale, converted back to views.
  • Baseline: seasonal naive, the same weekday 52 weeks earlier. A model that cannot beat it is not adding anything.

Results

Avg daily views per week (log scale)3001.0K3.0K10K30KJan 14Apr 14Jul 14Oct 14Jan 15Apr 15Jul 15Oct 15Jan 16forecast startsactualforecast
Public data: daily Wikipedia pageviews for one article, averaged by week. The model was fit only on data before “forecast starts” and never saw the holdout year. The band averages each day’s 95% interval over the week, so it shows where a typical day was expected to land, not a range for the weekly average.
Weekly average daily views: actual, forecast, and the daily 95% interval averaged over the week
Week ofActualForecastInterval
2014-01-2625,458——
2014-02-0285,766——
2014-02-093,778——
2014-02-162,444——
2014-02-232,250——
2014-03-022,192——
2014-03-092,238——
2014-03-161,885——
2014-03-232,625——
2014-03-301,717——
2014-04-061,677——
2014-04-131,634——
2014-04-202,277——
2014-04-271,964——
2014-05-043,597——
2014-05-112,204——
2014-05-182,022——
2014-05-252,256——
2014-06-011,621——
2014-06-081,598——
2014-06-151,407——
2014-06-221,290——
2014-06-291,425——
2014-07-061,505——
2014-07-131,899——
2014-07-202,047——
2014-07-272,571——
2014-08-032,567——
2014-08-103,464——
2014-08-173,127——
2014-08-243,791——
2014-08-314,389——
2014-09-0714,423——
2014-09-1410,307——
2014-09-216,673——
2014-09-284,395——
2014-10-058,154——
2014-10-126,165——
2014-10-1919,563——
2014-10-266,150——
2014-11-026,216——
2014-11-094,126——
2014-11-163,627——
2014-11-233,905——
2014-11-304,400——
2014-12-073,816——
2014-12-143,948——
2014-12-214,001——
2014-12-284,104——
2015-01-045,558——
2015-01-1115,416——
2015-01-187,2198,4742,769 to 25,933
2015-01-254,0628,5832,805 to 26,269
2015-02-0110,1306,2422,039 to 19,102
2015-02-083,0034,2371,385 to 12,967
2015-02-152,5932,978973 to 9,114
2015-02-221,7162,344766 to 7,172
2015-03-012,2722,113690 to 6,467
2015-03-081,8432,106688 to 6,445
2015-03-151,4392,164707 to 6,623
2015-03-221,6642,146701 to 6,566
2015-03-291,4561,986649 to 6,077
2015-04-051,1691,736567 to 5,312
2015-04-121,3221,500490 to 4,590
2015-04-191,6911,349441 to 4,129
2015-04-261,6501,301425 to 3,982
2015-05-031,4811,332435 to 4,077
2015-05-101,4631,387453 to 4,245
2015-05-172,3971,395456 to 4,269
2015-05-241,3001,311428 to 4,013
2015-05-311,1151,157378 to 3,539
2015-06-07979997326 to 3,051
2015-06-14909890291 to 2,725
2015-06-211,391864282 to 2,645
2015-06-28883924302 to 2,829
2015-07-051,0171,060347 to 3,245
2015-07-121,5581,241405 to 3,797
2015-07-191,4811,412461 to 4,320
2015-07-261,3161,531500 to 4,687
2015-08-021,4851,611527 to 4,931
2015-08-091,6401,719562 to 5,261
2015-08-161,9411,948637 to 5,963
2015-08-232,1282,394782 to 7,325
2015-08-302,4933,1191,019 to 9,544
2015-09-063,1844,0681,329 to 12,450
2015-09-136,7614,9631,622 to 15,189
2015-09-203,9415,3961,763 to 16,515
2015-09-274,9195,1901,696 to 15,882
2015-10-043,2574,5771,495 to 14,006
2015-10-112,7273,9421,288 to 12,063
2015-10-183,6143,5231,151 to 10,783
2015-10-253,0873,3681,101 to 10,309
2015-11-014,6303,4031,112 to 10,416
2015-11-083,8293,4831,138 to 10,659
2015-11-155,4143,4521,128 to 10,564
2015-11-223,5913,2511,062 to 9,949
2015-11-2943,8992,974972 to 9,103
2015-12-063,0292,795913 to 8,555
2015-12-132,5332,874939 to 8,794
2015-12-202,4183,3441,093 to 10,232
2015-12-275,6944,3281,414 to 13,247
2016-01-034,9445,8001,895 to 17,749
2016-01-103,4157,1712,343 to 21,947
2016-01-1714,4678,5582,796 to 26,190
Daily error over the holdout yearSeasonal modelSeasonal naive
Mean absolute % error (MAPE)36.4%95.3%
Median absolute % error24.9%49.4%
  • The model roughly halves the baseline's typical error (median 24.9% vs 49.4%). Seasonal naive replays last year's spikes into weeks where they did not happen again: its forecast for February 1, 2015 copies the Super Bowl XLVIII surge of February 2, 2014, about 128,000 views against roughly 8,400 actual.
  • The weekly cycle is large: weekend traffic runs about 41% below Mondays, which matters for any daily or weekly commitment.
  • The interval is too wide. It covered 98.4% of holdout days, more than its nominal 95%, because spikes in the training years inflate the residual spread. For planning that errs on the safe side, but it gives up precision.
  • Spikes are the main source of error. The largest holdout day, November 30, 2015, reached 189,032 views against a holdout average of 3,605. No seasonal model can see an event like that coming, which is why MAPE (pulled up by spikes) sits well above the median error.

Using a forecast like this for ad inventory

  • Plan commitments against the low end of the range, not the point forecast, so a soft week does not break a direct-sales guarantee. Convert views to sellable impressions with ad-load and fill assumptions.
  • Model known events explicitly. Launches, playoffs, and school terms belong in the model as regressors rather than being left for seasonality to absorb.
  • Keep scoring it. Re-fit on a schedule and track holdout error over time; last year's good model drifts.

What I would do next

  • Add event and holiday regressors, and handle spikes separately so they stop widening the interval.
  • Try a damped trend; a straight line over three years can overshoot.
  • Calibrate the interval (for example with quantile regression) so its coverage matches the nominal 95%.

Reproducibility: the analysis is a short Python script (numpy and pandas only) in this site's repository at analysis/forecast/forecast.py. It reads a pinned copy of the data, writes the chart data to a JSON file, and the site renders that file, so the numbers above are exactly the script's output.