Tracking & Attribution

What Is the 7-Day Event Time Window in Meta CAPI?

Meta CAPI accepts an event_time up to seven days old. What the window measures, why it is not your attribution window, and how to send late conversions.

Quick answer

The seven-day event time window is Meta's limit on how old a conversion event may be at the moment you send it. The `event_time` parameter on a server event must be a Unix timestamp in seconds no more than seven days in the past, and no later than now. It measures the freshness of the event, not the age of the click that caused it — a purchase today from a click three weeks ago is a today-event and sits comfortably inside the window. The limit only bites when you batch up conversions and upload them later.

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

The seven-day event time window is Meta’s limit on how old a conversion event may be when you send it. The event_time parameter on every server event is a Unix timestamp in seconds, and it must sit no more than seven days in the past and no later than the present moment.

It measures the freshness of the event. It says nothing about the age of the click.

That distinction is the whole article: almost every problem blamed on the window comes from reading it as something it is not.

What does the seven-day event time window actually measure?

It measures the gap between when a conversion happened and when your server told Meta about it. Nothing else. If a lead fills your form at 14:02 and your server dispatches the event at 14:02, the gap is zero seconds and the window is irrelevant. If your server dispatches it nine days later, the gap is nine days and the event is outside what the API accepts.

So the window is a rule about your dispatch schedule, not your customers’ behaviour. Teams who fire conversions as they occur never encounter it. Teams who reconcile monthly encounter it on every row.

Meta’s server event documentation is the authority on the parameter itself: event_time is required, it is seconds rather than milliseconds, and it carries no timezone — a Unix timestamp is already an absolute moment.

Why isn’t the seven-day window the same as your attribution window?

Because they are two different clocks owned by two different systems. Your attribution setting lives on the ad set and decides how far back Meta will look for a click when it decides which campaign earned a conversion. The event time window lives in the API and decides whether the event is accepted into the system at all.

One is a crediting rule. The other is an intake rule. They can produce numbers that look alike, which is a coincidence of defaults rather than a connection, and it is the single most common misreading in server-side setups.

Here is the consequence, stated plainly: a click can be older than seven days and still be attributed. A buyer clicks your ad on the 1st, comes back on the 20th and buys. That purchase is a 20th-of-the-month event. Its event_time is the moment the money moved, which is minutes ago, so it clears the window without effort. The nineteen-day-old click is not in the timestamp at all — it is in the identifiers you attach, the _fbc click ID and the hashed email and phone. Meta resolves the person from those and applies its own attribution setting to decide what the click was worth.

Which means the fix for attributing a purchase weeks after the ad click is never a timestamp trick. It is identity. Send the event when it happens, carry the identifiers, and the age of the click stops being your problem.

What happens when you send an event older than seven days?

Two behaviours are possible, and which one you get depends on your own code, not on Meta.

If you send the raw timestamp, Meta rejects the event with a validation error naming event_time, and it never enters the system. The failure lands in a response body nobody reads, so the only visible symptom is a conversion count that runs quietly low.

If your dispatcher clamps instead, the event is sent with its timestamp floored at the seven-day boundary. It delivers, carrying every identifier it would have carried. Its recorded time is wrong by however long the delay was — but a conversion on the wrong day is worth far more than one that does not exist, because the identifiers are what feed matching and optimisation.

There is a second boundary at the other end. An event timestamped in the future — from clock drift, or from a timestamp built in a local timezone ahead of UTC — is capped at the present moment by a future-skew guard rather than refused.

Timeline diagram of Meta's event time window: events inside seven days send as-is, an older event is floored at the seven-day boundary, and a future-dated event is capped at now

Why does a late conversion still matter if its timestamp gets clamped?

Because the timestamp is the least valuable thing in the payload. A conversion event is doing three jobs: telling the platform that a person converted, telling it which person, and telling it when. The first two survive clamping intact.

The algorithm learns from who converted. That learning is what makes the next thousand impressions cheaper, and it happens on the identifier set — hashed email, hashed phone, the click ID, the IP and user agent. Losing a day’s accuracy on the timestamp degrades your day-level reporting. Losing the whole event degrades the model.

So the honest trade-off reads like this. Send late conversions clamped, and accept that a batch of them will pile up on the boundary date in Ads Manager. Do not send them at all, and the platform optimises against a smaller, biased sample — biased specifically against your slowest, and often highest-value, buyers.

