Analytics rules as code

By ·

Somewhere in your business is a definition of what counts as a conversion. Someone created it. It may have been edited since. There is no history, no export, and no record of why, and no notification of when it changes.

Write it

origin: https://example.com
project: myapp/home

rules:
  - rule_id: signup_completed
    tag: converted
    description: Reached the signup success state
    logic: {"in": ["user.signup.success", {"var": "session.actions"}]}

  - rule_id: pricing_visitor
    tag: pricing
    description: Viewed pricing
    logic: {"in": ["page_view.pricing", {"var": "session.actions"}]}

Each rule is a condition evaluated against a completed session. A match writes a tag. Tags are what the clientlog digest counts and what triggers notifications.

The conditions are described in JSONLogic.

Commit it

The file lives beside the code it measures.

Rebuild the signup flow and the rule that measures it appears in the same diff. The reviewer sees both. When the flow changes and the rule does not, that is a visible omission in a pull request.

Check the changes

clog plan --file rules.yaml --origin https://example.com --project myapp/home
example.com/myapp/home
comparing rules.yaml against deployed rules

  ~ signup_completed    [modified]
      logic: {"in": ["signup.thankyou", ...]}
          -> {"in": ["user.signup.success", ...]}

  = pricing_visitor     [unchanged]
  + trial_started       [new - will be created]
  - old_funnel_step     [removed - will be deleted]

summary: 1 modified, 1 added, 1 removed, 1 unchanged

apply writes it. Exit codes: 0 for no differences, 1 for drift, 2 for a validation error, 3 for auth failure. --strict fails on any drift, for pipelines that require the deployed state to match the file.

Drift you did not create is the useful output. Someone edited a rule through the API three weeks ago. Now you know.

Backtest it

clog test --file rules.yaml --rule signup_completed --examples fixtures/sessions.json

The fixtures are sessions exported from your own data. Take one that converted and one that did not. Does the rule match the first and miss the second? We can now include analytics in our CI/CD process.

Rebuild the signup flow now and the test fails in CI, rather than the numbers failing silently for a fortnight.

Log it

commit 4f2a1b9

    Exclude hosting-provider signups from the conversion tag

    Nine signups last week came from one Chrome 142 / macOS user agent
    across five Tor and hosting operators, cycling the three plan
    variants in under a second each. They are counted as conversions
    and they are not conversions.

Six months later someone asks why the rule has an exclusion. The answer is one git blame away.

Rules accumulate. Each one is a lesson about your traffic, written down so it applies to every future session. The rules are a record of how people use your product.


Documentation: Rules