bls-api-client
A sync + async client inspired by blsR for the U.S. Bureau of Labor Statistics
(BLS) Public Data API.
- Sync and async clients (
BLSClient,AsyncBLSClient). - Polars output returns easy to use and convert Polars Dataframes.
- Automatic batching over the BLS per-request limits (series count and year span).
Installation
Requires Python 3.11+:
pip install bls-api-client
# or
uv add bls-api-client
import blsapi
Quick start
from blsapi import BLSClient
with BLSClient() as client:
df = client.get_series("LNS14000000", start_year=2023, end_year=2024)
print(df)
The result is a Polars DataFrame. Exporting elsewhere is simple:
df.write_parquet("data.parquet")
df.write_csv("data.csv")
df.to_pandas()
df.to_arrow()
Async
import anyio
from blsapi import AsyncBLSClient
async def main():
async with AsyncBLSClient() as client:
df = await client.get_series("LNS14000000", start_year=2023, end_year=2024)
print(df)
anyio.run(main)
Configuration
Everything has a sensible default, so bls-api-client works out of the box.
API key
A registration key is optional but raises your rate limits substantially. The key is resolved with this precedence:
- The explicit
api_key=argument, if given. - Otherwise the
BLS_API_KEYenvironment variable. - Otherwise no key (unauthenticated tier).
Example:
# Explicit (highest precedence)
client = BLSClient(api_key="API_KEY")
# Or rely on the environment
# export BLS_API_KEY=API_KEY (macOS/Linux)
# $env:BLS_API_KEY = "API_KEY" (PowerShell)
client = BLSClient()
client.has_key # returns True if a key is active
Other options
All are keyword-only on both clients:
| Argument | Default | Purpose |
|---|---|---|
api_key |
None -> BLS_API_KEY |
Registration key. |
base_url |
https://api.bls.gov/publicAPI/v2/ |
API base URL. |
timeout |
5/30/10/5s (connect/read/write/pool) |
httpx2.Timeout. |
max_retries |
3 |
Application-level retries for transient failures. |
auto_batch |
True |
Transparently split over the tier limits. |
user_agent |
blsapi/<version> |
Sent as User-Agent. |
client |
None |
Inject your own httpx2.Client/AsyncClient. |
import httpx2
from blsapi import BLSClient
client = BLSClient(
api_key="API_KEY",
max_retries=5,
timeout=httpx2.Timeout(connect=5.0, read=60.0, write=10.0, pool=5.0),
user_agent="app/1.0 (you@example.com)",
)
Usage
Multiple series and named aliases
Pass a list of ids, or a {label: id} mapping to relabel the output's series_id column:
df = client.get_series(
{"unemployment": "LNS14000000", "cpi": "CUUR0000SA0"},
start_year=2020,
end_year=2024,
)
df["series_id"].unique().to_list() # ["cpi", "unemployment"]
Wide format
Reshape the long frame to one value column per series, indexed by date:
from blsapi import pivot_wide
wide = pivot_wide(df) # columns: date, unemployment, cpi
(Annual-average rows have no real date and are dropped by pivot_wide.)
Calculations and catalog
df = client.get_series(
"LNS14000000", start_year=2023, end_year=2024, calculations=True
)
# adds net_change_{1,3,6,12}m and pct_change_{1,3,6,12}m columns, as provided by the BLS API.
resp = client.get_series_raw("LNS14000000", catalog=True) # returns a BLSResponse with catalog metadata
Surveys and popular series
client.list_surveys() # returns a Polars DataFrame of all surveys
client.get_survey("CU") # returns a dict of metadata for one survey
client.get_popular() # returns list of popular series ids
client.get_popular("LN") # returns popular ids within a survey
Quota planning
client.query_cost(["LNS14000000", "CUUR0000SA0"], 2000, 2024) # returns the number of API calls used
Error handling
All errors derive from BLSError, so you can catch broadly or narrowly:
from blsapi import BLSError, BLSValidationError, BLSAPIError, BLSHTTPError
try:
df = client.get_series("BAD_ID", start_year=2024, end_year=2023)
except BLSValidationError:
... # bad input caught locally, before any network call
except BLSAPIError as e:
... # BLS returned a non-success status; inspect e.status and e.messages
except BLSHTTPError:
... # transport/HTTP failure that persisted through the retry loop
except BLSError:
... # anything else from this library
Tiers & limits
| Series per request | Years per request | Queries per day | |
|---|---|---|---|
| No key | 25 | 10 | 25 |
| With key | 50 | 20 | 500 |
With auto_batch=True (the default), requests that exceed the per-request limits are split
into multiple calls automatically and stitched back together. Register for a free key at
https://data.bls.gov/registrationEngine/.
Development
uv sync # install dependencies
uv build # build the sdist + wheel
License
Metadata
Release files for bls-api-client 1.0.0.post1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bls_api_client-1.0.0.post1.tar.gz | 27.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bls_api_client-1.0.0.post1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 46.3 kB
Release files / bls_api_client-1.0.0.post1.tar.gz
| Download URL | bls_api_client-1.0.0.post1.tar.gz |
|---|---|
| Size | 27.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0371f6ec0ee40ec1e0187d5ff15dc5c0763b5ad1fab18a5190fa49e083407fd0
|
|
BLAKE2b-256 checksum How to use checksums |
aa6ce057672df1d463ab728e8e19ce545564339e45849465586112d0927702cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / bls_api_client-1.0.0.post1-py3-none-any.whl
| Download URL | bls_api_client-1.0.0.post1-py3-none-any.whl |
|---|---|
| Size | 19.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7afd49c9f2388913ae90ff1878c340c546728b1c7b55ae8be6589355bad91be2
|
|
BLAKE2b-256 checksum How to use checksums |
87cfc0745792b01fdd7bac14bafa8736d7047857ad0ff2fca04291c2f8166451
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|