Node.js and TypeScript SDK for the Featurable API.
Fetch your Featurable widgets and their Google reviews from any Node.js or TypeScript application. Written in TypeScript with full type definitions, zero runtime dependencies, and both ESM and CommonJS builds.
- Node.js 18 or newer (uses the built-in
fetch)
pnpm add featurable
# or
npm install featurable
# or
yarn add featurableCreate an API key in your Featurable developer settings
and provide it to the client, either directly or via the FEATURABLE_API_KEY
environment variable.
import { Featurable } from 'featurable';
const client = new Featurable({
apiKey: process.env.FEATURABLE_API_KEY,
});
const widget = await client.widgets.retrieve('your-widget-uuid');
console.log(
`${widget.gbpLocationSummary.rating}★ from ${widget.gbpLocationSummary.reviewsCount} reviews`,
);
for (const review of widget.reviews) {
console.log(`${review.author.name}: ${review.rating.value}/${review.rating.max}`);
console.log(review.text);
}CommonJS is supported too:
const { Featurable } = require('featurable');const client = new Featurable({
apiKey: '...', // defaults to process.env.FEATURABLE_API_KEY
baseURL: 'https://featurable.com/api/v2', // override the API base URL
timeout: 60_000, // per-request timeout in ms (0 disables)
maxRetries: 2, // retries for transient failures
defaultHeaders: {}, // headers added to every request
fetch: globalThis.fetch, // custom fetch implementation
});Every resource method accepts optional overrides:
const controller = new AbortController();
const widget = await client.widgets.retrieve('your-widget-uuid', {
timeout: 10_000,
maxRetries: 0,
signal: controller.signal,
headers: { 'X-Trace-Id': 'abc123' },
});All errors extend FeaturableError. HTTP errors are APIError instances with a
status code, and are further specialized so you can branch on the failure:
import {
Featurable,
APIError,
NotFoundError,
RateLimitError,
AuthenticationError,
} from 'featurable';
try {
await client.widgets.retrieve('missing');
} catch (error) {
if (error instanceof NotFoundError) {
// 404 — the widget does not exist
} else if (error instanceof RateLimitError) {
// 429 — retry later
} else if (error instanceof AuthenticationError) {
// 401 — check your API key
} else if (error instanceof APIError) {
console.error(error.status, error.requestId, error.body);
} else {
throw error;
}
}| Error | When |
|---|---|
BadRequestError |
HTTP 400 |
AuthenticationError |
HTTP 401 |
PermissionDeniedError |
HTTP 403 |
NotFoundError |
HTTP 404 |
ConflictError |
HTTP 409 |
RateLimitError |
HTTP 429 |
InternalServerError |
HTTP 5xx |
APITimeoutError |
Request exceeded the timeout |
APIConnectionError |
Network failure / request aborted |
By default the client retries up to maxRetries (2) times on network errors and
408, 409, 429, and 5xx responses, using exponential backoff with jitter.
When the API returns a Retry-After header, it is honored.
Retrieve a widget and its reviews by UUID. Returns a Widget.
See CONTRIBUTING.md.