Skip to main content
Public preview: Gap filling is available in public preview.
Examples use externalId for asset-centric projects. For data modeling, use instanceId instead. See Time series and datapoints for details.
Industrial historians often compress stored samples and reconstruct the signal at query time so dashboards see a continuous curve. Cognite Data Fusion (CDF) stores source data faithfully, but without gap filling, aggregate queries can omit buckets where no raw data points exist, which breaks consumers that expect one value per interval. Gap filling is an opt-in feature on aggregate queries. You set a fill object with a limit duration on each query item, and CDF then:
  • Interpolates across gaps up to the limit, using each aggregate’s interpolation mode and the time series’ isStep flag.
  • Extrapolates beyond the last sample by carrying the value forward for the limit duration.
  • Treats gaps larger than the limit as undefined and omits those buckets from the response.
The behavior is similar to OPC UA Historical Access bounding values and aggregate semantics.

Enable gap filling with fill.limit

You enable gap filling by adding a fill object to an item in POST /timeseries/data/list. The only required field is limit, a duration string that sets the maximum gap (measured between consecutive raw sample timestamps) that CDF will interpolate or extrapolate across. fill is set per item, so different time series in the same request can use different limits or opt out entirely.
fill.limit must be greater than or equal to the query granularity (for example, granularity: "1h" with fill.limit: "1h" or fill.limit: "65m" is valid, but fill.limit: "45m" is rejected).
While alignment is not required, set fill.limit as an integer multiple of the granularity (for example, granularity: "1h" with fill.limit: "4h") to keep bucket boundaries and fill limits aligned.
  • If you omit fill (or set it to null), behavior is unchanged: empty buckets are omitted, and the implicit defaults still apply.
  • If a gap exceeds fill.limit, CDF does not partially fill it: every bucket in that oversized gap is omitted from the response.
Time series data list

How gaps are reconstructed

The overview illustrations in Interaction with status codes map to the rules below.

Inside the data range (interpolation)

Between two good bounding data points, each aggregate uses its own interpolation rule: some respect the time series isStep flag (linear vs step), others always use step, and others do not interpolate at all. Gap filling inserts bounding values only when the raw gap is within fill.limit, using those same rules.

Beyond the last data point (extrapolation)

The very last data point in a time series is special: it is extended forward for the fill-limit duration using step extrapolation (forward-fill of the last known good value). So if the last data point is at 15:25 and fill.limit is 3h, the time series is defined until 18:25. The current server time does not impact extrapolation: a data point can extend into the future, up to and including the last interval that starts before the end parameter in the query. Step extrapolation is the conservative industry default and avoids misleading linear ramps into unknown territory.

Before the first data point (no backward extrapolation)

CDF does not extrapolate backward before the first data point in the time series or query range, even with gap filling enabled. Buckets before the first raw data point stay undefined unless a bounding data point falls within fill.limit.

Gaps larger than fill.limit

If the time from the last raw data point before a gap to the first raw data point after it is greater than fill.limit, the series is treated as undefined in that region: no interpolated curve is drawn and those buckets are omitted.

Interaction with status codes

Gap filling reuses the same quality rules as default aggregate behavior: ignoreBadDataPoints and treatUncertainAsBad decide whether a data point can bound interpolation. A bad or uncertain period can be skipped (default) or treated as a hard stop, which changes which gaps exist and therefore which regions exceed fill.limit. For a deep dive into status codes, see Status codes. Solid lines show measured or reconstructed values. Dashed lines show interpolation or extrapolation. Hatched regions mark intervals where the series is undefined or defined-but-bad. Both illustrations below use a fill.limit of 2 bucket periods and default treatUncertainAsBad: true.

Bad data points ignored (default)

When ignoreBadDataPoints is true (default), bad data points are not used as bounds. They are skipped rather than breaking up a gap, which can widen the effective gap between the last good data point before a bad region and the first good data point after it. If that distance exceeds fill.limit, CDF omits buckets in a second gap-too-large region even though raw data points exist inside the wall-clock span.

With ignoreBadDataPoints set to true (default) and a fill.limit of 2 periods, the bad sample is skipped and the surrounding gap widens

Bad data points kept

When ignoreBadDataPoints is false, bad data points bound interpolation. You can get a defined-but-bad interval (shaded in the illustration below) and interpolation forward-fills up to the start of that interval before stopping at its boundary. Because bad data points do not have a reliable value, CDF uses step interpolation at these boundaries regardless of isStep.

With ignoreBadDataPoints set to false and a fill.limit of 2 periods, the bad period acts as a hard stop and appears as a defined-but-bad band

When treatUncertainAsBad is false, uncertain data points are treated as good for bounding purposes and follow the same rules as good samples. See the status code aggregate behavior matrix for all combinations.

Aggregate behavior with gap filling

Each aggregate has a built-in relationship to bounding values. With gap filling enabled, time-weighted aggregates require bounds to integrate correctly, while count/min/max/sum aggregates stay tied to the actual data inside each time bucket.
General rule: If the time series is defined anywhere in an interval — by an actual data point, by interpolation, or by extrapolation — and not considered bad everywhere, CDF returns aggregates for that interval. Without gap filling, CDF only returns aggregates for intervals with at least one data point.

Time-weighted aggregates (interpolated)

These aggregates interpolate or extrapolate inside fill.limit using each aggregate’s inherent mode (isStep where applicable). totalVariation is not supported with gap filling because it measures transitions between stored samples, not interpolated bounds.

Min, max, sum and count aggregates (tied to raw data points)

These aggregates require actual measured values inside the interval.

Duration aggregates (interpolated state)

Duration aggregates use bounding value quality to decide how much time is spent in each state.

State aggregates special behavior

For the state aggregates (stateCount, stateDuration, stateTransitions), CDF calculates values per state. If any value is non-null for a state in the interval, CDF converts the remaining null values for that state to zero. For instance, if stateDuration > 0 due to interpolation from a previous data point, stateCount is filled in as 0 even if there are no data points with that state in the interval. stateDuration can be 0 if the time series is undefined after the last data point (for instance, due to a large gap).

Non-empty bucket edges

Gap filling affects more than completely empty buckets. If a bucket contains raw points only in the middle of the interval, time-weighted aggregates still need values at the bucket boundaries to integrate correctly. With fill enabled, those boundaries may come from interpolated or step-held bounds, so a bucket that is non-empty in the raw sense can still change value compared to the same query without gap filling.

Time zone changes

The fill limit does not take time zone changes into account. 1d is always 24 hours when gap filling.Gaps inside an interval are always filled. For instance, if an interval is 25 hours due to a DST transition, and you have a data point at the start and end of the interval more than 24 hours apart, CDF will still gap fill, even if fill.limit is 24h. For broader calendar and DST behavior, see Calendar and time zone.
Last modified on August 25, 2026