Config and declarations
routingcat.config.json names your site, its pages and its conversions. Each page’s slots and variants are written in your templates, in the slot markup, which npx routingcat push reads and stamps.
routingcat.config.json
npx routingcat init writes it, with your site, its public key and where your templates are; you or your agent add the pages, the objective and the outcomes.
As init writes it, here for a Laravel site, before any page:
{ "$schema": "https://cdn.routingcat.com/schemas/1.0.0/config-1.json", "site": "lumen", "public_key": "pk_lumen_XMufiEsf", "integration": "script", "routingcat": "1.0.0", "environments": { "production": { "hosts": [ "www.lumen.com" ] } }, "sources": [ "resources/views/**/*.blade.php" ], "head": { "partial": "resources/views/routingcat-head.blade.php" }, "pages": {}}| Field | Type | Default | What it holds |
|---|---|---|---|
$schema |
string | None | The address of the file’s JSON Schema, which your editor reads: https://cdn.routingcat.com/schemas/<version>/config-1.json, as push writes it for the routingcat version that runs it. A command refuses a file whose config-<n> is newer than its own, naming the version that reads it. |
site |
string | Required | Your site’s key, as npx routingcat init wrote it. |
public_key |
pk_ id |
Required | Your site’s public key, pk_ and the site’s key and 8 characters, as init wrote it. It names the site and only writes events, so it is safe in your pages. |
integration |
script |
Required | script, as init wrote it: RoutingCat’s script decides in each page. |
routingcat |
string | None | The version of the routingcat command your site runs, as 1.0.0, which writes your head partial: npx routingcat runs it for push, plan, doctor, docs and init, and stops where npx can’t fetch or run it. |
environments.production.hosts |
list of string | Required | Where your pages decide and record as production: exact hosts, or *. and a domain for its subdomains. init writes your production host. |
environments.production.branch |
string | None | Your production branch, which npx routingcat link github takes when you give it none. |
environments.preview.hosts |
list of string | None | Where your pages record as a preview, apart from your results. A page on any other host runs in development mode, and records nothing. |
sources |
list of string | Required | Where your templates are: globs from your project’s folder, as resources/views/**/*.blade.php, in the syntax of Node.js’s fs.glob: *, **, ?, [abc] and {a,b}; a file or folder whose name starts with . is left out. push reads the slot markup in the files they match. |
head.partial |
string | Required | Where push writes the head partial, which your layout includes. |
objective |
objective | None: a routed page then needs its own | The main conversion, which routing learns to get more of, on every page without its own. See Objectives. |
outcomes |
list of string | None | Events tracked beside the objective, by name: counted and reported, never steering routing. |
pages |
object | Required | Your routed pages, by key. |
pages.<key>.routes |
list of string | Required | The paths the page serves, with brackets for what varies: /pricing, /blog/[slug] for one segment, /docs/[...slug] for the rest of the path. At least one; a path belongs to one page. A path names every spelling of its page: /pricing is also /pricing/, /pricing.html and /pricing/index.html. |
pages.<key>.url |
string | None | One path of the page on your production host, which npx routingcat doctor reads to check the page as served. |
pages.<key>.objective |
objective | The site’s | The page’s own objective, in place of the site’s. See Objectives. |
slots |
object | None | Each slot’s routing, by its address, as home/hero. |
slots.<address>.fixed_share |
number | 0 | The share of the slot’s routed visits split evenly, or by weights, keeping each visitor on the same variant across visits: from 0 to 1. At 1, a classic A/B test. |
slots.<address>.weights |
object: variant key → number | Even | The fixed share’s split, by variant key: numbers from 0 to 1,000,000, relative to each other, one of them positive. A variant left out weighs 0 and stays out of the split. |
slots.<address>.personalization |
on or off |
on |
off routes every visitor of the slot the same way. |
slots.<address>.floor |
number | Automatic | The smallest chance each variant keeps of being picked for a routed visit outside the fixed share: from 0 to 1. |
slots.<address>.cap |
number | Automatic | The largest chance each variant can have of being picked for a routed visit outside the fixed share: from 0 to 1. |
variants |
object | None | Each variant’s parent, name, description and tags, by its address, as home/hero:learns. |
variants.<address>.parent |
string or list of string | None | The variant this one was made from, by key, or a version of it, as current@v2; several for a recombination. |
variants.<address>.relation |
fix, refine, fork or recombine |
None | How it relates to its parent. Required with one parent; several read as recombine. |
variants.<address>.name |
string | None | A name for people and agents. |
variants.<address>.description |
string | None | What the variant tries. |
variants.<address>.tags |
list of string | None | Labels to organize variants. |
wait_ms |
integer | 1,000 | How long, in milliseconds, a page’s routed slots wait on a first view for their routing data before they show their defaults: from 0 to 10,000. |
helpers.cookie |
true or false | false |
Whether your server sets the rc_vid cookie, as the server helpers do. |
helpers.fetch_site |
true or false | false |
Whether your server sets the rc_fs cookie, as the server helpers do. |
Objectives
An objective takes one of three forms, on the site or on a page. Its window is how long after a visitor first sees a page a conversion still counts for it: seconds, or a number then s, m, h or d. Limits and defaults gives its default and range.
| Form | Example |
|---|---|
| One event | "objective": "signup" |
| Several, where any one counts | "objective": ["signup", "trial_started"] |
| With its window | "objective": { "events": "signup", "window": "48h" } |
An objective names at most 32 events. A page with two or more live variants needs one, its own or the site’s.
The slot markup
A slot is an element of your template, its container, around its variants, each an element directly inside it. You write the keys and hidden; push writes the rest. From the example app, public/pricing.html, a line in a paragraph of its own and a word inside a sentence:
<h1>Pricing</h1> <div data-rc-page="pricing" data-rc-slot="lead" style="display:contents"> <p data-rc-variant="growth" data-rc-hash="b0918105ecaa53a328a4053a95c7f879e1296ea4e38c566ff8a21a2a2d3818ed" style="display:contents" class="lead">Free while you grow, then by billed visitors</p> <p data-rc-variant="start" data-rc-hash="43059d727593cbc63e95432acd1a62d6b5406187fd79e98c4603d08ee63b6d35" class="lead" hidden data-nosnippet>Start free; pay only for the visitors you bill</p> </div> <p>Start your <span data-rc-page="pricing" data-rc-slot="trial" style="display:contents"><span data-rc-variant="days14" data-rc-hash="55e70241ccd8f3434567706bbe2cfec639c4a80c72096d941822d2f79fa1e95f" style="display:contents">14-day</span><span data-rc-variant="days30" data-rc-hash="196d9ca52c6ba10b0bd7d6838fbc4e30cb89b84cd4290e524da094871695c691" hidden data-nosnippet>30-day</span></span> trial.</p>| Attribute | On | What it holds |
|---|---|---|
data-rc-page |
The container | The page’s key, as pages names it in routingcat.config.json |
data-rc-slot |
The container | The slot’s key |
data-rc-variant |
Each variant | The variant’s key |
hidden |
Each variant but the default | Keeps the variant hidden where RoutingCat doesn’t run |
data-rc-hash |
Each variant | The version of its content, which push writes |
style="display:contents" |
The container and the default | Keeps the slot from adding a box to your layout; push writes it where it is missing |
data-nosnippet |
Each hidden variant | Keeps its text out of the snippets search engines show; push writes it after hidden |
data-rc-lcp |
One <img> of a variant |
The variant’s main image, which RoutingCat preloads for whichever variant shows, so that no variant loads faster than another |
What push stamps
npx routingcat push reads the markup in every file sources matches, and in each start tag:
- writes each variant’s
data-rc-hash, right after itsdata-rc-variant; - adds
style="display:contents"to a container or a default that lacks it; - adds
data-nosnippetafterhidden, on a hidden variant that lacks it.
It never adds or removes hidden, and stamping twice changes nothing. push --check changes nothing, and fails while a stamp is due: run before each deploy, it keeps the versions your pages report true to your templates.
A <template> variant
A variant other than the default can be a <template> element carrying data-rc-variant, with data-rc-as="span" inside a paragraph, div by default. The browser renders none of its content, and RoutingCat’s script copies it into the page only for the visitors it is selected for, so it suits a variant with many elements or images. Use it only where no script of your own renders the slot’s HTML again.
Rules
npx routingcat push and plan refuse a file or markup that breaks one of these, naming its address or its template’s line.
routingcat.config.json
public_keyis the public key of the sitesitenames.- It names its head partial, and its production hosts under
environments, without which every page would run in development mode. - An outcome is listed once, and a route once in its page.
slotsandvariantsname pages declared underpages.- A slot’s
weightsare numbers from 0 to 1,000,000, one of them positive: a variant they leave out weighs 0, outside the split. - It holds the fields above alone: a field it doesn’t know is refused, naming it and the field meant, as
fixed_shareforfixedShare. - A route’s segments are each written as itself, or as a name in brackets alone:
[slug]for one segment, and, last,[...slug]for the rest of the path or[[...slug]]for the rest or none.:slugand*are refused, with the brackets to write.
The slot markup
- A container carries
data-rc-pageanddata-rc-slot, and each variantdata-rc-variant, each key written as itself, never as a template expression: lowercase letters, digits,-and_, at most 40 characters. See markup the scan can’t read. - Every child of a container is a variant, each key once; between them, only whitespace and comments. See markup that breaks the grammar.
- Exactly one variant, the default, has no
hidden: what your page shows today, which the control always sees, and so does a visitor whose browser runs no script. See markup that breaks the grammar. - Every other variant carries
hidden, written alone, and nodisplayin itsstyle, which would show it where RoutingCat doesn’t run. See markup that breaks the grammar. - The container and the default are
display:contents, aspushwrites them, and declare no other display. See markup that breaks the grammar. - Every image inside a variant, the default’s included, is
loading="lazy"and neverfetchpriority="high", so that no hidden image is fetched;data-rc-lcpmarks one<img>at most per variant. See markup that breaks the grammar. - A
<template>variant’sdata-rc-asisdivorspan. See markup that breaks the grammar. - Every copy of a slot in your templates carries the same variants, in the same order, with the same content. See markup that breaks the grammar.
- Every tag a variant opens closes inside it, in the same branch of a conditional; and slots stand in templates in HTML’s syntax: a template indented without tags, as Haml, Slim or Pug, includes an HTML partial that holds its slots. See markup the scan can’t read.
- A slot stays where the browser leaves it: inside a paragraph, its container and its variants are
spanelements; a container is never directly insidetable,thead,tbody,tfoot,tr,select,ul,olordl, but inside the cell or the item, or around the whole; never inside another slot’s variant; and never in<head>. See a slot the browser moves. - A variant holds nothing that acts while it is hidden: no script that runs, no structured data, no stylesheet, no
idgiven elsewhere on the page, and oneh1at most, only in a slot that holds the page’s heading. See what acts while hidden. - A form in a variant other than the default draws a warning, since it submits even while hidden: it must work once shown, and do nothing until then. See what acts while hidden.
- Each page your markup names is declared under
pagesinroutingcat.config.json, whoseslotsandvariantsname only slots and variants your markup carries. See markup and a config that disagree.