Frameworks
TanStack Start
Mount the Clivly tick route as a TanStack Start file route.
The docs work better when framework-specific scaffolding is on its own route instead of being buried in one huge page.
clivly.createClivlyHandler()
clivly.config.ts
Next.js
app/api/clivly/tick/route.tsTanStack Start
src/routes/api/clivly/tick.tsSvelteKit
src/routes/api/clivly/tick/+server.tsRemix
app/routes/api.clivly.tick.tsNuxt
server/api/clivly/tick.ts/api/clivly/tick
what Clivly calls
This is why `syncTrigger.path` is a single constant rather than a per-framework setting.
Every framework wraps the same createClivlyHandler(), and every route resolves to the same public URL: /api/clivly/tick. In TanStack Start, clivly init scaffolds file routes at src/routes/api/clivly/tick.ts, plus clivly/vite during dev.
TanStack Start uses file routes from @tanstack/react-router plus clivly/vite for the long-lived dev flow. This example matches the current scaffolded route shape and SDK guidance.
TanStack Start
import { createFileRoute } from "@tanstack/react-router";
import clivly from "../../../../clivly.config";
const handler = clivly.createClivlyHandler();
export const Route = createFileRoute("/api/clivly/tick")({
server: {
handlers: {
POST: ({ request }) => handler(request),
},
},
});Starting the SDK
TanStack Start boots from files your app already owns, so there is no separate
boot hook to scaffold — the plugin is what calls start(). clivly init adds
it to your Vite config when it can, and prints the lines when it cannot.
Without it your app runs and serves traffic but never checks in, so the dashboard sits on "No schema discovered yet" indefinitely.
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import { clivlyVite } from "clivly/vite";
import { defineConfig } from "vite";
import clivly from "./clivly.config";
export default defineConfig({
plugins: [tanstackStart(), clivlyVite(clivly)],
// Vite rejects unrecognised Host headers, so `clivly dev`'s tunnel is
// refused with 403 before it reaches the tick route. Only needed for
// tunnelled local development.
server: { allowedHosts: [".trycloudflare.com"] },
});When the app 500s before Clivly is involved
Two TanStack Start problems produce a total SSR failure — every request,
including your home page, returns 500. Both look like Clivly failures from the
dashboard, because a dead app cannot answer a sync trigger either.
Check GET / first. If your own home page 500s, the fault is not in Clivly's
route — no amount of rotating secrets or re-testing the trigger will help.
The router entry must export getRouter
start-server-core looks up entries.routerEntry.getRouter(), and the
generated routeTree.gen.ts imports that name too. An older scaffold exported
createRouter, which fails on every request with:
TypeError: entries.routerEntry.getRouter is not a function
import { createRouter as createTanStackRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen";
// The export MUST be named getRouter.
export function getRouter() {
return createTanStackRouter({ routeTree, scrollRestoration: true });
}
declare module "@tanstack/react-router" {
interface Register {
router: ReturnType<typeof getRouter>;
}
}Keep react-start and react-router in step
They publish on independent cadences, so a caret range on both can resolve to an
incompatible pair — in one case 39 minor versions apart from the same
^1.95.0. The symptom is an SSR crash naming an API one half does not have:
TypeError: serverSsr.reserveStreamFastPath is not a function
Pin them to versions that ship together. @tanstack/react-start declares the
@tanstack/react-router version it expects in its own dependencies — matching
that is the reliable check.
Neither of these is a Clivly failure
They are recorded here because the dashboard is usually where they are noticed:
a broken app cannot answer a sync trigger, so the first visible symptom is a
failed sync. GET / distinguishes them in one request.