Confirmation Delay (CD)
Confirmation Delay measures how long after a physical event happened Dockflow first had a confirmed reading of it. It is the metric most directly tied to an SLA on event timeliness, so this page documents the exact computation: which milestones are in scope, which are excluded and why, and how the target is set.
CD = predicted_at(first reading in the actual streak) − event_date (never negative)
Target: 24 hours | Lower is better | Available from March 2026
If you export your milestones and recompute CD, you will not land on the console figure unless you apply the same scope and exclusions. The most common reason a self-computed number comes out an order of magnitude higher is that it reads ingestion timestamps (created_at) over every raw event, while CD reads the confirmation timestamp (predicted_at) over resolved milestones only. The full list of differences is in Reproducing CD from your own data below.
What the two timestamps mean
| Field | Meaning |
|---|---|
event_date | When the event physically happened - e.g. the vessel actually departed, the container was actually discharged. |
predicted_at | The timestamp of the first reading in the actual streak: the first data point that established this event as confirmed (actual), not merely predicted. |
CD is the gap between the two. It answers: "Once something happened in the real world, how long until we had it confirmed?"
It is deliberately not measured from ingestion time (created_at, when a row landed in the database). Ingestion time includes carrier backfills and resends - a carrier re-sending a three-week-old event today would register as a three-week delay under ingestion time, which says nothing about how current the tracking was. predicted_at measures the moment the confirmation actually became available.
Which milestones are in scope
CD is computed over the resolved milestones of a tradeflow - the transport plan's output, one row per confirmed step - not over every raw tracking event received. A milestone is included when all of the following hold:
| Condition | In scope when |
|---|---|
| The milestone is confirmed | actual = 1 (predicted-only steps carry no CD) |
| A confirmation delay was computed | confirmation_delay_seconds is not null (see exclusions below) |
| The tradeflow is not deleted | deleted_at is null |
| The tradeflow involves your entity | your entity appears anywhere on the tradeflow, not only as lead/owner |
Entity scope is any-entity, not lead-entity. If your organisation is one of several parties on a tradeflow (for example the forwarder on a tradeflow owned by another party), its milestones count toward your CD. This matches how you experience the shipment: you are tracking it regardless of who created the tradeflow.
There is no "still active" filter. CD asks how fast an event that already happened was confirmed. Whether that tradeflow is still open today has no bearing on that answer, so completed tradeflows stay in the population. (This was corrected in mid-2026; an earlier version filtered to currently-active tradeflows only, which made historical months shrink over time toward the slow-to-close stragglers and put an artificial upward slope in older figures. See Reading CD over time.)
Exclusions: when a milestone carries no CD
Some confirmed milestones are deliberately given no CD value (confirmation_delay_seconds = null) and drop out of the average entirely. There are three reasons, each applied at the moment the milestone is computed:
| # | Exclusion | Why |
|---|---|---|
| 1 | Carrier "unknown time" default | Some carriers emit a placeholder local time of exactly 12:00:00 when the true clock time of an event is unknown (only the date is known). A CD computed against a placeholder time is meaningless, so events landing on exact local noon are excluded rather than counted as a real delay. |
| 2 | Event predates tracking | If the event was already actual before Dockflow started tracking that container, we could not have confirmed it faster than we started - the delay would just measure how long the container existed before it was added. Events before the container's first tracking record are excluded. |
| 3 | No confirmation reading | If no actual-streak reading with a predicted_at exists, there is nothing to measure the event against. |
Consequence for coverage: not every confirmed milestone carries a CD. In a typical month roughly 60-85% of confirmed milestones have a CD value; the rest are excluded by the rules above. This is expected, not missing data - the excluded milestones are the ones where a delay number would be misleading.
Outliers: the >240h tail is reported separately
After scope and exclusions, one more rule applies to the average:
- Any milestone with CD above 240 hours (10 × the 24h target) is treated as an outlier. It is removed from the reported average and counted separately as an
outlier_count, with its ownoutlier_avg.
Outliers are almost always a symptom of the exclusion rules not catching an edge case (a stale backfill, an unusually late carrier correction), not of routine tracking being slow. Reporting them separately keeps a handful of extreme values from dominating an average built on hundreds or thousands of normal milestones. The count shown as outliers is the excluded population - it is not part of the headline average.
A large "occurrences" or outlier count next to a healthy average is the excluded tail, working as designed - not a sign the average is wrong. The average is computed over everything below the outlier line.
Status bands
| Status | Band | Meaning |
|---|---|---|
| On Target | ≤ 24 h | Events confirmed within a day of happening |
| Warning | 24 - 36 h | Confirmation lagging; check which sources/event types drive it |
| Critical | > 36 h | Sustained lag; investigate via drill-down |
The 24h target reflects the practical carrier reporting cycle: most carriers batch-report on a daily rhythm, so sub-24h confirmation is the realistic ceiling for carrier-sourced events. Terminal-sourced events confirm faster (see below).
What drives CD, and what you can influence
| Factor | Effect | In your control? |
|---|---|---|
| Carrier reporting cadence | Carriers batch-update at their own intervals | No |
| Data source type | Direct terminal data confirms faster than carrier EDI | Partly - see below |
| Polling frequency | Dockflow polls more often near expected events (as often as every 6h) and less during quiet stretches (up to 24h) | Managed by Dockflow |
For terminal events (gate-in, gate-out, discharge, load), a correctly linked terminal means Dockflow receives the event directly from the terminal, which confirms far faster than waiting for the carrier's EDI to report the same move. A missing or wrong terminal link forces reliance on the slower carrier feed. Getting terminal connections right is the single biggest thing you can do to bring CD down on terminal events. See Terminal Integrations.
Reproducing CD from your own data
If you recompute CD from an export and get a much larger number, the difference is not an error in either place - it is that a naive query measures a different thing. The five differences, each of which moves the number:
| # | A naive raw query does this | CD does this instead | Direction |
|---|---|---|---|
| 1 | Reads every raw tracking event | Reads resolved milestones only (one per confirmed step) | Removes resends / duplicates |
| 2 | Uses ingestion time (created_at) | Uses confirmation time (predicted_at) | Removes backfill lag |
| 3 | Counts every actual event | Applies the three exclusions | Removes meaningless delays |
| 4 | Includes all values in the average | Excludes the >240h outlier tail | Removes extreme values |
| 5 | (older self-queries) filters to active tradeflows | Includes completed tradeflows | Removes survivorship bias |
The largest single lever is usually #2 (ingestion vs confirmation time) combined with #4 (the outlier tail). Applying all five reconciles a raw figure back to the console figure.
To reproduce the console average exactly: read milestones where actual = 1 and confirmation_delay_seconds IS NOT NULL, join to your entity via the tradeflow, drop values above 240h, and average confirmation_delay_seconds / 3600.
Reading CD over time
Two things to know before comparing months:
-
The metric starts in March 2026.
confirmation_delay_secondswas introduced on 1 March 2026. Filtering to any period before that returns nothing - there is no CD to show, because the field did not yet exist. This is why a February filter comes back empty. -
CD figures are not frozen snapshots. Milestones are recomputed every time the transport plan for a tradeflow is re-evaluated (a new event arrives, a correction lands). A past month's CD can therefore shift slightly as underlying tradeflows continue to evolve. The direction of drift is normally downward as late confirmations resolve.
Because a past month can still move, any CD figure handed onward as SLA evidence should be captured as a snapshot at the moment it is reported, or presented with the note that it reflects the state at time of reading. Do not treat a CD value pulled today for a month three months ago as a permanently fixed number.
For the MSC Direct activation on 18 June 2026 and how to read metric levels either side of it, see Metric history and baselines.
Drill-down and export
Click the CD card to see individual milestones:
- Sort worst-first (longest delays) or best-first.
- Paginated 20 per page.
- Export to CSV, up to 1,000 rows.
The drill-down applies the same scope and exclusions as the headline metric, so the rows shown are the rows in the average (outliers are labelled as such).