Debugging and Logging
Debugging and Logging
The SDK has no logging by default. Everything described here is opt-in, and your API key is never logged. The key is sent only as the X-API-Key request header; the SDK never logs request headers, and the resolved url on every event and error never contains it.
debug: true
The fastest way to see what the client is doing. It logs each request and response with console.debug, and each failure with console.error.
import { createClient } from '@rankhiker/sdk';
const rh = createClient({
apiKey: process.env.RANKHIKER_API_KEY!,
debug: true,
});
await rh.listArticles({ limit: 10 });
// [rankhiker] -> GET https://rankhiker.com/api/articles/export?limit=10
// [rankhiker] <- 200 GET https://rankhiker.com/api/articles/export?limit=10 (84ms, 10 articles)
If a list call comes back empty, the response line appends a hint so you can spot misconfiguration quickly:
[rankhiker] <- 200 GET .../api/articles/export (61ms, 0 articles) [0 results: check apiKey, baseUrl, workspaceId, and that articles are published]
A common cause of 0 results is a wrong workspaceId, a www redirect dropping the key in the browser (use the default apex baseUrl, not www), or simply no published articles yet.
logger callback
Pipe structured events into your own logging or observability system. The logger fires once per request, once per successful response, and once per error.
import { createClient, type RankHikerLogEvent } from '@rankhiker/sdk';
const rh = createClient({
apiKey: process.env.RANKHIKER_API_KEY!,
logger: (event: RankHikerLogEvent) => {
myLogger.info({ msg: 'rankhiker', ...event });
},
});
The RankHikerLogEvent shape
Every emitted event has this shape:
| Field | Type | Notes | ||
|---|---|---|---|---|
type | 'request' \ | 'response' \ | 'error' | Which lifecycle moment fired. |
method | string | HTTP method, always 'GET' today. | ||
url | string | Full resolved URL including query string. Never contains the API key. | ||
endpoint | string | The request path, for example /api/articles/export. | ||
status | number (optional) | HTTP status code. Present on response and error events. | ||
durationMs | number (optional) | Wall-clock duration in milliseconds. Present on response and error events. | ||
resultCount | number (optional) | Number of articles in the response. Present for list and single-article endpoints. | ||
error | RankHikerError (optional) | The error. Present on error events only. |
If you only care about one lifecycle moment, use the typed hooks instead of branching on event.type. They receive the same RankHikerLogEvent.
const rh = createClient({
apiKey: process.env.RANKHIKER_API_KEY!,
onRequest: (e) => console.log('sending', e.method, e.url),
onResponse: (e) => console.log('got', e.status, 'in', e.durationMs, 'ms'),
onError: (e) => reportToSentry(e.error),
});
| Hook | Fires when |
|---|---|
onRequest | Just before each request is sent (event.type === 'request'). |
onResponse | After each successful 2xx response (event.type === 'response'). |
onError | When a request fails: a network error or any non-2xx (event.type === 'error'). |
logger or hook never breaks the request. Every callback is guarded, so even if your logging code throws, the SDK call still resolves and returns its data (when debug is on, the SDK logs the callback failure with console.warn).
url on errors
RankHikerError now carries the resolved url it failed against, alongside status, body, endpoint, and cause. As everywhere else, the url never contains the API key.
import { createClient, RankHikerError } from '@rankhiker/sdk';
const rh = createClient({ apiKey: process.env.RANKHIKER_API_KEY! });
try {
await rh.listArticles();
} catch (err) {
if (err instanceof RankHikerError) {
console.error(err.status, err.url, err.endpoint, err.message);
}
throw err;
}
Key safety guarantee
The API key never appears in any log line, logger event, hook payload, or error. It is transmitted only as the X-API-Key header, the request URL never contains it, and the SDK never logs request headers. You can safely forward RankHikerLogEvent objects and RankHikerError instances to a third-party logging service.
Was this article helpful?