US Bureau of Labor Statistics
BLS API — CPI, jobs and wages straight from the agency that measures them — before FRED mirrors them
Release morning, when you want the official CPI, payrolls or unemployment number the moment it is out, and for the detailed CPI components (shelter, food, energy) that FRED carries only partly.
Reach for it when…
Release morning, when you want the official CPI, payrolls or unemployment number the moment it is out, and for the detailed CPI components (shelter, food, energy) that FRED carries only partly.
Not for: Long-history charting across many series (FRED is quicker), international comparisons (OECD, BIS), anything outside prices and labour.
Units, revisions, traps
Units. CPI series are indexes (1982–84 = 100); the headline 'inflation' is the 12-month percent change of the not-seasonally-adjusted index. Payrolls are levels in thousands.
Revisions. Payrolls are revised in each of the next two releases and again at the annual benchmark; CPI is not revised except seasonal factors.
- CUUR = not seasonally adjusted, CUSR = seasonally adjusted: the 12-month change uses NSA, the month-on-month uses SA.
- The no-key quota is per IP address and resets daily — a loop can burn it in a minute.
- Series ids encode the survey: CU (CPI), LN (household survey), CE (payrolls).
Classic mistake: Quoting the month-on-month change of the NSA index in December and calling it a slowdown.
Three recipes
- Recipe 1 · CPI-U, 12-month change, no key
- Recipe 2 · Payrolls and unemployment in one call
- Recipe 3 · Excel: the Data Finder without code
Each recipe: Python · Excel · Sheets, with how to read the result. Python recipes run under pandas; recipe 1 is re-run by the weekly check where the source allows it.
How to use it in your own work
Copy the snippet, change the series id, read the result the way the footer says. Replace YOUR_…_KEY with your own key where one is needed.
Recipe 1CPI-U, 12-month change, no key
# headline CPI-U (NSA index) → 12-month % change
import requests, pandas as pd
u = "https://api.bls.gov/publicAPI/v2/timeseries/data/CUUR0000SA0?startyear=2023&endyear=2026"
rows = requests.get(u, timeout=30).json()["Results"]["series"][0]["data"]
df = pd.DataFrame(rows)
df = df[df.period.str.startswith("M")]
df["date"] = pd.to_datetime(df.year + "-" + df.period.str[1:] + "-01")
s = pd.to_numeric(df.set_index("date")["value"], errors="coerce").sort_index()
print((s.pct_change(12) * 100).dropna().tail(6).round(1))- Data → From Web → the same URL; expand Results › series › data into a table, then a column with =C2/C14-1 for the 12-month change.
- No native JSON import — use the Python recipe, or FRED's CSV of the same series (CPIAUCNS).
Recipe 2Payrolls and unemployment in one call
# two series in one POST (no key: up to 25 series per request, 10 years)
import requests, pandas as pd
body = {"seriesid": ["CES0000000001", "LNS14000000"], "startyear": "2022", "endyear": "2026"}
r = requests.post("https://api.bls.gov/publicAPI/v2/timeseries/data/", json=body, timeout=30).json()
out = {}
for s in r["Results"]["series"]:
d = pd.DataFrame(s["data"]); d = d[d.period.str.startswith("M")]
d["date"] = pd.to_datetime(d.year + "-" + d.period.str[1:] + "-01")
out[s["seriesID"]] = d.set_index("date")["value"].astype(float).sort_index()
df = pd.DataFrame(out); df["payroll_change_k"] = df["CES0000000001"].diff()
print(df.tail(6))- Use the Data Finder (data.bls.gov/dataQuery) → add both series → Download CSV.
- Download the CSV from the Data Finder and File → Import.
Recipe 3Excel: the Data Finder without code
# the same numbers from the CSV the Data Finder exports (download first)
import pandas as pd
df = pd.read_csv("SeriesReport.csv", skiprows=11) # header rows vary by export
print(df.head())- data.bls.gov/dataQuery → search 'CPI-U all items' → tick the series → Download (CSV or XLSX).
- The file has ten header rows of metadata before the table.
- File → Import the downloaded CSV; set the header row to the one starting 'Series ID'.
Series → question map
The ids we use from BLS API, each with the question it answers. The catalog's compare view reads the concept tags behind these rows.
| Series | Answers | Region | Concept |
|---|---|---|---|
| CUUR0000SA0 | What is US inflation doing? (CPI-U, NSA index) | United States | cpi |
| CUSR0000SA0 | Month-on-month CPI (seasonally adjusted) | United States | cpi |
| LNS14000000 | What is the unemployment rate? | United States | unemployment |
| CES0000000001 | How many jobs were added? (nonfarm payrolls, thousands) | United States | payrolls |
| CES0500000003 | Are wages rising? (average hourly earnings, private) | United States | wages |
| CUUR0000SAH1 | Is shelter inflation cooling? | United States | cpi |
Compare with
Same question, different source: FRED, BEA API, Eurostat API. The compare view lines up coverage, frequency, history and access side by side and lists what the combination makes possible.
Questions readers ask
Do I need a BLS API key?
No for up to 25 requests a day and 10 years per series. A free registration key raises that to 500 a day, 20 years and 50 series per request.
Why does the BLS CPI differ from FRED's CPIAUCSL?
Same survey, different adjustment: CUUR0000SA0 is not seasonally adjusted, CPIAUCSL is. Their 12-month changes agree closely; month-on-month values differ.
When is CPI released?
Usually mid-month at 08:30 Eastern for the previous month; the schedule is at bls.gov/schedule/news_release/cpi.htm.
From the paper
Educational only — we explain, we never advise · snippet licence: public domain · corrections to [email protected], fixed within a day and logged in the changelog.