What are the three mistakes that push good events outside the window?

Restamping late events to “now.” The tempting workaround, and the most damaging thing in this article. Setting event_time to the current moment passes validation cleanly, so nothing complains — and you have just told Meta that four hundred people converted on a Tuesday afternoon. Every attribution calculation, time-to-conversion curve and optimisation signal now rests on a fiction. Clamping is honest about being approximate; restamping launders old data as new.

Sending milliseconds instead of seconds. Date.now() in JavaScript returns milliseconds. Meta wants seconds. The value is a thousand times too large, which places your event roughly fifty thousand years in the future, and it fails. Divide by 1000 and floor it.

Generating the timestamp in local time. A Unix timestamp has no timezone by definition, but a timestamp built by formatting a local date string and parsing it back acquires an offset. Teams in UTC+10 produce events ten hours in the future; teams in UTC-8 lose eight hours of window. The fix is to take the timestamp from the epoch directly, never from a formatted string.

A fourth habit is not a mistake so much as a design choice with a cost: batching. A nightly job is fine, since everything in it is hours old. A monthly reconciliation guarantees that most of what it carries arrives clamped.

How do you handle a sales cycle longer than seven days?

You separate the conversion you send from the conversion you wait for. A long cycle is not one event at the end; it is a sequence of moments, each of which can be sent the day it happens.

For lead generation: a Lead event when the form is completed, a Schedule event when a call is booked, a Purchase event when the deal closes. Each is dispatched on its own day, each is inside the window, and the campaign gets a signal at every stage instead of one delayed signal at the end. Choosing between them is a topic of its own — which CAPI events to send for lead gen covers the ladder.

For subscription and trial businesses the same pattern applies to the billing event rather than the form. The payment that lands on day 30 is a day-30 event, sent on day 30, and the only thing carrying the original click is the identity attached to it. That is how trial-to-paid conversions weeks later stay attributable without touching a timestamp.

The one case the window genuinely limits is historical backfill. Send the last six months of orders after installing server-side tracking and most of that batch clamps to the boundary. Backfill is useful for your own reporting and for matching customers already in your database. It is not a way to retroactively credit campaigns that ran in the spring.

Do the other ad platforms have the same window?

Every major platform limits how old a server-side event can be, but the limits differ and change, so treat seven days as Meta’s number, not the industry’s. Google’s offline conversion imports, Microsoft’s Conversions API, TikTok’s Events API and Pinterest’s Conversions API each publish their own acceptance rules, and the only reliable source for each is that platform’s current documentation.

What generalises is the architecture. Every one of these endpoints resolves the person from identifiers rather than from the clock, and every one punishes batch reconciliation. Build for same-day dispatch and you are inside all four windows without tracking any of them.

How does PartialLeads handle the seven-day event time window?

By making the window almost never apply, and by clamping honestly when it does.

Conversions dispatch at the moment they occur, from five separate dispatch points — the hot capture path, the catch-up worker, real-time conversion detection, the ecommerce event fan-out, and the inbound purchase pipeline — so no signal path waits for a nightly job. A purchase that arrives through a Shopify, WooCommerce, Stripe, GoHighLevel or universal webhook is matched to its session and fanned out to the Conversions API and the other platforms in the same pass.

When an event does need to go out late — a delayed webhook, a config reconnected after an auth failure, a manual send from an old lead — event_time is clamped rather than dropped: floored a minute inside the seven-day boundary, so the seconds spent in flight cannot push it back over, and capped at the present moment by a future-skew guard. The event delivers with its identifiers intact. Nothing is ever restamped to “now.”

Retries are safe because the event ID is deterministic: a SHA-256 of the pixel ID, event name and record ID, with a UNIQUE dedup table behind it, so a redelivered webhook physically cannot double-fire. That is what makes clamped retries sane — a late resend of an event you already sent is a no-op, not a duplicate.

You can see all of it in the CAPI activity log: each dispatch with its event name, status, platform and the timestamp it carried. The Leads list adds a per-lead API column showing which conversion APIs that lead was dispatched to — the fastest way to answer “did this one actually go out.” Both are part of knowing whether your Meta CAPI is working.

Meta CAPI activity log in the PartialLeads dashboard: one row per dispatch with the event name, status dot, source, EMQ and the event_time each event actually carried — one of them seven days older than the rest

