event_date is a claim about the world. coded_at is a claim about us. A backtest that filters on
event_date alone is asking “what happened by date D”, which is a question no one could have
answered on date D.
The as-of claim we do make
Filtering on when an event was coded gives you the set of events that existed in GDELT Cloud at that time. That is a real point-in-time view, and it is auditable in both directions:- The coding timestamp is populated on 100% of events, stamped once when the coder emits the event and never revised.
- Every event carries
source_urls— the actual articles it was derived from. Nothing is coded from a source we do not cite, so you can go read the evidence that was available at the time.
How to ask for it
The lever has a different name on each surface, and there is noas_of on events.
as_of on /api/v2/events returns 400, deliberately. Event metrics are computed live and are
not vintaged, so as_of could not return a reproducible point-in-time result there — and answering
200 with a plausible-looking result would be worse than refusing. Use observed_start /
observed_end, which bound something we actually record. as_of is supported where the data is
genuinely vintaged: /macro/observations, /screening/match and the Atlas /intelligence/*
surfaces.Why events are coded after the day they happened
Measured over the seven days ending 2026-07-21, across 11,993 events: the median gap between an article becoming available to us and its coded event being queryable is 38 minutes, with a 90th percentile of 61 minutes. 89.1% of events are available within the hour. Lag measured the other way — againstevent_date rather than against the article — looks much
larger, and the difference is mostly arithmetic rather than processing. Three real causes, in order.
1. Hourly cadence
Ingest runs on the top of every hour, so there is an irreducible sub-hour quantisation: an article that appears just after a run waits for the next one. The floor is set by the cycle, not by processing time, which is why the median lands near half a cycle plus the pipeline’s own duration. A separate catch-up pass runs near the end of each hour and sweeps clusters the main run did not reach, and range backfills re-code historical windows when coverage gaps are found.2. Publication lag in the sources themselves
event_date is when the event occurred, not when it was reported. Local and non-English outlets
frequently publish on D+1 about a D event, and for some regions that is the only coverage. The
conflict family shows this most.
3. The midnight boundary — an artefact, not a delay
event_date is a date, not a timestamp. An event that happened at 22:00 UTC and was coded at
23:00 UTC — one hour later — already registers as “coded the same day” with almost no margin, and
one coded at 00:30 registers as a next-day event on a 90-minute pipeline. Most of the apparent
day-scale lag against event_date is this, not work in progress.
We do not wait for corroboration before coding. A story does not have to accumulate articles to
become codeable — single-article clusters are a first-class coding path and are the majority of what
we code. Measured over the same window, computing latency from the earliest contributing article,
including everything that arrived later, moves the median by 32 seconds (2,332 s vs 2,300 s). If
coverage had to accrete before an event could be coded, that gap would be hours.
Later-coded events are better evidenced — but that is selection, not waiting
Comparing events coded within a day of theirevent_date against those coded in the following day:
The reason is which net caught them, not how long they sat. The hourly catch-up pass targets
clusters the main run left uncoded and requires at least two articles, so the events it recovers are
by construction the better-corroborated ones. Either way the practical conclusion holds: if you
drop the tail to get a tighter latency number, you are dropping your best-evidenced events.
How to use this in a backtest
1
Filter on when we coded it, not on when it happened
For a signal you claim to have had at time T, bound
observed_end at T. Filtering on
event_date alone silently imports hindsight.2
Set your decision lag from the distribution, not the median
If your strategy acts on same-day information, model a decision point at T+24h and accept that
you will see roughly 89% of the day’s events. If it can wait, T+48h gets you effectively all of
them, with better evidence.
3
Do not treat a thin day as a quiet day
A day with an unusually low event count near the present is more likely still filling in than
genuinely calm. Re-pull recent windows before drawing a conclusion about them, and prefer
windows that are at least 48 hours old.
4
Check the file's own as-of stamp
Every bulk file carries an
as_of value that reports what the weakest partition in it knew —
the minimum across dates, not the maximum, so one freshly settled day cannot vouch for a stale
month.
