Change, preview and deploy
Every change to what a page offers is a change to its slot markup in your templates. npx routingcat push stamps it and registers it, and your deploy serves it. This guide covers the changes you make most, how to look at a variant before and after it goes live, and how each deploy is registered. To change what is live without a deploy, see Change what’s live.
Try a new idea under a new key
Add a variant to the slot under a key the slot has never used: a new child of its container, carrying hidden. It goes live with your next production push, with a scorecard against its slot’s default: both are measured at the same time, on the same traffic. To compare two ideas, give each its own key. On Hobby, past the 10 live variants the account’s sites share, a new variant is held until there is room.
A key stays with its variant for good, even once the variant is retired, so a different idea always takes a new key. A variant your server honors, such as a price or a discount, is a trade-off on your site: see Weigh a variant your server honors before you add one.
Fix or refine under the same key
Edit a variant where it stands to fix a typo or tighten its wording. push stamps its new hash, which makes a new version, such as home/hero:learns@v2, and every version is kept.
- Routing builds on what the variant already showed, rather than starting over.
- Its scorecard compares the new version with the one it replaced, each over its own period, not at the same time. A different idea under an old key can’t be compared fairly, so it takes a new key.
- A version is made when the variant’s own source changes, as your template writes it. Reformatting it makes none, its whitespace, quotes and attribute order, and neither does editing a file it includes, or moving
hiddenfrom one variant to another. Whitespace that shows, as between two inline elements, is part of it. See Pages, variants and versions.
Remove a variant, change the default, or bring one back
- Delete a variant’s element from its slot, and the next production push retires it: it stops being served, and its history stays. Deleting a slot’s markup retires its variants; deleting a page’s slots and its entry in
routingcat.config.jsonalso stops routing it. - Write its key again, and the next production push brings it back with its history, and with a new version if its content changed.
- Change the default before you delete it, since every slot needs one. Take
hiddenanddata-nosnippetoff the variant that becomes the default; puthiddenon the old default and take out itsstyle="display:contents", which would show it without RoutingCat’s script.pushthen gives the new default its style. Neither variant gets a new version, since a version leaves out what marks the variant that shows.
retire and resume do the same without a deploy. After either, change the template to match, so the next push agrees.
See a variant in development
On a host your config lists in no environment, such as your own machine, your pages run in development mode: they show the defaults and record nothing. A host listed under environments.preview, such as a staging server, records to the preview environment instead, out of your results. A push from another branch registers that preview’s markup through the GitHub link, or with the preview deploy key; a production deploy key is refused there. In development, add ?rc= to a page’s URL:
?rc=hero:learnsshows that variant in a slot of the page you open;?rc=home/hero:learns,subhead:shortnames the page and several of its slots;?rc=offreturns to the defaults.
The choice lasts for the browser tab, and a badge in the page’s corner names what each slot shows. It works for any variant your head partial lists, so run push after each edit; your production hosts ignore it. In development, track and identify log to the browser’s console instead of recording.
Check what a push will make live
npx routingcat planplan reads your templates and routingcat.config.json as push does, checks them, and compares them with what production serves. It registers nothing. Try your first idea shows a full example.
- Each variant has a mark:
+new,~a new version,-retired. - Each line says what the variant will be compared with: its slot’s default, or its own previous version.
- On Hobby,
plancounts the site’s live variants, the defaults not counted, toward the 10 the account’s sites share, and marks each variant the push would hold. plan homereports one page.- Exit code 0 means
pushwill accept the change. Exit code 1 means it would refuse it, and the line says how to fix it.
Your agent runs plan and tells you what will go live before it registers.
Register each deploy
Your pages decide from what push registered, and each page names, in its head partial, the variants its deploy serves. So each production deploy is registered by push, run right after it, with push --check before it: a push before a deploy that then fails would make live variants your pages never ship. From a deploy that changed your templates until about 2 minutes after its push, your pages show your defaults and record no decision, and doctor names such a page. A site registers in one of three ways, which Set up RoutingCat sets up.
In CI: on GitHub Actions once npx routingcat link github has linked the site, in a job with permissions: id-token: write; or in any CI with the deploy key in ROUTINGCAT_DEPLOY_KEY. RoutingCat reads the branch from the CI’s own variables on GitHub Actions, GitLab, Bitbucket, CircleCI, Jenkins’ multibranch pipelines, Azure Pipelines, Buildkite, Cloudflare’s Workers Builds or Pages, Netlify and Vercel; in any other CI, set ROUTINGCAT_BRANCH to the branch the run deploys. The CI takes two steps:
-
npx routingcat push --checkbefore the deploy. It changes nothing, asks nothing of RoutingCat, and fails while a template lacks a stamp or the partial is out of date:$ routingcat push --checklumen · 1 template · 1 slot, 4 variantsstamps 1 edit push would makelayouts/index.html:3 home/hero:current data-rc-hash fe31485fd14a…, was 58c2042d15ca…partial layouts/partials/routingcat-head.html: up to date✗ Your templates lack 1 of the edits routingcat push makes, so their slots would report other versions than this deploy registers. Run routingcat push, then commit what it changes. (D71, exit 1) -
npx routingcat pushright after the deploy, which registers it:- with the GitHub link, production from a run of your production branch that a
push,workflow_dispatch,scheduleorrepository_dispatchevent started, and a preview from any other run, such as a pull request’s or arelease’s; - with the production deploy key, production from a run of your production branch alone: a run of another branch, of a tag or of a pull request is refused. Such runs register previews with the preview key instead, from
npx routingcat keys deploy --env preview.
- with the GitHub link, production from a run of your production branch that a
The example app’s workflow on GitHub Actions, with the GitHub link, takes both steps around its build and its deploy, at the version its config pins, 1.0.3:
name: Deploy
on: push: branches: [main]
jobs: deploy: runs-on: ubuntu-latest # `id-token: write` lets `push` ask GitHub for the run's OIDC token, which proves the push once # `npx routingcat link github --branch main` has linked the site to this repository. permissions: contents: read id-token: write steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - run: npm ci - run: npx routingcat@1.0.3 push --check - run: npm run build # The site's own deploy of dist/ goes here. - run: npx routingcat@1.0.3 pushIn your host’s deploy script, for a host that deploys on its own, such as Forge, Ploi or a deploy hook on your server: push runs at the end of the script, once the server serves the new templates, with the deploy key and ROUTINGCAT_BRANCH in the script’s environment, as ROUTINGCAT_BRANCH=$FORGE_SITE_BRANCH npx routingcat push on Forge. push --check stays before the deploy, in your CI, or on your machine before you commit. Only a host without a deploy script needs your CI to start its deploy, through the host’s deploy hook, and push once the site serves it.
From your machine, for a site that pushes neither in a CI nor in its host’s deploy script: before you deploy, run push --check, and where it fails, push, which from your machine stamps your templates and registers nothing, then commit what it changes. Right after the deploy, run npx routingcat push --env production. It lists the edits it would still make, here on a Hugo site whose new hero slot was never stamped:
$ routingcat push --env productionlumen · 1 template · 1 slot, 4 variantsstamps 9 edits push would make layouts/index.html:2 home/hero style="display:contents" layouts/index.html:3 home/hero:current data-rc-hash 58c2042d15ca… layouts/index.html:3 home/hero:current style="display:contents" layouts/index.html:6 home/hero:oneclick data-rc-hash c4a2d99ee3bd… layouts/index.html:6 home/hero:oneclick data-nosnippet layouts/index.html:9 home/hero:studio data-rc-hash 975b5d620955… layouts/index.html:9 home/hero:studio data-nosnippet layouts/index.html:12 home/hero:best data-rc-hash c37fb91bad3a… layouts/index.html:12 home/hero:best data-nosnippetpartial layouts/partials/routingcat-head.html: missingThen it prints the plan, as plan shows it. At a terminal, it asks you to confirm. Run by your agent, it pushes nothing and ends:
✗ Nothing was pushed: this plan goes to production once the person confirms it. Show it to them; once they agree, run routingcat push --env production --confirm 6553f70fd916. (D115, exit 3)Your agent shows you the plan, and once you agree, runs it again with --confirm and the digest. It pushes exactly the plan you saw, or nothing if your templates or production changed since:
written 9 stamp edits, layouts/partials/routingcat-head.htmlroutingcat LIVE home: 4 variants in hero, routing within about 2 minutes (ch_01m40j70srer495wr3vhnyvjca, pb_01m40j70srfb59gbvnmr3nv2t6)Here the push also wrote the stamps the templates lacked, which the deployed pages don’t carry: commit them and deploy again, so your pages name what was registered. A push that has nothing left to write registers exactly what your deploy serves.
Know what each push makes live
| Push | What happens |
|---|---|
Production: in CI or a deploy script on your production branch, or --env production |
It registers the change, which is live within about 2 minutes of both the push and the deploy. |
| A preview: in CI with the GitHub link on any other run, or with the preview deploy key | It registers the new versions as a preview and changes nothing live. |
On your machine, without --env production |
It stamps your templates and writes the partial, and registers nothing. |
A production push applies only what its templates changed since the previous one, so an act on something your templates didn’t change holds. Its last line is RoutingCat’s receipt, one of these:
routingcat LIVE home: 4 variants in hero, routing within about 2 minutes (ch_2, pb_1)routingcat NOT LIVE preview: 4 versions registered for home; production unchangedroutingcat registered ch_1 · objective signup · outcomes waitlist · no page routed yetNOT LIVEalso appears on a production push when routing is off for the site. On Hobby, until the site’s owner has a card on file, it readsroutingcat NOT LIVE routing waits for a card on file: add one at …, nothing charged: see Add a card to start routing.- A push that can’t reach RoutingCat registers nothing and exits with code 4: run it again.
- A push fails on an invalid declaration, with the same message
planwould have shown; on a credential RoutingCat refuses, with its reason and exit code 1; and where npx can’t run the version your config pins, with exit code 2. A variant past the 10 live variants your Hobby account’s sites share is held instead, and the push names it after its receipt, with the held-variants warning.
Preview a variant in production
npx routingcat preview home/hero:oneclickOn a home page with one slot:
https://www.lumen.com/#rc_preview=1.eyJieSI6InByXzAxazZnIn0.c2ln forces home/hero:oneclick@v2 path / (its first route) · on dp_01m4xns9ggfyhra1beeb6f424r · until 10:12ZOpened in a browser, it shows a preview badge; the visit stays out of results and leaves your own assignments as they are.- The link is signed and valid for one hour. It shows the variants you name, at most one per slot of one page, and the defaults in the page’s other slots. Its token comes after
#, so it never reaches your server, your logs or a referrer. - It opens the page’s first route without a dynamic segment, else its most frequent path over the past 7 days. Give
--path /pricingwhen the page has neither. - The production deployment must carry the version. A push registers your deployment last, after its changes: if
previewsays no deployment that includes the version has registered yet, run the production push again on the same templates, thenpreview. - The badge names the variant each slot shows. A click hides it.
- The preview lasts for the browser tab, until the link expires. Open the page with
#rc_preview=offto end it sooner.