Skip to content

Run it in production

What RoutingCat adds to your pages, what visitors and records go through when RoutingCat can’t be reached, how routed pages work with caches and a Content Security Policy, and how to upgrade, pause or remove RoutingCat.

Plan for its cost on each page

  • RoutingCat picks a visitor’s variants before the page is served, in your root middleware.ts on Vercel or in the Worker in front of Nuxt’s on Cloudflare. It decides locally, from routing data it refreshes in the background, with no call to RoutingCat on the page’s path.
  • On Vercel, the middleware runs on every page request, as Routing Middleware, on Node.js, before Vercel’s cache, so on its cache hits too. RoutingCat’s matcher entries leave out Nuxt’s assets, _ipx images, API routes under /api and any path with a file extension, payloads included. Vercel bills its runs to your account, and each run adds Vercel’s own time to the page, which depends on the region.
  • On Cloudflare, the Worker runs first on every request but those for Nuxt’s built assets, under /_nuxt/, and on Pages, for your site’s other static files, which Pages’ _routes.json leaves out. It decides your pages, answers /_rc, and passes everything else to Nuxt untouched. In RoutingCat’s tests, it added 2 to 5 ms of CPU on average to a routed page, which Cloudflare bills to your account with the Worker’s requests: see Cloudflare.
  • In-page navigations ask for the next page’s variants. When a visitor follows a link to a routed page, RoutingCat’s module asks your site’s /_rc path for that page’s variants, beside Nuxt’s own payload fetch, and the page renders with them. In RoutingCat’s tests on Vercel, that call took 55 to 59 ms at the median, against 40 to 42 ms for the payload. The navigation waits for it at most a second, then shows that page’s defaults.
  • Every variant is in the page. Each hidden variant adds its markup to the page’s HTML, and the head snippet, early in every page’s <head>, is a 1,244-byte inline script. Build a page says how to keep hidden variants’ images from loading.
  • Some browsers can’t show a selection: Safari before 16.4, Chrome before 105 and Firefox before 121. Their visitors see your defaults, and their visits stay out of results.
  • Nothing RoutingCat sends delays a response. The middleware or Worker sends its records after the response, your server’s routingcat.track and routingcat.identify send within the request’s lifetime without holding the response, and the browser posts its reports without waiting for an answer.

Expect changes within about 2 minutes

  • Deploys and acts reach visitors within about 2 minutes on the server instances that serve traffic, Vercel’s or Cloudflare’s. An instance idle for longer serves its next request with the routing data it had, then refreshes, so on a quiet site a paused variant can show once more.
  • A page’s first production deploy serves the page’s defaults for those 2 minutes on Vercel, recording arrivals but no decisions. On Cloudflare, the build waits up to a minute for routing data that holds its own changes, so that the Worker routes the page from its first request; when the wait runs out, the build log says so, and the page routes within about 2 minutes.
  • On Vercel, right after a deploy that adds a page, a slot or a variant, a new server instance can hold its first routed requests for up to a second, while it fetches routing data that knows them.

Know what happens when RoutingCat is unreachable

Visitors always get a page.

What can’t reach RoutingCat Pages Records
A running deployment, for routing data Routing continues with the routing data each server instance last had; a new instance starts from the copy its build embedded. Acts and new learning reach visitors once RoutingCat is back. Unaffected, unless ingestion is down too
A running deployment, for ingestion Unaffected The middleware’s or Worker’s records and your server’s events are retried once, then lost, and so are the browser’s reports. A backend calling the events API gets an error, and can retry safely, since each event carries its id.
A build The build ships as usual, with one line in its log, and its deployment shows your defaults. That deployment records nothing until a deploy that reaches RoutingCat.
The command It exits with code 4: run it again later.

A deployment whose build registered nothing records no visits and no conversions, from your server or from the browser. After each deploy, look for RoutingCat’s line in the build log, or run npx routingcat doctor, and redeploy if the build didn’t register.

