Concepts

How Clivly reaches your app

Why the sync trigger URL is an address rather than a credential, and how it resolves in development and production.

Two directions, not one

Almost everything you configure travels one way — out of your app to Clivly. Exactly one thing travels the other way, and that difference explains nearly every "is this broken?" moment during setup.

The keys authenticate you. The trigger URL is an address. They are not peers, even though they sit next to each other in the same file: one proves who is calling, the other says where to call.

That is why a blank CLIVLY_SYNC_TRIGGER_URL is not a missing credential. Nothing can guess where your app will be deployed, so pairing cannot fill it in the way it fills in keys.

Your first pnpm dev

What a first run actually looks like on a laptop, so you can tell a normal stage from a real problem.

You have scaffolded an app, wired Drizzle and your auth, run clivly login, and started the dev server. Here is what is true at that moment:

  • Dashboard shows your app live — works. The heartbeat is an outbound POST. It reaches Clivly from localhost like any other API call.
  • Schema and contacts sync — works. clivly push-schema and the SDK's row pushes are outbound too.
  • Dashboard "Run sync" does nothing — expected. Clivly would have to dial your laptop, and localhost on Clivly's servers means Clivly's own machine.

One button, not your whole setup. Nothing is misconfigured — the inbound leg simply has nowhere to land yet.

Local development: clivly dev

The fix for local development is a command, not an environment variable.

Package manager
terminal
npx clivly dev

This opens a cloudflared tunnel, builds <public origin>/api/clivly/tick, and registers it with Clivly as an override. You will see:

Terminal
$ npx clivly dev

Tunnel: https://quiet-fox-42.trycloudflare.com/api/clivly/tick
Dashboard-triggered sync now points at this local session.

Leave the variable blank in development

The override outranks whatever is in .env, so there is nothing to edit. On a clean exit (Ctrl-C) the override is removed again.

Development, deployed, pinned

The same variable across the three situations you will actually meet.

clivly login writes a visible template rather than an empty line, so the shape is obvious when you come to fill it in:

.env
# Public URL of your tick route — replace <yourDomain.com> once deployed.
# Local dev: run `clivly dev` instead.
CLIVLY_SYNC_TRIGGER_URL=https://<yourDomain.com>/api/clivly/tick

The angle brackets are load-bearing. While they are there the SDK treats the line as unset, so an unedited placeholder never becomes a real — and broken — address.

Production: usually automatic

On most platforms you never set the URL by hand.

clivly init writes syncTrigger.path into your config. Combined with the origin your host already publishes, the SDK reports its own public URL on the first heartbeat after deploy — no edit required on Vercel, Cloudflare Pages, Railway, Render or Fly.

clivly.config.ts
syncTrigger: {
// `path` lets the SDK build its own public URL from the hosting platform's
// environment, so on those platforms you never set the URL by hand.
path: "/api/clivly/tick",
url: process.env.CLIVLY_SYNC_TRIGGER_URL,
secret: process.env.CLIVLY_SYNC_TRIGGER_SECRET,
},

Set CLIVLY_SYNC_TRIGGER_URL explicitly when you are behind a custom domain the platform does not advertise, on a host with no origin variable, or when you simply want it pinned.

Resolution order

Which address wins, in the order the SDK decides it.

A stale tunnel override

The one failure mode worth recognising on sight.

The override registered by clivly dev outranks your production URL and is scoped to the workspace, not the environment. If clivly dev dies without a clean shutdown — a crash, a hard kill, a laptop sleeping — the dead trycloudflare.com address stays registered.

Your deployed app then has a perfectly correct CLIVLY_SYNC_TRIGGER_URL that is being ignored in favour of a tunnel that no longer exists, and nothing in your .env hints at it.

If Run sync fails in production and the env var looks right

Check for a stale override first — Integrations → Remote sync in the dashboard. Clearing it restores the reported URL.

Reading clivly status

What each stage means when the ladder prints.

Terminal
Sync trigger URL
! Still the placeholder (https://<yourDomain.com>/api/clivly/tick)
  — remote sync cannot call back into this app.
  Replace <yourDomain.com> with your deployed origin, or delete the
  line. For local development run `clivly dev`.

A warning here is not a failure. Push-only deployments — where your app decides when to sync and nothing needs to call in — can leave this unset permanently.