The contract
analytics.json sits next to your manifest.json and schema.json. One App ships one analytics.json, declaring one or more flat views over the entities in its schema.json.
my-app/
manifest.json identity, vendor and app name, capabilities
schema.json the entities your app owns
analytics.json which of those entities are analysable, and how
Validate as you write
The contract is published as JSON Schema:
https://schemas.revenexx.com/analytics.schema.json
Point your editor at it with $schema and you get completion and validation as you type — which matters here, because most of the file is string locators whose exact form is checked by a pattern:
{
"$schema": "https://schemas.revenexx.com/analytics.schema.json",
"version": "1",
"views": []
}
Two fields are required at the top level: version, which is the contract major version and is currently "1", and views, which needs at least one view. Nothing else is allowed at the top level.
Its relationship to schema.json
schema.json is the source of truth; analytics.json is a projection of it.
schema.json says | analytics.json says |
|---|---|
| Which entities your app owns, and their fields, attributes and relations | Which of those entities are analysable, flattened into which columns |
Every view's source names an entity from your schema.json, and every column's from locator resolves against that entity — its scalar columns, its attributes, the relations it can follow. So a view can never expose something the schema does not describe, and a rename in schema.json is a change you have to make in both files.
Two practical consequences:
- Write
analytics.jsonafter the schema settles. Declaring analytics over an entity whose fields are still moving is churn for no benefit. depends_ondocuments the entities a view reads through relations. It is not a join specification — the locators do that — but it records the dependency, and it is the field a reviewer reads to understand what a view touches.
Where the two files come apart: analytics.json is one row per key, not one row per locale. A localised attribute is collapsed to a single scalar at the view's default_locale, so per-locale breakouts have to be explicit extra columns. See Column locators.
Its relationship to manifest.json
The manifest supplies the identity that names the emitted dataset. Your vendor and app name plus the view name produce a fixed pattern:
analytics.<vendor>__<app>__<view>
So a view named locations in the acme/warehouse App is registered as analytics.acme__warehouse__locations. You do not choose the name; you choose the view name, and the rest comes from the manifest.
What happens at deploy time
analytics.json is picked up as part of the normal App deploy, alongside the manifest and schema:
revenexx deploy app
At deploy, the views in analytics.json are compiled and registered as datasets for the tenant, scoped so each one only ever returns that tenant's rows. They then appear in that tenant's Analytics Studio — in the dataset picker, in cohorts, and in the chart builder — labelled with your title and description.
See Deploy with the CLI for the full loop.
There is nothing to call and nothing to enable afterwards. Deploying is the whole of publishing analytics, and re-deploying with a changed analytics.json is how you change them.
What it is not
- It is not a query API for you. Declaring a view does not give your own code a way to query it. It puts your data in front of the tenant's operator, in Cockpit.
- It is not a place for SQL. You declare what is analysable and where each column comes from. The platform builds the flat view.
- It is not where isolation or storage is configured. Both are platform decisions you cannot opt out of — see Tenant isolation.
Sizing the opportunity
Only a handful of the platform's own apps ship an analytics.json today — notably neither the orders app nor the customers app does — so views you declare genuinely add to what the tenant can analyse rather than duplicating it.
Where to go next
- Declaring a view — the fields of a view, one by one.
- Example — a complete file.
- Schema reference — the
schema.jsonthis projects from.