Runnable examples and a fully-mocked test suite for the official
newsdata.io Python client
(newsdataapi).
newsdata.io is a news API that gives you programmatic access to articles from 90,000+ news sources across 206 countries, 89 languages, and 17 categories. You can fetch real-time breaking news, search a historical archive, and get specialized crypto and financial-market coverage — all as clean JSON.
This repository is a learning-by-example companion to the official
newsdataapi Python SDK. It contains:
examples/— one runnable script per endpoint, each showing 3–5 realistic queries with inline comments explaining every parameter.tests/— apytestsuite that mocks every HTTP call (so it runs offline with no API key) and verifies the happy path, edge cases, and every documented error code.
If you have never used newsdata.io before, start at Quick Start.
| Endpoint | SDK method | Description | Example file |
|---|---|---|---|
| Latest News | latest_api() |
Real-time news from the last 48 hours | examples/latest_news.py |
| News Archive | archive_api() |
Historical news search over a date range | examples/news_archive.py |
| News Sources | sources_api() |
Discover available publishers / source_ids |
examples/news_sources.py |
| Crypto News | crypto_api() |
Cryptocurrency news, filterable by coin |
examples/crypto_news.py |
| Market News | market_api() |
Financial news, filterable by symbol |
examples/market_news.py |
| News Count | count_api() |
Aggregate article counts over a date range | examples/news_count.py |
| Crypto Count | crypto_count_api() |
Aggregate crypto counts over a date range | examples/news_count.py |
| Market Count | market_count_api() |
Aggregate market counts over a date range | examples/news_count.py |
| Pagination & CSV | (all of the above) | Manual / generator / scroll paging + CSV export | examples/pagination_and_export.py |
| Error handling | (all of the above) | Catching the typed exception hierarchy | examples/error_handling.py |
Clone this repo, then from its root install the dependencies with either pip or uv:
# Using pip
pip install -r requirements.txt# Using uv (faster; creates/uses an isolated .venv automatically)
uv venv # create a virtual environment
uv pip install -r requirements.txt # install into itThis installs the SDK (newsdataapi), python-dotenv for key management, and
the test dependencies (pytest, pytest-mock).
Just want the SDK in your own project?
pip install newsdataapioruv add newsdataapi
- Create a free account at https://newsdata.io/register.
- Open your dashboard at https://newsdata.io/dashboard.
- Copy your API key (it looks like
pub_xxxxxxxxxxxxxxxxxxxxxxxx).
Your key is read from a local .env file so it is never hardcoded or
committed (.env is git-ignored).
cp .env.example .env
# then edit .env and paste your key:
# NEWSDATA_API_KEY=pub_your_api_key_herepython examples/latest_news.pyEvery script in examples/ is standalone and runnable the same way.
The most common call for each endpoint. All filters are keyword-only; most accept either a single string or a list of strings (lists are comma-joined automatically).
from newsdataapi import NewsDataApiClient
# The context manager closes the HTTP session cleanly on exit.
with NewsDataApiClient("YOUR_API_KEY") as client:
# --- Latest News --------------------------------------------------------
latest = client.latest_api(q="bitcoin", country="us", language="en")
for article in latest["results"]:
print(article["title"], "-", article["link"])
# --- News Archive (date range required) ---------------------------------
archive = client.archive_api(
q="olympics", from_date="2024-01-01", to_date="2024-01-31"
)
# --- News Sources -------------------------------------------------------
sources = client.sources_api(country="us", category="technology")
# --- Crypto News (coin filter is unique to this endpoint) ---------------
crypto = client.crypto_api(coin=["btc", "eth"], language="en")
# --- Market News (symbol filter is unique to this endpoint) -------------
market = client.market_api(symbol=["AAPL", "MSFT"], language="en")
# --- Count endpoints (from_date & to_date are positional) ---------------
counts = client.count_api("2024-01-01", "2024-01-07", q="bitcoin", interval="day")The most useful filters shared across the news endpoints. See the official docs for the full list.
| Parameter | Type | Description | Example |
|---|---|---|---|
q |
str |
Full-text search; supports AND/OR/NOT and "exact phrases" |
q="bitcoin AND etf" |
qInTitle |
str |
Search only in the title (mutually exclusive with q) |
qInTitle="tesla" |
qInMeta |
str |
Search title + description + keywords (mutually exclusive with q) |
qInMeta="ai" |
country |
str | list[str] |
ISO-2 country codes (up to 5 on free/basic) | country=["us", "gb"] |
category |
str | list[str] |
Topic: business, technology, sports, health, … | category="technology" |
language |
str | list[str] |
ISO language codes | language="en" |
domain |
str | list[str] |
Restrict to specific source_ids |
domain="bbc" |
domainurl |
str | list[str] |
Restrict to specific publisher URLs | domainurl="bbc.com" |
excludedomain |
str | list[str] |
Exclude specific domains | excludedomain="cnn.com" |
prioritydomain |
str |
Source quality tier: top / medium / low |
prioritydomain="top" |
timeframe |
int | str |
Limit to the last N hours/minutes | timeframe=6 |
from_date / to_date |
str |
Date window (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS) |
from_date="2024-01-01" |
size |
int |
Articles per page, 1–50 | size=50 |
page |
str |
nextPage cursor for the next page of results |
page="<token>" |
full_content |
bool |
Include the scraped article body | full_content=True |
image |
bool |
Only articles that have an image | image=True |
video |
bool |
Only articles that have a video | video=True |
removeduplicate |
bool |
Drop near-duplicate stories | removeduplicate=True |
sentiment |
str |
positive / negative / neutral |
sentiment="positive" |
tag |
str | list[str] |
Filter by AI-assigned content tags | tag="blockchain" |
sort |
str |
pubdatedesc (default) / pubdateasc / relevance |
sort="relevance" |
coin |
str | list[str] |
Crypto only — ticker symbols | coin=["btc", "eth"] |
symbol |
str | list[str] |
Market only — stock tickers | symbol="AAPL" |
organization |
str | list[str] |
Company-name filter | organization="Tesla" |
interval |
str |
Count only — bucket size (hour, day, all) |
interval="day" |
Mutually-exclusive groups (setting more than one raises
NewsdataValidationError before any request is sent):
q / qInTitle / qInMeta · country / excludecountry ·
category / excludecategory · language / excludelanguage ·
domain / domainurl / excludedomain. Also, sentiment_score requires
sentiment to be set.
The SDK raises a typed exception hierarchy. All errors derive from
NewsdataException, so except NewsdataException is always a valid catch-all.
NewsdataException (base — catch-all)
├── NewsdataValidationError client-side: bad / conflicting params
├── NewsdataNetworkError network failure (timeout, DNS, ...)
└── NewsdataAPIError the API returned an error status
├── NewsdataAuthError 401 / 403
├── NewsdataRateLimitError 429
└── NewsdataServerError 5xx
| HTTP code | Cause | Exception raised | How to handle |
|---|---|---|---|
200 |
Success | (none) | Use response["results"] |
400 |
Bad request / missing required parameter | NewsdataAPIError |
Fix the request; check required params |
401 |
Invalid or missing API key | NewsdataAuthError |
Verify NEWSDATA_API_KEY is set & correct |
403 |
Key not allowed for this resource / plan | NewsdataAuthError |
Check your plan & API key permissions |
409 |
Parameter conflict | NewsdataAPIError |
Remove conflicting parameters |
415 |
Unsupported parameter type | NewsdataAPIError |
Send the correct type for each param |
422 |
Validation error (bad parameter value) | NewsdataAPIError |
Correct the offending parameter value |
429 |
Rate limit exceeded | NewsdataRateLimitError |
Back off; honor err.retry_after seconds |
5xx |
Server-side error | NewsdataServerError |
Transient — the SDK retries; try again later |
| (network) | Timeout / connection failure | NewsdataNetworkError |
Inspect err.original; retry later |
| (client-side) | Invalid / conflicting params (caught locally) | NewsdataValidationError |
Check err.param; no request was sent |
from newsdataapi import (
NewsDataApiClient, NewsdataAuthError, NewsdataRateLimitError,
NewsdataAPIError, NewsdataException,
)
with NewsDataApiClient("YOUR_API_KEY") as client:
try:
response = client.latest_api(q="technology")
except NewsdataAuthError as e:
print(f"Bad API key (HTTP {e.status_code})")
except NewsdataRateLimitError as e:
print(f"Rate limited — retry after {e.retry_after}s")
except NewsdataAPIError as e:
print(f"API error {e.status_code}: {e.response_body}")
except NewsdataException as e: # catch-all for anything else
print(f"Request failed: {e}")See examples/error_handling.py for a full demo.
The test suite is fully mocked — it makes no real HTTP requests and needs no API key.
# Using pip
pip install -r requirements.txt
pytest tests/# Using uv
uv pip install -r requirements.txt
uv run pytest tests/Useful variations (prefix with uv run if you installed with uv):
pytest tests/ -v # verbose, one line per test
pytest tests/test_latest_news.py # a single endpoint's tests
pytest tests/ -k "rate_limit" # only tests matching a keywordTests use pytest-mock to patch the client's HTTP session, and shared fixtures
(client, mock_get, sample_article, …) live in
tests/conftest.py.
Each newsdata.io plan has its own request rate and articles-per-request limit
(free accounts return 10 articles/request; paid plans return up to 50). When
you exceed the limit the API returns HTTP 429. The SDK automatically
retries with exponential backoff (honoring the Retry-After header) and,
only after exhausting max_retries, raises NewsdataRateLimitError with a
.retry_after hint. Tune the behavior at construction time:
client = NewsDataApiClient(
"YOUR_API_KEY",
max_retries=5, # attempts before giving up
retry_backoff=2.0, # base backoff seconds (doubles each attempt)
pagination_delay=1.0, # seconds slept between pages while scrolling
)Results come one page at a time with a nextPage cursor. The SDK gives you
three ways to consume them (see
examples/pagination_and_export.py):
# 1. Manual — pass the cursor yourself.
page1 = client.latest_api(q="tech")
page2 = client.latest_api(q="tech", page=page1["nextPage"])
# 2. Generator — yields one response per page (max_pages caps total pages).
for page in client.latest_api(q="tech", paginate=True, max_pages=5):
print(len(page["results"]))
# 3. Scroll — auto-follows the cursor and merges everything into one dict
# (max_result caps how many articles are accumulated).
merged = client.latest_api(q="tech", scroll=True, max_result=200)To stay within limits while paginating, keep pagination_delay at a sensible
value and bound your loops with max_pages / max_result.
- 📖 Official API documentation — https://newsdata.io/documentation
- 🐍 Python client (
newsdataapi) on GitHub — https://github.com/newsdataapi/python-client - 📦
newsdataapion PyPI — https://pypi.org/project/newsdataapi/ - 📰 Article response object reference — https://newsdata.io/blog/news-api-response-object/
- 🔑 Sign up for a free API key — https://newsdata.io/register
- 📊 Your dashboard — https://newsdata.io/dashboard
This repository is for educational/demo purposes and is not an official
newsdata.io product. The newsdataapi SDK is MIT-licensed.