Add Matomo retention dimension: Days Since Registration#12227
Merged
mekarpeles merged 9 commits intomasterfrom Apr 3, 2026
Merged
Add Matomo retention dimension: Days Since Registration#12227mekarpeles merged 9 commits intomasterfrom
mekarpeles merged 9 commits intomasterfrom
Conversation
- Add get_patron_status(user) helper that buckets patron account age
into visit-scoped Matomo dimension values: visitor, d0, d1+, d7+,
d14+, d30+, d90+
- Set web.ctx.patron_status per-request in setup_contextvars processor
- Add patron_status default ('visitor') to context.defaults
- Push _paq.setCustomDimension(1, patron_status) in head.html before
the Matomo Tag Manager container fires trackPageView
- Add unit tests covering all bucket boundaries and error cases
for more information, see https://pre-commit.ci
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a Matomo visit-scoped custom dimension (“Days Since Registration”, dimension ID 1) to enable retention analytics by bucketing a patron’s account age and sending that bucket with pageview tracking.
Changes:
- Add
get_patron_status(user)helper to bucket account age intovisitor,d0,d1+,d7+,d14+,d30+,d90+. - Compute and store
patron_statusduring request setup and provide a safe default in context defaults. - Send the computed bucket to Matomo via
_paq.setCustomDimension(1, ...)in the site<head>.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| openlibrary/plugins/openlibrary/code.py | Adds bucketing helper + sets web.ctx.patron_status per request + adds default context value |
| openlibrary/templates/site/head.html | Pushes Matomo custom dimension 1 to _paq before tag manager loads |
| openlibrary/plugins/openlibrary/tests/test_patron_status.py | Adds unit tests for bucketing behavior and fallbacks |
for more information, see https://pre-commit.ci
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #12144
Wire up Matomo visit-scoped custom dimension 1 ("Days Since Registration") to enable patron retention analytics on openlibrary.org.
Technical
The dimension was already created in Matomo admin (dimension ID 1, visit-scoped). This PR adds the server-side bucketing logic and the JS call to send it.
openlibrary/plugins/openlibrary/code.pyget_patron_status(user)— maps a patron's account age to one of seven dimension values:visitor,d0,d1+,d7+,d14+,d30+,d90+. Readsuser.createddirectly (infogami stores this as adatetime.datetime). Falls back tod90+on any error.setup_contextvarsprocessor — computesweb.ctx.patron_statusonce per request after the user session is resolved, so it's available to all templates.setup_context_defaults— addspatron_status: 'visitor'as a safe default.openlibrary/templates/site/head.html$if not is_bot()guard, initializes_paqand callssetCustomDimension(1, '$ctx.patron_status')before the Matomo Tag Manager container loads. Because the MTM container script is async, the_paqqueue is populated first and processed in order when the tracker initializes — so the dimension is set beforetrackPageViewfires.No individual user tracking; no user IDs or hashes. Purely aggregate, compatible with IP anonymization.
Testing
visitord0d30+(or appropriate bucket)pytest openlibrary/plugins/openlibrary/tests/test_patron_status.py -vScreenshot
N/A — analytics-only change, no UI.
Stakeholders
@mekarpeles