Keep caches from hiding decisions

  • Your routed pages can be cached as usual. Every visitor gets the same HTML, every variant in it, and the middleware or Worker runs before the cache, adding each visitor’s own variants and cookies to the response. So Nuxt’s prerendered pages, and its route rules that cache pages or regenerate them, keep working on routed pages.
  • Never cache routed pages’ HTML in front of RoutingCat. A CDN in front of Vercel, or a cache rule in front of the Worker, that serves your HTML from its own cache skips RoutingCat: every visitor gets the cached copy’s variants, and nothing is recorded. status then warns that render beacons outnumber decisions, and doctor names the cache. Caching assets there is fine.
  • Keep Server-Timing on your pages. RoutingCat hands each visitor’s variants to the page in that response header, so a header rule or a proxy that removes it shows the visitor your defaults.
  • Cloudflare in front of Vercel works, since Cloudflare doesn’t cache HTML unless told to. Turn on its visitor-location headers: in Cloudflare, your domain → Rules → Settings → Managed Transforms → “Add visitor location headers”. Without them, visitors’ local times come from Cloudflare’s edge or from their country, and doctor and status say so. Behind Cloudflare, visits also reach more of Vercel’s regions, so more of them meet a new server instance after a deploy.
  • On Cloudflare Workers or Pages, Workers Cache, Cache Everything and the zone’s other settings each change what RoutingCat’s Worker sees: Cloudflare says how to set each.

Let your Content Security Policy run RoutingCat

A site without a Content Security Policy needs nothing here. With one, the policy must allow:

  • the head snippet, an inline script: by the page’s nonce on its tag, or by its hash in script-src;
  • the style rules it writes, by the same nonce, or with 'unsafe-inline' in style-src. A policy that allows inline styles only by hash blocks them, and visitors see your defaults;
  • each slot’s own style="display:contents", where the policy restricts style attributes: with 'unsafe-hashes' and its hash in style-src-attr, or slots render as boxes;
  • your own site’s /_rc path in connect-src, which 'self' covers.

doctor’s policy line checks each on your production pages, and names the source to add.

Upgrade

  1. Upgrade the routingcat package with your package manager. It carries the command, the SDK, the Nuxt module and the agent skill, so they stay level.
  2. Run npx routingcat init. It brings the skill level with the package, unless the skill was edited here, which it keeps; doctor reports a skill older than the package. It also brings the note in AGENTS.md up to date, if you have it.
  3. Deploy. Visitors get the new version only with your deploy, and builds install the version in your lockfile.

Learning, settings and acts never need an upgrade: they reach the version you deployed within about 2 minutes.

Pause or remove RoutingCat

  • Turn routing off for the whole site with npx routingcat set routing=off. Every page shows its defaults, and visits and conversions are still recorded. npx routingcat set routing=on resumes from what routing had learned. See Routing settings.
  • Remove it from your code in one change, then deploy:
    • in each routed page, each <RoutingCatSlot>, replaced by its default variant’s content, and each useRoutingCat;
    • the routingcat/ folder, the routingcat.track, routingcat.identify and routingcat.link calls in your server code and your pages, and routingcatProperties in your PostHog init;
    • routingcat/nuxt in nuxt.config’s modules, with its routingcat options if you set any;
    • on Vercel, RoutingCat’s part of middleware.ts, or the whole file if init wrote it;
    • on Workers, worker.ts, with your Wrangler configuration’s main pointing at Nitro’s Worker again, .output/server/index.mjs, and RoutingCat’s run_worker_first and version metadata binding taken out;
    • .routingcat/ in .gitignore, routingcat.config.ts, the skill’s folders, .agents/skills/routingcat/ and .claude/skills/routingcat/, and the package;
    • the note for coding agents in AGENTS.md and CLAUDE.md, from <!-- routingcat --> to <!-- /routingcat -->, and AGENTS.md itself if the note is all it holds.
  • Archive the site. Archiving revokes the site’s keys and its binding to your Vercel or Cloudflare project, stops collection, and deletes the site’s records within 90 days, unless you ask otherwise. The site’s owner asks RoutingCat to archive it. To have the records deleted sooner, ask for their deletion.

Next