Public DocsRoute-backed sectionsUpdated July 24, 2026

Clivly docs that match the product you ship today

Install the CLI, scaffold your routes, and connect your database to Clivly. Every step below is its own page, so you can deep-link straight to the one you need.

What Changed In This Refresh
The previous page was accurate in parts, but it no longer mirrored the current integration path closely enough.

Lead with `clivly@next`, not the older stable line.

Added `create-clivly`, `connect()`, `doctor()`, and `cursorStore` guidance.

Separated framework recipes from widget and auth setup.

Kept better-auth, remote sync, and serverless guidance current.

Getting Startedquickstart

Quickstart

Install the package, define the SDK once, and pick the correct runtime entry point before doing anything else.

`npm install clivly``connect()``start()` vs `runScheduled()`
Install
Install the package, define the SDK once, then pick the runtime entry point that matches your host.
Package manager
terminal
npm install clivly

# optional peers, only when your app uses them
npm install drizzle-orm
npm install vite
npm install @clerk/backend
npm install @workos-inc/node
Package manager
terminal
npm create clivly
  • Install the default (`latest`) tag — that is the supported line these docs describe.
  • `npm create clivly` scaffolds a fresh app and hands straight into `init`.
  • Once installed locally, plain `npx clivly …` uses the workspace copy rather than re-fetching.
  • `clivly@next` exists for prereleases. Only reach for it when you need something that has not shipped to `latest` yet.
Define the SDK once
Constructing the SDK is pure. Nothing connects until you call an entry point.
clivly.config.ts
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,
  },
});
Choose the runtime entry point
The right call depends on whether the host is long-lived, request-scoped, or just validating credentials.
runtime.ts
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.
  • `runScheduled()` and `createClivlyHandler()` are the production path for serverless and edge runtimes.
Start of the docs flow
You are at the earliest guided section.