Skip to content

Quickstart · Node.js

Updated: September 7, 2026

Target: a Node service serving translated strings, in under ten minutes. Read the first section before writing code — the client does less than its name suggests, and knowing that up front saves an hour.

What the client does

azbox-node exposes exactly one class with one method:

new AzboxClient({ token, projectId, language })
await client.getKeywords({ afterUpdatedAt? })

Three consequences:

  • It only reads. Keywords are created in the panel; there is no upload method.
  • One language per client. For several languages, one client each.
  • No translate() helper. You get the list and build the lookup yourself. That is steps 4 and 5 below.

The credential is token, not apiKey. Passing apiKey throws AzboxClient: 'token' is required.

Before you start

  • Node 18 or newer — the client uses the global fetch
  • An AZbox project with its Project ID and API key

1 · Create the project and import your strings

In the dashboard: Create Project, then import your en.json (i18next format is read natively, nested keys included) or add keywords with Add Keyword.

2 · Install

npm install azbox-node

3 · Fetch

import { AzboxClient } from "azbox-node";

const client = new AzboxClient({
  token: process.env.AZBOX_API_KEY,
  projectId: process.env.AZBOX_PROJECT_ID,
  language: "ES",
});

const keywords = await client.getKeywords();
// [{ id: "home.title", data: { translation: "Bienvenido", ... } }]

One call to GET /v1/projects/:id/keywords?token=…&language=….

4 · Build the lookup

Calling getKeywords() per string would be one HTTP request per string. Fetch once at startup:

const dictionaries = new Map<string, Map<string, string>>();

export async function loadLanguage(language: string) {
  const client = new AzboxClient({
    token: process.env.AZBOX_API_KEY!,
    projectId: process.env.AZBOX_PROJECT_ID!,
    language,
  });
  const keywords = await client.getKeywords();
  dictionaries.set(language, new Map(
    keywords
      .filter((k) => typeof k.data.translation === "string")
      .map((k) => [k.id, k.data.translation as string]),
  ));
}

export function t(language: string, key: string, params?: Record<string, string | number>) {
  const value = dictionaries.get(language)?.get(key);
  if (value === undefined) return key;
  return params
    ? value.replace(/\{(\w+)\}/g, (m, p) => String(params[p] ?? m))
    : value;
}

Interpolation is yours: the API returns the string as stored, placeholders included.

5 · Refresh only what changed

const changed = await client.getKeywords({ afterUpdatedAt: lastSync });

This is what makes over-the-air work on the server: correct a string in the panel and the next refresh picks it up without a deploy. A failed refresh is not fatal — you still hold the previous dictionary in memory.

6 · In CI

env:
  AZBOX_API_KEY: ${{ secrets.AZBOX_API_KEY }}
  AZBOX_PROJECT_ID: ${{ secrets.AZBOX_PROJECT_ID }}

If something fails

  • 'token' is required — you passed apiKey. The option is token.
  • Empty array — the project has no keywords in that language, or the language code does not match the one configured in the project.
  • fetch is not defined — Node older than 18.

Next

Call to action background

Start Global Growth Today

Upload your language files, get them translated, and keep every locale in sync as your product keeps changing.

Get Started - It's Free