The honest constraints. PartialLeads cannot widen Meta’s window; nobody can. A clamped event’s recorded day is approximate, so a large backfill will visibly stack on the boundary date in Ads Manager — that is the expected shape, not a bug. And dispatch completeness is not the same as attribution: every conversion that reaches the pipeline gets sent, but whether Meta ties it to a user and a click depends on the identifiers captured and on Meta’s own graph. We control dispatch. The platform controls matching.

What breaks The mechanism Where you see it in the dashboard
Conversions batched and uploaded weeks later are rejected Dispatch at the moment of conversion from five separate paths, not a nightly reconciliation CAPI activity log, timestamps close to the event
A genuinely late event fails validation on event_time event_time floored inside the seven-day boundary and capped at now, never restamped CAPI activity log, event timestamp on the row
Resending a delayed event double-counts it Deterministic SHA-256 event ID with a UNIQUE dedup table per config CAPI activity log, one row per event
No way to tell whether a given lead’s event ever went out Per-lead dispatch record for each conversion API Leads list, API column
Late conversions dropped entirely, starving the algorithm Purchases matched to sessions server-side and fanned out to Meta, Pinterest, TikTok and Google Attribution report, Purchases ledger

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

Sources

  1. Meta for Developers — Conversions API: https://developers.facebook.com/docs/marketing-api/conversions-api
  2. Meta for Developers — Conversions API server event parameters (event_time): https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/server-event
  3. Meta for Developers — Deduplicate Pixel and server events: https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events

Frequently asked questions

QCan I send a conversion to Meta CAPI if the ad click was more than seven days ago?
Yes. The seven-day limit applies to the event's own timestamp, not to the age of the click. A purchase today from a click three weeks ago is a today-event, so its event_time clears the window easily. The old click is carried by the identifiers in the payload — the click ID, hashed email and hashed phone — and Meta applies its own attribution setting from there.
QWhat error does Meta return when event_time is outside the window?
A validation error on the event_time parameter, returned in the response body with a code, a human-readable message and an fbtrace_id. The event is not stored. Because the rejection happens server-to-server, nothing surfaces in Events Manager except a conversion count that runs lower than your CRM's — which is why the response body is worth logging.
QShould I set event_time to the current time for old conversions?
No. It passes validation, which is exactly what makes it dangerous. You are telling Meta that a batch of people converted this afternoon, which corrupts attribution windows, time-to-conversion reporting and optimisation at once. Clamping the timestamp to the seven-day boundary is approximate and honest; restamping to now is precise and false.
QIs the seven-day event time window the same as Meta's seven-day attribution window?
No. The attribution setting on your ad set decides how far back Meta looks for a click when crediting a conversion. The event time window is an API intake rule deciding whether the event is accepted at all. They are separate clocks owned by different parts of the system, and the numbers looking alike is a coincidence of defaults.
QWhy is my event_time fifty thousand years in the future?
You sent milliseconds. Date.now() in JavaScript returns milliseconds since the epoch; Meta's event_time is seconds. The value ends up a thousand times too large, which places the event far in the future and fails validation. Divide by 1000 and floor the result. A timestamp built from a formatted local date string causes a smaller version of the same bug.
QCan I backfill six months of historical orders into Meta after installing server-side tracking?
You can send them, but anything older than seven days delivers with its timestamp clamped to the boundary rather than its real date. That is useful for matching customers already in your database and for your own records. It is not a way to retroactively credit campaigns that ran months ago, and the batch will visibly stack on one date in Ads Manager.
QDoes a clamped event still count for optimisation?
It still enters the system with its identifiers, which is what the algorithm learns from. What suffers is day-level reporting, because the event is recorded on the boundary date rather than the day it happened. A conversion on the wrong day is worth considerably more than a conversion that was never sent — but neither is as good as dispatching it the day it occurred.
QDo Google, TikTok, Pinterest and Microsoft have the same seven-day rule?
They all limit how old a server-side event can be, but the limits differ between platforms and change over time, so check each platform's current documentation rather than assuming Meta's number. The architectural answer is the same everywhere: dispatch conversions as they happen and you stay inside every window without tracking any of them.

Find the qualified leads your forms are currently throwing away.

Install PartialLeads on one landing page, send traffic, and compare what your CRM captured against what PartialLeads recovered and qualified.