Better I18NBetter I18N

Quick Start

Get Better i18n Content running in your app in under 5 minutes

Better i18n Content lets you ship localized content — blog posts, marketing pages, FAQs, anything structured — from a single source of truth to every framework you use, with view analytics out of the box.

What you get

  • Content models — Define your shape once (fields, types, relations). Use it everywhere.
  • Localized entries — Each entry stores per-language translations alongside source values.
  • REST delivery — Public CDN-backed API at content.better-i18n.com. Cache-Control + KV-backed responses.
  • View analytics@better-i18n/content SDK tracks content.view events with framework adapters for Next.js, React, Expo, Svelte, Vue, and vanilla JS.
Dashboard (define models + entries)


Content API (content.better-i18n.com)
   │              │
   │              └─►  POST /v1/track ──► CF Analytics Engine
   ▼                                         │
GET /v1/content/...                          ▼
   │                                   Dashboard charts
   ▼                                   (views, languages, top entries)
Your app (Next.js, React, Expo, ...)

Reads are cached at the edge (KV, 60s TTL). Writes from the SDK are fire-and-forget — sendBeacon first, fetch keepalive fallback. Never blocks page renders.

Install

npm install @better-i18n/sdk
bun add @better-i18n/sdk
pnpm add @better-i18n/sdk
yarn add @better-i18n/sdk

Add your first model

Get your API Key

  1. Go to dash.better-i18n.com
  2. Navigate to SettingsAPI Keys
  3. Select Content as the type
  4. Create and copy your API key

Keep your API key secret. Never commit it to version control. Use environment variables instead.

Create a client

lib/content.ts
import { createClient } from "@better-i18n/sdk";

export const content = createClient({
  projectId: "your-org/your-project",
  apiKey: process.env.BETTER_I18N_API_KEY!,
});

Find your project ID in Settings → General → Project ID, or read it off the dashboard URL: dash.better-i18n.com/{org}/{project}.

Fetch content

import { content } from "./lib/content";

// List all content models
const models = await content.getModels();

// List published entries (chainable API)
const { data: posts, total } = await content
  .from("blog-posts")
  .eq("status", "published")
  .limit(10);

// Get a single entry in French
const { data: post } = await content
  .from("blog-posts")
  .language("fr")
  .single("hello-world");

console.log(post.title, post.body);

Track views

Install the analytics SDK and call useTrackView() on your content pages. See Analytics.

Environment variables

.env
BETTER_I18N_API_KEY=bi_your-api-key
BETTER_I18N_PROJECT=acme/web-app
VariableRequiredDescription
BETTER_I18N_API_KEYYesYour API key from the dashboard
BETTER_I18N_PROJECTYesProject identifier in org/project format

Configuration options

OptionTypeRequiredDefaultDescription
projectIdstringYesProject ID — accepts org/project slug or canonical UUID. Find both in dashboard Settings → General → Project ID.
apiKeystringYesAPI key for authentication
apiBasestringNohttps://content.better-i18n.comCustom API base URL
debugbooleanNofalseLog request URLs and responses to console

UUID vs slug — passing the project UUID instead of the slug makes your CDN URLs immune to dashboard slug renames. Recommended for production deployments where the slug might evolve. The UUID is shown in dashboard Settings → General → Project ID.

project is still accepted as a legacy alias for projectId — existing integrations keep working. New code should use projectId for consistency with the Analytics SDK and dashboard.

Debugging

Enable debug mode to see exactly what the SDK is doing:

const client = createClient({
  projectId: "acme/web-app",
  apiKey: process.env.BETTER_I18N_API_KEY!,
  debug: true,
});

This logs all requests and responses to the console:

[better-i18n] Client initialized { apiBase: "https://content.better-i18n.com", org: "acme", project: "web-app" }
[better-i18n] → getEntries(blog-posts) https://content.better-i18n.com/v1/content/acme/web-app/models/blog-posts/entries?status=published
[better-i18n] ← 200 OK

Next steps

  • Models & Entries — define schema in dashboard + query with chainable from() API
  • REST API — raw HTTP for any framework
  • Analytics — track which content gets viewed

On this page