Your Reports Now Speak Editorial: Content & Reader Dimensions, Pages & Users Reports, Named A/B Tests

For as long as web analytics has existed, the unit of measurement has been the URL. Your CMS knows that /economy/salaries/pension-reform-84f46e03 is a 1,400-word paywalled feature published this morning, sitting behind a section that matters to you. Your analytics knew it as a string. Every question about what kind of content works had to be answered by exporting a report, pulling a second export from the CMS, and joining the two in a spreadsheet — assuming the URL patterns lined up, which they never quite do.

This month we closed that gap. Alke Analytics now reads your content the way you write it, and your reader the way your subscription funnel sees them — automatically, without a tag plan meeting.

Every page — and every reader — now describes itself

Sixteen new named dimensions ship alongside the ten custom data slots you already had. Most of them fill themselves in.

What the page is. The collector derives a three-level content hierarchy (level1, level2, level3) from the URL path — and it drops the trailing slug only when the page really is a piece of content, so /economy/salaries/pension-reform-84f46e03 groups under economy › salaries while /economy/salaries/ still groups as a section. It reads your JSON-LD for schemaType, datePublished, dateModified, wordCount, mediaCount and coverImage.

And it reads your paywall — as three states, not two. Free, paywalled, or not declared. That distinction matters more than it sounds: a boolean would have to guess, and a page whose paywall flag couldn’t be read would land in your paid inventory. It doesn’t. It lands in “not declared”, where you can see it, filter on it, and go fix the markup.

Who the reader is. loggedIn, subscriptionStatus (anonymous, registered, trial, subscriber, expired), newsletter, and a rolling visit counter that becomes a loyalty tier: fly-by, regular-reader, engaged-regular, superfan. Plus goal for the conversion reached on a page, and abtest for the experiment running on it.

Two things we care about here:

  • Automatic never overwrites you. If your site pushes a harmonized level1 because your URLs don’t match your editorial taxonomy, extraction will not stomp on it. Values you set win, always — and a harmonized level you push goes through the same normalization as a derived one, so the two group together instead of splitting your rubric in half.
  • Nothing is silently truncated. A value that breaks its contract — a word count in the millions, a two-letter country code that isn’t two letters, a cover image that isn’t a URL — is rejected outright with an explicit message, rather than cut short and stored as something plausible and wrong.

setDimension() and setDimensions() are available on every platform: web, iOS, tvOS, Android, Android TV and Tizen. The automatic extraction is web-only, for the obvious reason that there is no URL path, no JSON-LD and no DOM inside a native app — there, you push what you know.

Two new reports built on top: Pages and Users

New dimensions are only worth as much as the reports that use them, so there are two new pages in the sidebar.

Pages walks through the structure of your site and then the substance of it: page group, the three hierarchy levels, host, schema type, paywall status, and three new content buckets. Users answers the two questions you actually ask about an audience — who is this person (logged in, subscription, newsletter, country) and how attached are they (visit sequence, engagement level, goal, bot). Each dimension gets a chart and a table, with the same metrics, comparisons and revenue breakdowns as everywhere else.

The three content buckets are the new part:

BucketDerived fromSlices
article_lengthword countnot-declared · short (1–299) · standard (300–799) · long-form (800–1499) · in-depth (1500+)
media_richnessmedia countno-media · single · few (2–4) · rich (5–9) · gallery (10+)
content_agepublication datenot-declared · breaking (<24h) · this-week · this-month · this-year · archive (>1y)

These are computed at read time, not collected. Nothing new is stored, nothing new is sent, and the thresholds can move later without rewriting a single row of history. They filter and group like any other column — so “what does an in-depth archive piece earn compared to a short breaking one” is now a two-click question.

One small thing with an outsized effect: “Not declared” is now a real, named, selectable value. Six columns store an empty string to mean “nobody ever declared this”, and until now every layer above the database rendered that as a blank cell — in the table, in the public API, and in the Google Sheets connector. It’s now labelled, clickable, and filterable. Clicking it builds an is empty filter, which is what you meant.

Your A/B tests, by name

The abtest identifier your site pushes is whatever your experimentation tool calls it — hp_hdr_v3_b, if you’re lucky. Readable in code, unreadable in a report.

There’s now an A/B test dictionary, per property, in Settings. Map an identifier to a name and a description once, and it shows up named everywhere abtest is grouped — including in your CSV exports. The identifier field suggests the values actually observed in your data, because case is significant on collection and a typo would otherwise create an entry that describes nothing, forever, with no signal that it’s broken.

Two deliberate choices: deleting an entry is a soft delete (your historical reports don’t switch back to raw identifiers overnight), and clicking a named cell to filter still sends the stored identifier, with the raw value on hover — so what you see filtered is what you asked for.

The same vocabulary on every screen

None of the above is worth much if your app measures differently from your site.

