@brandfine/client
v0.8.0
Published
Brandfine consumer SDK — typed HTTP client, server-side caches, locale + navigation resolvers, and webhook helpers for landing-page integrations.
Readme
@brandfine/client
Typed HTTP client, server-side caches, locale + navigation resolvers, webhook helpers, and analytics tracker installer for landing pages consuming the Brandfine CMS.
Status: early development (
0.x.y). API may change in minor bumps before1.0.
Install
npm install @brandfine/clientAvailable on public npm with provenance — installs are verified against this repo's CI runs.
Subpath exports
import {
createBrandfineClient,
type AnalyticsConfig,
type AnalyticsInstallResult,
} from '@brandfine/client'
import { createCache, createKeyedCache } from '@brandfine/client/cache'
import { resolveNavigation, localizePath } from '@brandfine/client/resolvers'
import {
verifyWebhookSecret,
parseWebhookPayload,
} from '@brandfine/client/webhook'Pick the import path that scopes to what you actually use — tree-shaking does the rest, but subpath imports keep consumer bundle analysis honest.
What it does
const bf = createBrandfineClient({
baseUrl: 'https://api.brandfine.co',
apiKey: process.env.BRANDFINE_API_KEY!,
})
// Content reads
await bf.posts.list({ type: 'blog', locale: 'pt' })
await bf.posts.getBySlug('uk-eta-2026')
await bf.workspace.get()
await bf.categories.list()
await bf.navigations.get('header')
// Analytics — auto-inject the Brandfine tracker into <head>
await bf.analytics.install()
// Submissions — POST a contact-form submission
await bf.submissions.create({
name: 'Alex',
email: '[email protected]',
message: 'Hello!',
})
// Appointments — for workspaces running the Appointments plugin
const { slots } = await bf.appointments.getAvailability()
await bf.appointments.createRequest({
visitorName: 'Alex',
visitorEmail: '[email protected]',
requestedAt: slots[0].start,
})The full surface lives under seven namespaces — posts, categories, workspace, navigations, analytics, submissions, appointments — plus a get(path) escape hatch.
Server-side only
The workspace API key (bfwk_*) is broad-scope — it can read posts, navigations, submissions, analytics, and write submissions + appointments. Don't put it in the browser bundle even behind a NEXT_PUBLIC_* / PUBLIC_* / VITE_* prefix.
Every recipe in our docs (SDK reference) keeps the SDK call server-side. Your frontend posts to your own backend; your backend hits Brandfine.
Static-export site without a server runtime? See Static sites for your options — add an adapter, run a tiny proxy, or wait for scoped publishable keys (bfpk_*, on the roadmap).
Analytics
bf.analytics.install() fetches this workspace's tracker config from Brandfine and injects <script defer src="…" data-website-id="…"> into document.head exactly once. Idempotent across StrictMode double-invokes, SPA route changes, and multi-instance scenarios via a marker attribute on the injected tag.
For static sites (Next.js output: 'export', Astro), use the build-time variant to keep the API key out of the browser bundle and skip the runtime round-trip:
// Server-side at build/request time:
const config = await bf.analytics.getConfig()
// Pass `config` to a client component that calls:
bf.analytics.install({ config })Full walkthrough with framework recipes: docs.brandfine.co/docs/sdk/analytics.
Caching
createCache(opts) and createKeyedCache(opts) are minimal SWR caches with TTL + background revalidation. They take any async fetcher — including bf.posts.list — and make the cached value the source of truth for hot paths. Pair with verifyWebhookSecret to invalidate on publish.
Documentation
- SDK quickstart — minimal Astro integration end-to-end.
createBrandfineClient— full options + method reference.- Analytics install — runtime vs build-time, framework recipes.
- Submissions — POST a contact-form submission.
- Appointments — booking availability + visitor requests for workspaces running the Appointments plugin (server-side only).
- Webhook handler — verify + parse + dispatch.
- REST API reference — for non-TypeScript consumers.
License
MIT
