Getting Started
Quickstart
Prerequisites, account setup, the runtime entry point, and verification — the whole path in order.
Prerequisites
Clivly embeds into an app you already have. It does not create one, and it never creates tables in your database.
- Node.js 22 or newer. Every published package declares
engines.node: ">=22". - An existing app. Route scaffolding covers Next.js, TanStack Start, SvelteKit, Remix and Nuxt; anywhere else you mount one fetch handler by hand.
- Drizzle ORM — only required for
clivly initto generate a config. Prisma, Kysely and raw SQL are fully supported through a hand-writtenfetchPagesource. - A backend. Clivly Cloud posts to a route your app owns; a static-only site has nowhere to mount it.
- npm, pnpm, yarn and bun all work. Examples use npm.
The five-minute path
The shortest working path, start to finish. Every step below expands on one of these five.
npm install clivly
One dependency — it carries the CLI and the SDK.
npx clivly init
Scaffolds clivly.config.ts, the routes, and .env.
npx clivly login
Pairs this machine and writes your credentials.
Start your app
This is what connects it. Nothing before this reaches Clivly.
npx clivly status
Says which rung you are on and what to do next.
Steps 1–3 prepare files and credentials. Step 4 is the one that makes your app appear in Clivly.
# 1. Create your account + organization at https://clivly.com/sign-up
# 2. In your app's directory:
npm install clivly
# 3. Scaffold clivly.config.ts, the routes, the boot hook, and .env —
# then pair this machine.
npx clivly init
# 4. If you skipped pairing (--no-login), or need to re-pair:
npx clivly login
# 5. Start your app. That is what connects it.
npm run devclivly initwrites four files:clivly.config.ts(yours to edit), the tick route, the auth-verify route, and the boot hook for your framework. Plus env placeholders.- It creates no database tables and does not modify your ORM schema.
- Then start your app the way you normally do. The boot hook checks in for you, so the dashboard shows the app as Live within seconds — no command needed.
npx clivly statusis a read-only diagnostic for when something looks wrong. It is not part of connecting.
Create your account and organization
Sign up, create the organization, and collect the two keys before you touch any code.
- Sign up at clivly.com/sign-up. The onboarding flow creates your organization — the tenant every key, mapping and widget belongs to.
- Open the Connect app dialog from the dashboard or the ⌘K palette. It shows your framework's install command and an
.envsnippet with both keys already filled in. - The secret key is shown once. Regenerating it revokes the previous key, so redeploy after rotating.
npx clivly logindoes this for you: it pairs the machine over a browser approval and writes the credentials into your framework's env file.
Define the SDK once
Constructing the SDK is pure. Nothing connects until you call an entry point.
createClivlySDK({ … })
clivly.config.ts
start()
Long-lived Node host. Heartbeats and syncs on a schedule.
runScheduled()
Serverless or cron. One pass, then exit.
createClivlyHandler()
Your tick route. Lets Clivly ask for a sync.
connect()
Checks credentials and reachability. Changes nothing.
A config that imports cleanly but calls no entry point is silent by design — not broken.
import { createClivlySDK, defineClivlyConfig } from "clivly/sdk";
import { discoverFromDrizzle, fromDrizzle } from "clivly/drizzle";
import { db, participants, accounts } from "./db";
import * as schema from "./db/schema";
const entities = defineClivlyConfig({
entities: {
participants: {
concept: "contact",
source: "participants",
fields: { name: "full_name", email: "email" },
},
accounts: {
concept: "company",
source: "accounts",
fields: { name: "legal_name", domain: "website" },
},
},
});
export default createClivlySDK({
apiKey: process.env.CLIVLY_SECRET_KEY ?? process.env.CLIVLY_API_KEY!,
entities,
schema: discoverFromDrizzle(schema),
source: {
contacts: fromDrizzle(db, participants, {
entity: "participants",
cursorField: "updatedAt",
}),
companies: fromDrizzle(db, accounts, {
entity: "accounts",
cursorField: "updatedAt",
}),
},
syncTrigger: {
path: "/api/clivly/tick",
url: process.env.CLIVLY_SYNC_TRIGGER_URL,
secret: process.env.CLIVLY_SYNC_TRIGGER_SECRET,
},
// Long-lived Node hosts only. The HTTP heartbeat resumes automatically
// while a socket is connecting or reconnecting.
presence: { transport: "websocket" },
});sourceis keyed by CRM concept —contacts/companies/deals/custom. The entity's ownsource:field is a host table name. Conflating them means an entity resolves to no source and silently syncs nothing.cursorFieldandidFieldare Drizzle property keys (updatedAt), not database column names (updated_at).- A bare
import "./clivly.config"will never connect — the factory is pure by design, so the SDK stays tree-shakeable. - After editing this file, restart your app. It reads the config once, at boot.
Choose the runtime entry point
The right call depends on whether the host is long-lived, request-scoped, or just validating credentials.
const status = await clivly.connect();
if (!status.ok) throw new Error(status.reason);
await clivly.start(); // long-lived Node / Vite dev only
await clivly.runScheduled(); // one-shot cron/serverless run
export const POST = (request: Request) =>
clivly.createClivlyHandler()(request);connect()is the one-shot health check and returns structured status.start()is for long-lived Node processes and Vite dev only. Withpresence.transport: "websocket", it uses a WebSocket for liveness once the server confirms it is ready.- WebSocket presence is opt-in today. While it connects or reconnects, the existing HTTP heartbeat cadence stays active automatically; sync keeps its own cadence.
runScheduled()andcreateClivlyHandler()are the production path for serverless and edge runtimes.- Getting this wrong is the most common integration failure: on serverless,
start()'ssetIntervalstops ticking after the first response.
Verify
One command tells you which step of the setup you are on, and what to do about it.
npx clivly status
npx clivly status --verbose
npx clivly status --config ./apps/web/clivly.config.ts- The ladder: credential → Clivly reachable → config loads → config is edge-safe → setup checks → sync trigger URL.
- Read-only. It writes nothing.
- A working integration shows every step green,
clivly: connected to <your org>on dev boot, and recent presence on the Integrations page. A connected WebSocket deployment reports its own transport and state.