CPI consensus vs actual is the comparison that decides whether an inflation release moves markets, and the July 2026 print made the point cleanly. On August 12 the BLS reported headline CPI up 0.1% for the month and 3.4% year over year, with core at 0.2% and 2.5%. As CNBC reported, every one of those figures matched the Dow Jones economist consensus exactly. Markets answered with something close to a shrug: broad US equity benchmarks finished the session between minus 0.04% and plus 0.54%, Treasury yields eased, and Bitcoin held the mid-$63,000s with no directional follow-through.
That non-event carries a practical lesson for anyone building research, dashboards, or alerts around scheduled economic releases. The release itself is known months in advance. Prices respond to the gap between the reported number and what was already expected. So when you wire an economic calendar into code, the fields that matter are consensus, actual, the revision history of prior prints, and exact timestamps. The rest is furniture.
The July print, as reported#
The BLS release put headline CPI at 0.1% month over month and 3.4% year over year, down from June's 3.5%. Core CPI came in at 0.2% for the month and 2.5% on the year, also a tenth below the prior reading. Inflation is still cooling, which is real information in an absolute sense. But every bit of it was already in the consensus, and therefore already in prices.
The reaction matched that near-zero surprise. Equities drifted slightly higher, and coverage that day attributed most of the gain to individual earnings reports rather than to the inflation data. Treasury yields fell as rate expectations softened, per CNBC. Crypto barely registered the print at all.
The clearest effect showed up in expectations rather than prices. Before the release, September Fed rate-hike probabilities disagreed sharply across the futures-implied and prediction-market measures that publish them, spanning roughly 36% to 52%. After the in-line print that spread compressed to roughly 36% to 38%, with CME FedWatch showing 38% hike against 62% hold by midday on August 12. One scheduled number collapsed a sixteen-point disagreement into a two-point band while barely moving the underlying assets.
Consensus vs actual: the only pair that is news#
Event-study methodology treats each release as one observation of a surprise: actual minus consensus, usually scaled by the standard deviation of past surprises so that CPI and payroll releases can sit in the same regression. Under that framing, July's CPI was a zero.
This is why a bare release schedule predicts volatility poorly. Everyone knows CPI drops at 8:30 a.m. Eastern on a published date. What nobody knows in advance is the residual against consensus. A calendar feed that only says when events happen answers the easy question. A useful one also carries what forecasters expected, what arrived, what the prior reading was, and precisely when the number became public. Those fields let you compute the surprise, and the surprise is the variable with explanatory power.
The zeros matter too. A model of how much EURUSD moves per unit of CPI surprise needs the no-surprise observations in its sample, and July 2026 is now a clean one. Skipping quiet releases biases the sample toward drama.
Pulling consensus and actual from an economic calendar API#
SiftingIO's economic calendar endpoint returns US releases from official agency calendars, 25 event types covering CPI, payrolls, FOMC decisions, GDP, and the rest, each tagged with a low, medium, or high impact tier:
curl -H "X-API-Key: $SIFTING_KEY" \
"https://api.sifting.io/v1/fnd/economic-calendar"
Each event carries event_id, name, agency, and impact, two timestamps (scheduled_at for when the release is slated, released_at for when it actually landed), and the value fields that drive everything above: consensus, actual, and previous. The value fields stay null until the number is out. Computing a surprise series takes a few lines of Python:
import os
import requests
resp = requests.get(
"https://api.sifting.io/v1/fnd/economic-calendar",
headers={"X-API-Key": os.environ["SIFTING_KEY"]},
)
resp.raise_for_status()
for event in resp.json()["data"]:
if event["actual"] is None or event["consensus"] is None:
continue # scheduled but not yet released
surprise = event["actual"] - event["consensus"]
print(event["name"], event["released_at"], surprise)
Results paginate with a cursor (meta.next_cursor), and the full field reference is under /docs/economic-calendar.
Where measurement infrastructure earns its keep#
On a day like August 12 there's little to measure. The print matched, prices shrugged, and a daily bar tells most of the story. The case for careful plumbing rests on the other days: the print that comes in two tenths hot, where the repricing happens in the seconds and minutes after released_at. Measuring that reaction honestly means joining the release timestamp against tick data or 1-minute bars on the same clock, UTC throughout, and being able to say exactly which bar contained the release and which bars came after. For the bar side, historical endpoints like /v1/hist/forex/EURUSD/bars serve 1-minute FX bars in UTC. A pipeline that can only align events to a calendar date merges the reaction with six and a half hours of unrelated trading.
The levels quoted in this post are closing figures as publicly reported, and for an in-line day that resolution is enough. A day that deviates deserves better, and the time to have the timestamp discipline in place is before it arrives.
Common pitfalls#
- Aligning to
scheduled_atinstead ofreleased_at. Releases are occasionally delayed, and a reaction window stamped from the scheduled time can begin before the number exists. Anchor event windows toreleased_atand align to the bar containing that timestamp. Date-only joins are worse still, since they blend the release reaction with a full session of unrelated moves. - Treating consensus as one universal number. July's figures matched the Dow Jones survey exactly, but different surveys poll different forecasters, and the same release can score as a zero surprise against one median and a small beat against another. Store the consensus you computed against, as it stood at release time, next to the surprise itself.
- Backfilling revised values into history. Monthly releases revise earlier months, so June's figure as restated in a later release can differ from June's original print. A pipeline that overwrites
actualwith the latest revision hands a backtest information that didn't exist at decision time. Keep first prints and revisions in separate columns and compute historical surprises from first prints only.
The tooling here is ordinary: a calendar feed that exposes consensus, actual, previous, and both timestamps, plus the discipline to store values as they were known at the time. Releases that land on forecast will keep looking like non-events, and July's CPI was a textbook one. The next print that misses is when the plumbing proves its worth.



