# How to Set a Useful Marketing Data Freshness SLA

Canonical URL: https://www.martechdevs.com/blog/marketing-data-freshness-sla

By [Jafrin Akter Alo](https://www.martechdevs.com/authors/jafrin-akter-alo)

Data Engineer and Co-founder, martechdevs

Published: 2025-07-17

Last updated: 2026-09-15

A useful marketing data freshness agreement defines which decision the data supports, how current and complete it must be, when it must be available and what happens when it misses that standard. Measure the final report or activation output as well as its source feeds. A successful pipeline run or one recently loaded row does not prove the whole dataset is ready.

## Start with the decision and its deadline

Ask the report owner what they will do with the data and when. A weekly budget review, a daily lead-routing process and a customer suppression check have different failure costs. Giving all three an hourly refresh schedule wastes money in some places and creates avoidable risk in others.

For a campaign-budget meeting at 09:00, the useful promise may be that the prior complete business day's cost and accepted-lead data is available by 08:30. For a suppression audience, yesterday's data may already be too old. Define the product and decision before selecting a refresh interval.

Use precise terminology in the agreement. A service-level indicator is the measured result, a service-level objective is the target and a service-level agreement adds an agreed commitment and response to failure. [Google's SRE guidance](https://sre.google/workbook/implementing-slos/) distinguishes objectives from contractual agreements and recommends indicators tied to the user's experience. Internal teams often call their operating agreement an SLA; make the actual responsibilities explicit rather than relying on the label.

A [warehouse and customer data implementation](https://www.martechdevs.com/data-warehouse-cdp) should produce this operational contract alongside the models. Otherwise, the marketing team interprets a green dashboard as current while the data team interprets green as a completed query.

## Define freshness, coverage and correctness separately

Freshness asks how old the usable information is. Coverage asks whether the required accounts, partitions, records or fields are present. Correctness asks whether the values and relationships satisfy the agreed rules. A dataset can pass one and fail the others.

Suppose 99 advertising accounts loaded yesterday's results, but the largest account did not. A global maximum load timestamp may be current, and almost every account may be present, while most spend is missing. Check required accounts individually and distinguish account-count coverage from spend-weighted exposure.

A job that updates an audit timestamp without receiving new source information should not reset the data's age. A dashboard cache refresh should not imply that the underlying warehouse has advanced. Preserve source-through time, ingestion time, model publication time and dashboard or destination refresh time as different observations.

Use a trusted readiness manifest where possible: the source account, report date, extraction configuration, completed pages or cursor ranges, record count, totals and reconciliation result. A manifest is evidence only for the completeness it actually verifies. Calling a batch complete because the last HTTP request returned successfully is insufficient if earlier pages were skipped.

The [data warehouse design guide](https://www.martechdevs.com/blog/data-warehouse-design) explains the underlying model boundaries. The freshness agreement should name which boundary the user can rely on.

## Write one concrete operating contract

Here is a hypothetical starting contract for a daily paid-media performance report. It is an example to adapt, not an industry-standard promise.

The consumer is the growth manager making the 09:00 daily budget decision. The report covers all 12 explicitly registered advertising accounts and the accepted commercial lead ledger. The business timezone is Asia/Dhaka. By 08:30 each day, the report must include the prior local calendar day from 00:00 inclusive to the following 00:00 exclusive.

A good delivery requires every expected account-date slice, completed extraction pagination, validated transformations, no duplicate business keys and reconciled control totals under source-specific tolerances. The lead ledger uses exact accepted-submission counts after its documented test exclusions. Advertising cost uses each source's currency and reporting settings before any approved currency conversion.

The target is good delivery on at least 29 of the most recent 30 eligible daily deadlines. The denominator comes from the expected schedule, so a missing job still counts as a failed delivery. Do not calculate success only from runs that happened to produce logs.

The data owner receives an early warning when recovery time is running short. The growth manager sees an explicit stale or incomplete status by 08:30 if the contract is missed. The operating response is to defer automated budget changes for affected accounts and use the last reconciled report with its date clearly shown.

The agreement names an owner, backup owner, incident channel and next-update interval. It also explains that later source revisions may restate prior days under the separate correction policy. A timely provisional delivery is not a promise that a vendor will never revise a metric.

## Budget latency across the whole path

Work backward from the decision deadline. In a hypothetical two-hour end-to-end target, the source publication allowance is 60 minutes, ingestion 20, transformation and checks 15, destination refresh 10 and contingency 15. Those serial allowances total 120 minutes.

If the source typically publishes after three hours, refreshing the warehouse every five minutes cannot satisfy a two-hour event-to-report promise. Either choose another source or export mode, change the decision window or explicitly promise a narrower source-availability-to-report target. Do not hide source latency by starting the clock after the slowest part.

Measure actual stage durations and the end-to-end duration. Percentiles do not add cleanly: the 95th percentile of each stage summed together is not automatically the end-to-end 95th percentile. The slow events may occur on different runs, and failures may be correlated.

For a daily batch, deadline performance may be more understandable than per-record latency. For a continuous suppression feed, record-level delay and the oldest unprocessed eligible item may matter more. Choose the observation unit according to the decision, then preserve that unit in the numerator and denominator.

A quiet source also needs a rule. No new leads overnight may be normal. A successful poll with a verified source cursor or an explicit zero-record batch can distinguish no activity from a stalled pipeline. A synthetic heartbeat alone proves connectivity, not that all business data was processed.

## Do not let one fresh row hide an incomplete batch

Consider a fixed evaluation time of 08:30 UTC. A model was published at 08:25, its declared source-through time is 08:00 and the agreed maximum data age is 30 minutes. At first glance it meets the age target exactly.

However, its expected batch contains 100 distinct receipt IDs and only 99 are present. The output is incomplete. A different fixture containing all 100 IDs plus one duplicate delivery row is also unacceptable for a model whose grain is one row per receipt, even though its distinct count looks correct.

This original Python acceptance fixture checks those conditions independently. It uses an authoritative expected-ID manifest for a synthetic batch; real sources may require a different completeness control.

```python
from datetime import datetime, timedelta, timezone

UTC = timezone.utc
now = datetime(2026, 10, 14, 8, 30, tzinfo=UTC)
through = datetime(2026, 10, 14, 8, 0, tzinfo=UTC)
published = datetime(2026, 10, 14, 8, 25, tzinfo=UTC)
expected = {f"receipt-{i}" for i in range(100)}

def readiness(actual_ids, expected_ids, source_through, published_at, checked_at):
    times = (source_through, published_at, checked_at)
    if any(t.tzinfo is None or t.utcoffset() is None for t in times):
        raise ValueError("Use timezone-aware timestamps")
    ordered = source_through <= published_at <= checked_at
    age_ok = ordered and checked_at - source_through <= timedelta(minutes=30)
    unique = len(actual_ids) == len(set(actual_ids))
    complete = set(actual_ids) == expected_ids
    return {"fresh": age_ok, "unique": unique,
            "complete": complete, "ready": age_ok and unique and complete}

all_ids = sorted(expected)
assert readiness(all_ids, expected, through, published, now)["ready"]
assert not readiness(all_ids[:-1], expected, through, published, now)["ready"]
assert not readiness(all_ids + [all_ids[0]], expected,
                     through, published, now)["ready"]
assert not readiness(all_ids, expected, through - timedelta(seconds=1),
                     published, now)["ready"]
```

The checks show why a recent timestamp and matching row count are not sufficient on their own. Equal sets catch missing or unexpected IDs; uniqueness catches repeated rows; time ordering rejects future publication or source-through claims. The inclusive 30-minute boundary is part of this example's contract, not a universal tool default.

A real report also needs correctness checks for monetary totals, required fields and joins. Keep those results separate so an incident tells the operator whether to investigate availability, missing data or transformation logic.

## Use freshness tools with their actual semantics

[dbt's freshness configuration](https://docs.getdbt.com/reference/resource-configs/freshness) supports warning and error thresholds and a loaded timestamp field or query. Choose a field that reflects the information you intend to measure. A maximum timestamp measures the newest qualifying observation; it does not by itself verify every required partition or account.

Version matters. Current dbt documentation describes `dbt freshness` for source and model checks in v2.0 and later, while `dbt source freshness` remains supported for source-only checks. Use the command and configuration appropriate to the installed version rather than copying a generic snippet into an older project.

Also make the publication gate explicit. dbt's [source freshness deployment guide](https://docs.getdbt.com/docs/deploy/source-freshness) states that `dbt build` does not itself include source freshness checks and documents different behavior for its freshness checkbox and an explicit job step. Verify that a failed check actually blocks the output you intend to protect.

For data-quality rules, [Dataform's assertion documentation](https://docs.cloud.google.com/dataform/docs/test-data) describes assertions that fail when their query returns violating rows. A test existing in the project is not proof that downstream publication waits for it. Inspect dependencies and run a deliberate failure in a safe environment to prove the gate.

Keep freshness, quality checks and the final destination acknowledgement in one run record. That gives the operator a single place to determine what was safe to publish and what remains unresolved.

## Alert early enough for someone to act

A warning five seconds before a deadline is technically early and operationally useless if recovery takes 20 minutes. Set the warning from observed repair time, the decision deadline and the team's availability.

For the 08:30 daily report, an example warning might fire at 08:00 if any required slice is still missing and typical recovery takes 15 minutes. At 08:30, publish the readiness status even if the team is still investigating. Avoid leaving yesterday's numbers on screen under today's date.

An alert should identify the affected report, source account, missing period, last known usable cutoff, failed check and owner. It should also link to the recovery procedure and explain which business actions should pause. An alert saying only that a model failed forces every responder to rediscover the impact.

Group downstream symptoms under the initiating incident where possible. One failed source can break ten reports; ten unrelated pages do not create ten different root causes. Still verify each consumer after recovery, because a successful source reload may not refresh cached reports or destination audiences.

Test the last mile. If a dashboard cache remains stale after the warehouse recovers, the consumer still has stale data. If a destination rejects an audience update, successful warehouse publication has not fulfilled the activation promise.

## Calculate reliability without hiding missed runs

Under the example 29-of-30 deadline target, one bad delivery in 30 produces 96.67% and still meets the stated target. Two bad deliveries produce 93.33% and fail it. If the team instead promises at least 99% over only 30 daily observations, even one miss produces a failure. Choose a window and target that express the intended tolerance honestly.

Count incomplete or incorrect deliveries as bad when the contract requires readiness, even if they arrived on time. Keep separate failure reasons so the same incident is not counted several times in the overall deadline metric.

Track maximum delay, repeated misses and business impact alongside the ratio. A single missing major-account report can matter more than a harmless low-volume delay. Do not silently remove difficult accounts from the expected inventory to improve the score.

The [late-arriving data guide](https://www.martechdevs.com/blog/late-arriving-marketing-data) covers historical corrections. For a freshness agreement, record whether recovery restored the promised cutoff, whether a backfill changed previous reports and whether affected activation outputs were reconciled.

## Review the cost of making the promise faster

A tighter target may require more frequent extraction, larger processing capacity, different source access, more monitoring and someone available to respond. Estimate those costs against the value of the earlier decision.

If a weekly decision cannot change before Friday, a costly five-minute refresh may provide little benefit. If a customer suppression error sends inappropriate messages within minutes, a daily batch is not an adequate design. The [warehouse ROI guide](https://www.martechdevs.com/blog/data-warehouse-roi) helps frame this tradeoff around operational and commercial outcomes.

Start with the smallest set of outputs whose lateness causes real harm. Measure a baseline, agree on an achievable target and run failure drills before expanding the promise to every table. The contract should make decisions safer and responsibilities clearer, not create a collection of alerts nobody trusts.

![Define the decision, measure cutoff coverage and quality, warn early, publish readiness and review recovery.](https://www.martechdevs.com/assets/blog/marketing-data-freshness-sla.svg)

## Acceptance checks for the agreement

- [ ] The consumer, decision, timezone, deadline and expected source inventory are explicit.
- [ ] Source-through, ingestion, publication and destination refresh timestamps have separate meanings.
- [ ] Missing runs remain in the reliability denominator.
- [ ] Freshness cannot pass solely because one account or one row updated recently.
- [ ] Empty but complete batches can be distinguished from failed or incomplete extraction.
- [ ] A controlled missing-row, duplicate-row and stale-cutoff fixture fails publication as intended.
- [ ] Warnings leave enough recovery time and identify the affected business action.
- [ ] Recovery includes downstream reports or audiences and records any historical restatement.

## Frequently asked questions

### What should a marketing data freshness SLA contain?

Name the consumer decision, required cutoff, coverage, quality rules, deadline, timezone and observation window. Include ownership, warning and failure responses, plus how readiness and recovery are verified at the final destination.

### Is the last successful pipeline run enough to measure freshness?

No. A run can succeed with old, partial or incorrectly transformed data. Check source-through time and required coverage, then confirm the report or activation destination actually received the usable result.

### What if a source has no new records?

Use a verified complete poll, cursor or batch manifest to distinguish no activity from missing delivery. A newest-record timestamp alone cannot make that distinction reliably for a quiet source.

### Does dbt build automatically enforce freshness?

The deployment documentation says source freshness checks are separate from `dbt build`. Configure the version-appropriate freshness command and prove that its failure blocks the publication path you intend to protect.

### How fast should marketing data refresh?

Fast enough for the decision and the harm caused by delay, given source availability and operating cost. A budget review and a customer suppression feed usually need different contracts rather than one universal refresh interval.

## Sources

1. [Google SRE: Implementing service-level objectives](https://sre.google/workbook/implementing-slos/). Accessed 15 September 2026.

2. [dbt: Freshness configuration and version behavior](https://docs.getdbt.com/reference/resource-configs/freshness). Accessed 15 September 2026.

3. [dbt: Source freshness in deployment jobs](https://docs.getdbt.com/docs/deploy/source-freshness). Accessed 15 September 2026.

4. [Google Cloud Dataform: Test data quality with assertions](https://docs.cloud.google.com/dataform/docs/test-data). Accessed 15 September 2026.
