Visibility Forecasting
Predict future AI visibility scores using a Holt-Winters ensemble with bootstrap-calibrated prediction intervals, cross-validated diagnostics, and confidence quality ratings.
Overview
Visibility Forecasting projects your AI visibility score forward in time using a statistically rigorous time-series ensemble. The engine trains three competing models on up to 180 days of history, weights them by out-of-sample accuracy, and returns forecasts at 30, 60, or 90 days with honest, empirically-calibrated confidence bands.
Every forecast ships with diagnostic metrics so you can trust (or distrust) the numbers: cross-validated error, coverage probability, residual autocorrelation tests, and an overall confidence quality rating of High, Medium, or Low.
How It Works
Data Collection and Cleaning
The system pulls up to 180 days of historical visibility scores, aggregated to daily averages. Before fitting, two preprocessing steps protect the models from bad data:
- IQR-based outlier detection + Winsorization — Extreme values are clamped to a 2.0x IQR fence (deliberately wider than the textbook 1.5x so genuinely volatile-but-real days are not over-clamped) rather than discarded. This preserves sample size while preventing a single bad day from distorting the trend.
- Bridging a missed capture — The models need evenly-spaced observations, so a single missed capture is bridged by interpolation. Anything wider is not: a straight line drawn across a longer silence would be inventing observations, and invented points make the forecast look more confident than the record deserves (they have no spread, so they shrink the prediction interval). When a gap is too wide to bridge, the series is split and only the run since the gap is used — the diagnostics report both how many points were bridged and how many were set aside.
Everything is counted in capture cycles, not days
A forecast needs 14 captures, not 14 days. For a project capturing daily that is 14 days; capturing weekly, 14 weeks; monthly, 14 months. The engine steps forward one capture at a time too, so a 30-day horizon is 30 points for a daily project and 4 for a weekly one — a weekly project has nothing to say about next Tuesday in particular.
This matters because the alternative silently fabricates. Treating a weekly project as a daily series means inventing six points out of every seven, and a model trained mostly on interpolation reports a confidence it has not earned.
The Three Models
The engine fits three competing models on every run:
- Holt-Winters Additive — Level + trend + weekly seasonality (period = 7). Best when your visibility has a day-of-week pattern (e.g., weekday peaks). Daily capture only, and it needs three full weeks of it.
- Holt Damped Trend — Level + damped trend, no seasonality. Best when your data has a clear direction that should eventually flatten out, not extrapolate forever. Fits at any cadence.
- Seasonal Naïve — Repeats last week's pattern. A strong baseline that is hard to beat on noisy data. Daily capture only.
The two seasonal models are offered only to projects that capture daily, because a week is seven captures only when a capture is a day. On a weekly project those seven positions span seven weeks, and there is no seven-week cycle in visibility to find — fitting one would read a pattern off the calendar rather than out of the data. Weekly, fortnightly and monthly projects are forecast by the damped-trend model alone, which is the honest position when there is one observation per cycle.
Each model runs a fine-grained grid search across ~200+ parameter combinations (alpha, beta, gamma, phi), optimizing AICc (corrected Akaike Information Criterion) on the full series. AICc penalizes overfitting more aggressively than raw error. The parameter count includes the estimated residual variance (so a model with k smoothing parameters is scored as k+1) — the standard convention, which keeps the comparison between models with different numbers of parameters fair.
Ensemble Weighting
Each model's out-of-sample accuracy is measured using expanding-window time-series cross-validation:
- Minimum training window: 21 captures, adapting down toward the 14-capture floor for shorter-but-valid series so they still cross-validate (instead of silently returning equal weights).
- CV horizon: 7 captures ahead per fold.
- Leakage-free folds — every fold re-runs the full grid search on its own training slice. The model never tunes its smoothing constants on data it is about to be tested against, so CV RMSE is an honest out-of-sample estimate and the weights are not biased toward the more flexible models.
The final ensemble weights each model inversely by its CV RMSE, so the model that best predicts unseen data contributes most to the forecast. A single model can be selected if one dominates, or the ensemble can blend all three.
Bootstrap-Calibrated Prediction Intervals
Instead of assuming residuals are normally distributed (which they rarely are), the engine builds empirical prediction intervals via path-resimulation bootstrap — the method described in Hyndman & Athanasopoulos, Forecasting: Principles and Practice (§5.5):
- For each model in the ensemble, compute its residuals on the training data and centre them (zero mean).
- Simulate complete future trajectories — about 500 in total, split across the models in proportion to their ensemble weights. Each trajectory runs that model's own update equations forward, injecting a freshly resampled residual at every step — so the error feeds back through the level, trend and seasonal state exactly as a real shock would, and uncertainty compounds correctly the further out you forecast.
- At each horizon day, take the empirical percentiles across the pooled trajectories: the 2.5th/97.5th for the 95% band and the 10th/90th for the 80% band.
Pooling across the whole ensemble (not just the single best model) means the band reflects two distinct sources of uncertainty: the random shocks within each model and the structural disagreement between models. When the three models forecast diverging futures, the band correctly widens to admit that ambiguity — something a single-model band could never show.
This is more correct than the common shortcut of scaling a single residual by √(horizon), which only holds for a pure random walk and ignores how trend and seasonality propagate error. The resulting bands are naturally asymmetric and widen at the right rate — narrow where the ensemble is confident and agrees, wide where the models genuinely cannot tell or disagree. Both the 80% and 95% bands are emitted directly by the engine (the chart does not approximate one from the other), and both are persisted with stored forecasts so historical views show the real intervals rather than a reconstruction.
Diagnostics Returned
Every forecast response includes a diagnostics object:
| Metric | Meaning |
|---|---|
cvRmse | Cross-validated root mean squared error |
cvMae | Cross-validated mean absolute error |
cvMape | Cross-validated mean absolute percentage error (null if any actual is 0) |
coverageProbability | Calibration check: across cross-validation folds, the fraction of held-out actuals that fell inside a 95% band built from the empirical 2.5/97.5 quantiles of the model's own residuals (compounded by √horizon) — the same non-normal basis as the displayed intervals, not a Gaussian ±1.96σ band. Target ~95%. It verifies the model's uncertainty is the right size; the forecast's displayed bands themselves come from path-resimulation. |
ljungBoxQ + ljungBoxPValue | Ljung-Box test for residual autocorrelation (p > 0.05 = residuals look like white noise, model has extracted the signal) |
residualStdDev | Standard deviation of residuals |
outliersDetected / outliersWinsorized | How many outliers the preprocessor clamped |
gapsFilled | How many missed captures were bridged by interpolation |
confidenceQuality | Overall rating — high, medium, or low |
cadence | The spacing the models actually stepped in, read from your capture record |
intendedCadence | How often the project is meant to capture, from its schedule. Copy is written in this unit |
stepDays | Days in one step — 1 daily, 7 weekly, 14 fortnightly, 30 monthly |
cyclesAvailable / cyclesRequired | Captures you have, and the 14 a forecast needs |
observationsDroppedBeforeGap | Captures set aside because an outage split the series |
insufficientHistory / staleHistory | Present when there is no forecast, and which of the two reasons applies |
lastObservationDate | The last day this project captured |
The winning model name and its parameters (e.g., { alpha: 0.35, beta: 0.12, gamma: 0.20 }) are stored with the forecast so every prediction is traceable to a specific model configuration.
Confidence Quality Rating
The engine combines the diagnostics into a single signal:
- High — Low CV error, coverage near 95%, residuals pass Ljung-Box. Trust the forecast for planning.
- Medium — One or more diagnostics are marginal. Use the forecast directionally; treat point estimates with caution.
- Low — High CV error, poor coverage, or residual autocorrelation. The model is struggling with your data. Don't bet the quarter on it.
When there is no forecast
Sometimes the honest answer is that there isn't one. There are exactly two reasons, and the page says which:
"Not enough history to forecast" — a forecast needs 14 captures and this project has fewer. The panel counts them in your own rhythm: "A forecast needs 14 fortnightly captures. This project has 5, the first on 1 Jun 2026." Nothing to fix; the forecast appears on its own once there are enough.
"Captures have stopped" — there are captures, but not recent ones: "No captures since 3 Aug 2026 — a forecast needs current captures." A model anchored on a month-old reading projects forward from a present nobody measured, and at a long enough silence its predicted dates land in the past. The forecast returns on its own once capturing resumes.
How long is "too long" depends on your own capture rhythm, not on a fixed number of days: silence counts as stopped once it exceeds two capture cycles — two days for a daily project, a fortnight for a weekly one, two months for a monthly one. It is the same threshold used to decide a gap is too wide to bridge, because a hole too wide to interpolate across is a hole too wide to project from. And it is measured against the rhythm your schedule promises, so a new project is never told captures have stopped before the next one was even due.
When captures do not match the schedule
If your captures have been landing at a different rhythm from the one you set, the panel says so: "Captures have landed about a month apart, not every fortnight."
That is worth knowing on its own — every step of that ladder is at least a halving, so a fortnightly project capturing monthly is getting half the evidence it was set up for. The forecast still steps at the rhythm your captures actually arrived in, because that is what the models can see; the sentence is written in the rhythm you chose, because that is the one you can do something about.
Forecast Horizons
A horizon is asked for in days and answered in captures — one point per capture cycle. A 30-day horizon is 30 points for a daily project, 4 for a weekly one, and 1 for a monthly one.
| Horizon | Use Case |
|---|---|
| 30 days | Short-term planning. Narrowest intervals, highest confidence. |
| 60 days | Medium-term strategy. Intervals widen as uncertainty compounds. |
| 90 days | Long-term outlook. Useful for trend direction and relative comparison. |
Segment Filtering
Forecasts can be computed for any prompt segment:
- All prompts (default) — Aggregate forecast across your whole portfolio.
- Branded — How visibility is trending on queries that mention your brand.
- Non-Branded — The most important segment — organic discovery trajectory.
- Competitor — Head-to-head comparison query trajectory.
Pass the ?segment= parameter to the API or use the segment toggle on the analytics page. Historical data is re-aggregated from raw snapshots for the selected segment, so the forecast is accurate for that slice.
How to Use
- Navigate to Analytics → Forecasting, or use the MCP tool
get_visibility_forecast. - If there is no forecast, read which of the two reasons is given — not enough captures yet, or captures have stopped. They call for different things: waiting, and looking at why capturing stopped.
- Check the confidence quality rating. If it's Low, ask why — is the history too short, too volatile, or full of gaps?
- Review the winning model in the response. If Seasonal Naïve dominates, your data doesn't have enough signal yet — keep capturing.
- Watch coverage probability. If it's drifting far from 95%, the intervals are miscalibrated and need more data.
- Compare last month's forecast to this month's actuals to build intuition for how accurate your specific project is.
Interpreting Results
- High-quality ensemble with narrow bands — Your visibility is stable and predictable. Optimization efforts are producing consistent results.
- High-quality ensemble with wide bands — Your visibility is genuinely volatile. The model is calibrated; the world is just noisy.
- Low-quality rating — Don't trust the point estimate. Look at trend direction only, and capture more data.
- Ljung-Box p < 0.05 — Residuals have autocorrelation, meaning there is signal the model hasn't captured. Often a sign your series has a change point (a platform update, a product launch) that broke the stationarity assumption.
Forecast Storage
Key forecast snapshots (at 30, 60, and 90-day marks) can be stored in the visibility_forecasts table. This lets you compare what you predicted against what happened — a crucial feedback loop for calibrating your own trust in the system.
The model version, winning model name, and full parameter set are all persisted, so every historical forecast is fully reproducible.
Plan Requirements
Visibility Forecasting requires the Advanced AI Insights feature, available on Pro-Individual plans and above.