Official Node.js client for the Newsdata.io News API. It
wraps every endpoint (latest, archive, sources, crypto, market,
count, crypto/count, market/count) with client-side parameter validation,
automatic retries with exponential backoff, scroll/paginate helpers, and a
typed error hierarchy. It also covers the real-time WebSocket service end to
end with NewsDataApiWebSocket: register, list, and delete queries, and stream
the matching news as it is published.
Zero runtime dependencies — uses the built-in fetch and WebSocket
(Node 22+).
npm install newsdata-nodejs-clientimport { NewsDataApiClient, NewsdataError } from 'newsdata-nodejs-client';
const client = new NewsDataApiClient(process.env.NEWSDATA_API_KEY);
try {
const res = await client.latestApi({
q: 'bitcoin',
country: ['us', 'gb'], // string or array of strings
language: 'en',
});
for (const article of res.results) {
console.log(article.title, '-', article.link);
}
} catch (err) {
if (err instanceof NewsdataError) console.error(err.message);
}CommonJS:
const { NewsDataApiClient } = await import('newsdata-nodejs-client');| Method | Endpoint | Notes |
|---|---|---|
latestApi(params) |
/1/latest |
Real-time news |
archiveApi(params) |
/1/archive |
Historical news |
sourcesApi(params) |
/1/sources |
Available sources (single page) |
cryptoApi(params) |
/1/crypto |
Cryptocurrency news |
marketApi(params) |
/1/market |
Market / financial news |
countApi(params) |
/1/count |
Aggregate counts (requires from_date, to_date) |
cryptoCountApi(params) |
/1/crypto/count |
Aggregate crypto counts (requires dates) |
marketCountApi(params) |
/1/market/count |
Aggregate market counts (requires dates) |
websocketRegister(params) |
/1/websocket/register |
Register a real-time query |
websocketFetch() |
/1/websocket/fetch |
List registered queries |
websocketDelete(id) |
/1/websocket/delete |
Delete a registered query |
Each params value may be a single value or an array (arrays are sent
comma-separated). Parameter names are case-insensitive. See the
Newsdata.io documentation — or the
OpenAPI 3.1 spec — for the full
parameter reference per endpoint.
Endpoint methods return a Promise by default. Two opt-in modes:
// scroll: follow nextPage cursors, resolve to one merged response.
const merged = await client.latestApi({ q: 'news', scroll: true, maxResult: 200 });
// paginate: async generator, one response per page.
for await (const page of client.latestApi({ q: 'news', paginate: true, maxPages: 5 })) {
process(page.results);
}scroll and paginate are mutually exclusive. With paginate: true the method
returns an AsyncGenerator; otherwise it returns a Promise.
await client.latestApi({ rawQuery: 'q=bitcoin&country=us&language=en' });rawQuery is mutually exclusive with all other parameters and is validated
against the endpoint's allowed keys.
Register a query first — the returned registration_id identifies it from then on:
import { NewsDataApiClient, NewsDataApiWebSocket } from 'newsdata-nodejs-client';
const client = new NewsDataApiClient('YOUR_API_KEY');
const ws = new NewsDataApiWebSocket(client);
const { results } = await ws.websocketRegister({ q: 'bitcoin', language: 'en' });
const registrationId = results.registration_id;websocketRegister takes the familiar filter parameters (q, country,
language, domain, …) — no date or paging filters, since a registered query
matches news as it is published. Registering an identical query twice rejects
with a NewsdataApiError whose statusCode is 409; the existing id is at
err.responseBody.results.registration_id. websocketFetch() lists every
registered query and websocketDelete(id) removes one.
Then stream — each response has the familiar status / totalResults /
results shape:
for await (const response of ws.stream(registrationId)) {
for (const article of response.results) {
console.log(article.title, '-', article.link);
}
}Break out of the loop to stop; the connection closes either way. ws.close()
ends an in-flight stream from outside the loop.
Transient drops (network errors, server restarts, abnormal closes) are
reconnected automatically with a capped exponential backoff. Pass
reconnect: false to stop on the first disconnect instead. A permanent
rejection — bad API key or unknown
registration_id, exhausted API credits, or too many simultaneous devices — throws
NewsdataWebSocketAuthError and is not retried.
The server always accepts the handshake and then closes with code 1008 when
the connection is refused, carrying one of three reasons: invalid credentials or registration not found, api limit reached, or device limit reached (more
than 5 devices on one registration_id). Every other close code — including
1013 (send timeout, meaning the client read too slowly) — is transient and
reconnects.
Each delivered article consumes 1 API credit per connected device.
Catch it like any other client error:
import {
NewsdataWebSocketAuthError,
NewsdataWebSocketError,
} from 'newsdata-nodejs-client';
try {
for await (const response of ws.stream(registrationId)) {
// ...
}
} catch (err) {
if (err instanceof NewsdataWebSocketAuthError) console.error('rejected:', err.message);
else if (err instanceof NewsdataWebSocketError) console.error('stream error:', err.message);
else throw err;
}All connection options are optional:
const ws = new NewsDataApiWebSocket(client, {
baseUrl: 'wss://ws.newsdata.io/ws/event', // staging / self-hosted / proxied
reconnect: true, // auto-reconnect on transient drops; default true
reconnectDelay: 1000, // ms before the first reconnect (doubles each retry)
reconnectDelayMax: 30000, // cap on the reconnect delay
openTimeout: 10000, // ms to wait for the opening handshake
WebSocket: undefined, // override the implementation (default: global WebSocket)
});Node 22+. Streaming uses the global
WebSocket, which Node ships from v22. On older runtimes pass your own implementation, e.g.new NewsDataApiWebSocket(client, { WebSocket: require('ws') }).Node's global
WebSocketdoes not expose the handshake HTTP status. When a connection fails before it opens, the client probes the same URL over HTTP to tell a permanent rejection (401 / 403) from a transient failure.
Runnable example: examples/websocket.js.
Before any request is sent, parameters are validated and normalized. A
NewsdataValidationError is thrown (without spending API quota) when:
- a parameter is not accepted by that endpoint;
- mutually-exclusive parameters are set together —
q/qInTitle/qInMeta,country/excludecountry,category/excludecategory,language/excludelanguage,domain/domainurl/excludedomain; sizeis outside 1–50;sentiment_scoreis set withoutsentiment;- a count endpoint is missing
from_dateorto_date.
Booleans (full_content, image, video, removeduplicate) are coerced to
1 / 0.
import {
NewsdataValidationError,
NewsdataAuthError,
NewsdataRateLimitError,
NewsdataApiError,
NewsdataNetworkError,
} from 'newsdata-nodejs-client';
try {
await client.latestApi({ q: 'news' });
} catch (err) {
if (err instanceof NewsdataValidationError) {/* err.param */}
else if (err instanceof NewsdataAuthError) {/* 401 / 403 */}
else if (err instanceof NewsdataRateLimitError) {/* err.retryAfter */}
else if (err instanceof NewsdataApiError) {/* err.statusCode, err.responseBody */}
else if (err instanceof NewsdataNetworkError) {/* err.cause */}
}Hierarchy:
NewsdataError (catch-all base)
├── NewsdataValidationError (.param)
├── NewsdataApiError (.statusCode, .responseBody)
│ ├── NewsdataAuthError (401 / 403)
│ ├── NewsdataRateLimitError (429; .retryAfter)
│ └── NewsdataServerError (5xx)
├── NewsdataNetworkError (.cause)
└── NewsdataWebSocketError (real-time stream)
└── NewsdataWebSocketAuthError (policy-violation close 1008)
const client = new NewsDataApiClient(apiKey, {
timeout: 30_000, // per-request, ms
maxRetries: 5, // total attempts (1 = no retry)
retryBackoff: 2_000, // base backoff, ms (exponential)
retryBackoffMax: 60_000, // cap on a single backoff, ms
paginationDelay: 1_000, // delay between pages, ms
maxResult: null, // default cap for scroll mode
maxPages: null, // default cap for paginate mode
includeHeaders: false, // attach responseHeaders to results
baseUrl: undefined, // override for staging/proxy
fetch: undefined, // inject a custom fetch
logger: console, // optional { debug, info, warn }; API key is redacted
});Retries cover network errors, HTTP 429, and 5xx. 429 honors the Retry-After
header (integer seconds or HTTP-date); otherwise backoff is exponential. Auth
and other 4xx errors are never retried.
npm test # node --test, runs offline (no API key required)Official Newsdata.io clients across languages and runtimes:
- Python — newsdataapi/python-client (PyPI)
- React (hooks) — newsdataapi/newsdata-reactjs-client (npm)
- PHP — newsdataapi/php-client (Packagist)
- Java — newsdataapi/newsdata-java-sdk (Maven Central)
- .NET — newsdataapi/newsdata-dotnet-sdk (NuGet)
- Go — newsdataapi/newsdata-go-client (pkg.go.dev)
- Dart / Flutter — newsdataapi/newsdata-flutter-client (pub.dev)
- MCP Server (AI assistants) — newsdataapi/newsdata.io-mcp (PyPI)
Also see free news datasets for ML / NLP work.
