feat: track activation first-insert → first-save funnel#2866
Open
ineagu wants to merge 2 commits into
Open
Conversation
Adds first-insert (once/session) and first-save (once/site, persisted via a new boolean option) activation milestones + a bucketed depth signal. Consent-gated, non-PII. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Bundle Size Diff
|
Contributor
|
Plugin build for 01834b7 is ready 🛎️!
|
Contributor
E2E TestsPlaywright Test Status: See serial and parallel matrix jobs Performance ResultsserverResponse: {"q25":391.6,"q50":398.95,"q75":422.9,"cnt":10}, firstPaint: {"q25":508.5,"q50":605.35,"q75":675.2,"cnt":10}, domContentLoaded: {"q25":3308.9,"q50":3322.85,"q75":3335.9,"cnt":10}, loaded: {"q25":3309.6,"q50":3323.35,"q75":3336.4,"cnt":10}, firstContentfulPaint: {"q25":8931.2,"q50":9000.75,"q75":9044.5,"cnt":10}, firstBlock: {"q25":13506.8,"q50":13630.05,"q75":13661.2,"cnt":10}, type: {"q25":22.15,"q50":23.44,"q75":24.29,"cnt":10}, typeWithoutInspector: {"q25":19.83,"q50":20.09,"q75":22.23,"cnt":10}, typeWithTopToolbar: {"q25":27.43,"q50":28.61,"q75":30.98,"cnt":10}, typeContainer: {"q25":13.13,"q50":13.46,"q75":14.31,"cnt":10}, focus: {"q25":118.91,"q50":124.87,"q75":130.21,"cnt":10}, inserterOpen: {"q25":39.27,"q50":40.38,"q75":41.77,"cnt":10}, inserterSearch: {"q25":12.72,"q50":13.01,"q75":13.35,"cnt":10}, inserterHover: {"q25":5.12,"q50":5.31,"q75":5.47,"cnt":20}, loadPatterns: {"q25":1469.67,"q50":1478.47,"q75":1497.4,"cnt":10}, listViewOpen: {"q25":219.85,"q50":233.66,"q75":237.26,"cnt":10} |
- first-insert is now once-per-site (new otter_activation_first_insert option) and fires only on a real insertion (count exceeds the load-time baseline), not on opening existing content - treat established sites (existing otter_blocks_logger_data) as already-activated so long-time users aren't counted - gate both milestones on settings-loaded to avoid a fast-publish double-fire; add .catch on the persistence writes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Outcome
We don't currently know how many people who add their first Otter block ever go on to actually save/publish a post with it. That first-insert → first-save step is the core activation moment for the plugin, and today it's a blind spot in our telemetry.
This adds two milestone events that let us compute that funnel:
With both in hand we can answer: "What share of sites that try an Otter block reach the point of saving content with it, and how rich is that content?" That informs onboarding decisions — where to invest in nudges, defaults, or guidance if there's a meaningful drop-off between trying a block and committing to it.
What changed
inc/plugins/class-options-settings.php— registers a new boolean site optionotter_activation_first_save(defaultfalse,show_in_rest) used as the per-site "already fired" marker for the first-save milestone, so it persists across browsers/devices rather than re-firing per session.src/blocks/plugins/data-logging/index.js— adds the funnel logic to the existing editorsubscribeloop:countOtterBlocks()— recursively counts Otter (themeisle-blockscategory) block instances, including inner blocks.getDepthBucket()— buckets that count into a closed enum.activationFirstInsertFired); intentionally not gated on save so the insert → save drop-off stays computable.otter_activation_first_savevia the Settings store (mirroring theotter_blocks_logger_datamechanism) so it fires exactly once per site. The state is guarded immediately before the async settings save so concurrent subscribe ticks can't double-fire.Telemetry event shapes added (all via the existing
window.oTrk?.set(...)accumulator):Compliance
'true') and a bucketed block-count enum.featureValuefor depth is restricted to a closed allowlist ('1','2-3','4-10','10+'); raw counts are never sent.Boolean( window.themeisleGutenberg.canTrack ), which is derived server-side from the existingotter_blocks_logger_flagopt-in (inc/class-registration.php,inc/Tracker.php). No event sets{ consent: true }(theoTrkper-event consent-override path) — there is no consent bypass in this change. If a site hasn't opted in, nothing fires.otter_activation_first_saveoption only stores a boolean milestone marker; it holds no user data.Test plan
On a site with usage tracking enabled (
otter_blocks_logger_flag=yes, i.e.window.themeisleGutenberg.canTrack === true):activation / first-insert / trueevent is accumulated onoTrk. Insert more Otter blocks in the same session and confirm it does not fire again (once-per-session guard).activation / first-save / trueplusactivation / first-save-depth / <bucket>fire, that the bucket matches the number of Otter blocks present (1 →'1', e.g. 5 →'4-10'), and thatotter_activation_first_saveflips totruein Settings (/wp-json/wp/v2/settings).! isAutoSaving).Events can be observed on the
window.oTrkaccumulator in the editor console before flush, and downstream where the otheroTrk/tiTrkevents land (the/tracking/eventsendpoint → Metabase).Related
Part of the telemetry-expansion roadmap, following the established data-logging pattern from PR #2862 (block add/remove tracking). Reuses the same
oTrkaccumulator andotter_blocks_logger_flagconsent gate, and the per-site "fire once" mechanism mirrors the existingotter_blocks_logger_dataoption.🤖 Generated with Claude Code