By the end of this guide you will have a working SSE subscriber that listens for new FXMacroData release events in real time, filters for the currencies and indicators you care about, and then pulls the full indicator payload from the REST API the moment a release is published.
Prerequisites
- A FXMacroData API key if you want non-USD streams; USD-only streams work without authentication
- A browser environment for the
EventSourceexample, or Python 3.9+ for the worker example - The
requestspackage installed if you want to follow the Python example (pip install requests) - A basic understanding of the announcement endpoints such as USD inflation docs and EUR policy rate docs
Step 1 — Understand what the SSE stream delivers
The new SSE endpoint opens a long-lived HTTP connection and pushes an event every time FXMacroData ingests a fresh economic release. The endpoint is:
https://fxmacrodata.com/api/v1/stream/events
You can narrow the feed with two optional query parameters:
currencies— a comma-separated list such asusd,eurindicators— a comma-separated list such asinflation,policy_rate
For non-USD currencies, pass your API key as a query parameter. For example:
curl -N "https://fxmacrodata.com/api/v1/stream/events?currencies=eur,gbp&indicators=inflation,policy_rate&api_key=YOUR_API_KEY"
If you connect without filters and without a Professional key, the stream is automatically restricted to USD events. That makes SSE useful even for a free proof-of-concept before you wire in broader coverage.
Important behavior
- The stream is a trigger, not the full dataset. Each SSE message tells you that a release landed; you still call the matching announcement endpoint to fetch the full records.
- The server sends heartbeats. Idle connections receive a
: heartbeatcomment roughly every 15 seconds so proxies do not close the stream. - Each event includes an ID. That ID is what powers replay on reconnect via
Last-Event-ID.
Step 2 — Know the event format before you write a client
FXMacroData emits standard W3C EventSource frames. A typical message looks like this:
id: usd_inflation_1772109000
event: announcement
data: {"event_id": "usd_inflation_1772109000", "currency": "usd", "indicator": "inflation", "records_written": 1, "timestamp": 1772109002}
The payload fields are intentionally small and operational:
event_id— deterministic identifier in the form{currency}_{indicator}_{timestamp}currency— lowercase currency code such asusdoreurindicator— the FXMacroData indicator slug, for exampleinflation,policy_rate, ornon_farm_payrollsrecords_written— number of new records saved during ingestiontimestamp— Unix timestamp for when the event was published onto the stream
Because the SSE message does not carry the full time series, the normal pattern is: listen for the event, then call the relevant endpoint under API data docs to retrieve the newly available release data.
Step 3 — Open the stream in a browser with EventSource
If you are building a dashboard, browser-based notifier, or internal monitoring page, native
EventSource is the simplest way to consume the stream. Use the query string for auth so
the connection works in the browser without custom headers.
const apiKey = "YOUR_API_KEY";
const streamUrl = new URL("https://fxmacrodata.com/api/v1/stream/events");
streamUrl.searchParams.set("currencies", "eur,gbp");
streamUrl.searchParams.set("indicators", "inflation,policy_rate");
streamUrl.searchParams.set("api_key", apiKey);
const source = new EventSource(streamUrl);
source.addEventListener("announcement", async (event) => {
const payload = JSON.parse(event.data);
console.log("Release received", payload);
const dataUrl = new URL(
`https://fxmacrodata.com/api/v1/announcements/${payload.currency}/${payload.indicator}`
);
dataUrl.searchParams.set("api_key", apiKey);
const response = await fetch(dataUrl);
const records = await response.json();
const latest = records[records.length - 1];
console.log("Latest record", latest);
});
source.onerror = (error) => {
console.error("SSE connection problem", error);
};
Native EventSource automatically reconnects when the connection drops. Because FXMacroData
sends an id: field with each message, the browser will automatically include the last received
event ID during reconnects, which lets the server replay buffered events you missed.
Why this pattern works well
Your page stays idle until a release actually lands. There is no five-minute poller, no wasted requests, and no timing gap between publication and your refresh logic. That is especially useful for high-sensitivity releases such as USD non-farm payrolls or EUR inflation.
Step 4 — Fetch the full indicator payload after each alert
The most important design point is that SSE tells you when to fetch, not everything to display. After an event arrives, call the matching announcement endpoint and inspect the freshest record.
async function fetchLatestRelease(currency, indicator, apiKey) {
const url = new URL(`https://fxmacrodata.com/api/v1/announcements/${currency}/${indicator}`);
if (currency !== "usd") {
url.searchParams.set("api_key", apiKey);
}
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Announcement fetch failed: ${response.status}`);
}
const records = await response.json();
return records[records.length - 1] ?? null;
}
source.addEventListener("announcement", async (event) => {
const payload = JSON.parse(event.data);
const latest = await fetchLatestRelease(payload.currency, payload.indicator, apiKey);
if (latest) {
console.log(`New ${payload.currency.toUpperCase()} ${payload.indicator}`, latest);
}
});
This keeps the stream lightweight while preserving the full fidelity of the REST endpoints. It also means the same downstream parsing code can be reused whether your trigger comes from SSE, a scheduler, or a manual API call.
Step 5 — Build a Python worker with explicit replay on reconnect
For a server-side daemon or bot, it is often useful to control reconnect logic directly and send the
Last-Event-ID header yourself. The example below listens for announcement events, stores the
last seen ID, and replays missed buffered events after a disconnect.
import json
import time
import requests
API_KEY = "YOUR_API_KEY"
STREAM_URL = (
"https://fxmacrodata.com/api/v1/stream/events"
"?currencies=eur,gbp&indicators=inflation,policy_rate&api_key=" + API_KEY
)
def fetch_latest_release(currency: str, indicator: str) -> dict | None:
url = f"https://fxmacrodata.com/api/v1/announcements/{currency}/{indicator}"
params = {"api_key": API_KEY} if currency != "usd" else {}
response = requests.get(url, params=params, timeout=20)
response.raise_for_status()
records = response.json()
return records[-1] if records else None
def consume_stream() -> None:
last_event_id = None
while True:
headers = {"Accept": "text/event-stream"}
if last_event_id:
headers["Last-Event-ID"] = last_event_id
try:
with requests.get(STREAM_URL, headers=headers, stream=True, timeout=90) as response:
response.raise_for_status()
event = {}
for raw_line in response.iter_lines(decode_unicode=True):
if raw_line is None:
continue
line = raw_line.strip()
if not line:
if event.get("event") == "announcement" and event.get("data"):
payload = json.loads(event["data"])
last_event_id = event.get("id") or payload["event_id"]
latest = fetch_latest_release(
payload["currency"],
payload["indicator"],
)
print("Announcement event", payload)
print("Latest record", latest)
event = {}
continue
if line.startswith(":"):
continue
field, _, value = line.partition(":")
event[field] = value.lstrip()
except requests.RequestException as exc:
print(f"Stream disconnected: {exc}. Reconnecting in 3 seconds...")
time.sleep(3)
if __name__ == "__main__":
consume_stream()
This is the right pattern when you need deterministic replay across temporary outages. If the connection drops after an event was published but before your worker processed it, the next request includes the last received ID and the server replays buffered events that came after it.
Step 6 — Decide what you want to do when an event lands
Once the stream is wired in, the real design choice is what happens downstream. Common patterns include:
Refresh a dashboard card
When a matching event arrives, fetch the latest record and redraw one panel instead of reloading the entire page.
Trigger a trading or alert workflow
Push the event into Slack, email, or a trading queue after you compare the latest release with your thresholds.
Warm a cache
Use SSE as the invalidation trigger, then refresh the affected indicator cache only when new data is confirmed.
Combine with the release calendar
Use the release calendar guide to know what is scheduled next, then keep SSE open as the live confirmation layer.
Step 7 — Handle a few edge cases up front
SSE is simple, but production use still benefits from a few rules:
- Do not assume one event equals one value.
records_writtenmay be greater than one if a release updates more than a single record. - Expect reconnects. Browsers, proxies, and mobile networks will occasionally break long-lived connections; replay support exists for exactly this reason.
- Keep the stream narrow where possible. Filtering by
currenciesandindicatorsreduces noise and avoids unnecessary downstream fetches. - Leave REST as the source of truth. The stream tells you a release happened; the canonical record still comes from the matching announcement endpoint.
What you built
You now have the core event-driven pattern for FXMacroData realtime workflows: subscribe to
/api/v1/stream/events, filter to the currencies and indicators that matter, react to
announcement events as they arrive, and fetch the full release data only when the stream tells you
something new has landed.
A natural next step is to combine SSE with the release calendar scheduling guide so you know what is due next and still receive an immediate signal when publication actually happens.
— The FXMacroData Team