A real page boundary, everywhere. pushNavigation() is now the single page boundary in single-page apps and in native apps. It sends the final hit for the page you’re leaving, clears everything page-scoped — dimensions whatever their source, goal, custom data, active time, scroll, video sequence — and re-derives the automatic dimensions of the page you’re on. This fixed real damage: time on page kept running until the report was actually transmitted, so a page whose beacon left late was credited with seconds it never had. And two pushPageView() calls without a boundary between them shared a pageview id, which meant the second page vanished from your reports while its ad revenue was counted twice — a true RPM of 1,500 reading as 3,000. pushNavigation() between two page views is now required, and the documentation says what forgetting it costs.

Video events got the same treatment: a player still alive across a navigation used to report its video with the next page’s dimensions. The tracker now captures its context when it starts, not when it sends.

Traffic source, derived natively. The Apple and Android SDKs now categorize traffic themselves, against the same closed vocabulary of eleven values the server accepts — SEO, SEA, Social, Email, Paid Advertising, Referral, Affiliate, Google Discover, LLM, Other Campaign, Direct. Before, a category set by an integrator was silently rewritten server-side with nothing to warn them. Campaign attribution from deeplinks (handleOpenURL()) works on iOS, tvOS and Android, and the source is decided once when the session opens and carried by every report in it.

Consent, with the same answer on every platform. The no-exemption mode (requireExplicitConsent) existed on the web only, while being documented under a tab whose native siblings said nothing about it — so a publisher enabling it on their site and shipping an app had two different compliance postures for one consent decision. It now runs on all five native SDKs. Set it, and nothing reaches our servers until Alke Tech (IAB TCF vendor 1506) is explicitly consented. The SDK keeps working normally — ad targeting, ad calls, everything — only transmission is held, in memory only, because a mode whose whole promise is “nothing leaves” can’t be persisting its own queue to disk. Absence of a signal is never consent: a silent CMP, a vendor list too old to carry us, a short bitfield — all answer no.

One more platform note worth knowing: on a connected TV, engagementLevel describes a household, not a person. The device is shared. A superfan on apple-tv is an assiduous household, and the reports say so rather than letting you read it as one very devoted individual.

In brief

  • Source attribution is fixed — and your series will break. UTM parameters were being read under the wrong key and were, in practice, ignored entirely: an arrival on ?utm_medium=newsletter with no referrer was filed as Direct. It is now filed as Email. This is the correction you want, but be warned — traffic currently sitting in Direct, Referral and SEO will move to Email, Paid Advertising and Social from deployment day, and your source reports will show a discontinuity there. It’s worth an annotation.
  • Click-to-filter no longer builds filters it can’t express. Clicking a date cell used to construct an impossible operator and return an error. Clicks that can’t say anything now do nothing, and the filter bar offers is between / before / after instead.
  • env=ctv is documented. tvOS has always emitted it, but the parameter table listed only web and app — and the natural reading that “app covers all native” is wrong. Filtering on app excludes your connected TV traffic.
  • setCustomData() and setLateCustomData() now return a boolean on every platform, where they previously returned undefined on success. A deliberate break, so that success and rejection are finally distinguishable.
  • And a good deal you’ll never see. Behind the reports, a large share of this month’s work went into the platform itself: infrastructure moved, capacity re-sized, storage and streaming hardened, and our own build and review tooling tightened. None of it changes a screen. All of it is why the screens stay fast, and why the next features land sooner.
  • Google Ad Manager Data Transfer now has a published delivery contract, plus a ready-made Snowflake export query — for publishers whose GAM files reach us through a partner re-export. File tree, naming, the eight file types and their columns, the alke_id prerequisite, and a validation checklist before the first delivery.

Wrapping up

The through-line this month is that your analytics should already know what your CMS knows. A section, a length, a publication date, a paywall, a subscriber, a loyal reader — these are the terms you actually plan and argue in, and until now they lived on the other side of an export. They’re dimensions now: filterable, groupable, chartable, and the same on the web, in your apps and on TV.

As always, everything above is live in your dashboard today. Go ask it something you couldn’t ask last month.


See what Alke Analytics can do for your properties

Start your free 7-day trial — no credit card required, no commitment.

Start free trial — 7 days · Request a Demo

Xavier Leune

About Xavier Leune

17 published articles

Xavier Leune is the founder and CEO of Alke Analytics, with 2 decades of experience and over 10 years at one of France's largest digital media groups 4 years as VP of Engineering. He led analytics initiatives for high-traffic publisher properties, specializing in GDPR compliance, Core Web Vitals optimization, and cross-property data aggregation. Xavier's expertise in Advertising technology, CMP tracking, and audience management addresses the unique challenges of modern digital publishing. An active member of the French PHP User Association, he combines technical depth with editorial understanding.