Skip to content

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:

public/pricing.html
<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 its data-rc-variant;
  • adds style="display:contents" to a container or a default that lacks it;
  • adds data-nosnippet after hidden, 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_key is the public key of the site site names.
  • 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.
  • slots and variants name pages declared under pages.
  • A slot’s weights are 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_share for fixedShare.
  • 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. :slug and * are refused, with the brackets to write.

The slot markup

  • A container carries data-rc-page and data-rc-slot, and each variant data-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 no display in its style, which would show it where RoutingCat doesn’t run. See markup that breaks the grammar.
  • The container and the default are display:contents, as push writes 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 never fetchpriority="high", so that no hidden image is fetched; data-rc-lcp marks one <img> at most per variant. See markup that breaks the grammar.
  • A <template> variant’s data-rc-as is div or span. 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 span elements; a container is never directly inside table, thead, tbody, tfoot, tr, select, ul, ol or dl, 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 id given elsewhere on the page, and one h1 at 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 pages in routingcat.config.json, whose slots and variants name only slots and variants your markup carries. See markup and a config that disagree.