Skip to content

feat: track block add/remove events via telemetry#2862

Open
ineagu wants to merge 1 commit into
developmentfrom
feat/track-block-add-remove
Open

feat: track block add/remove events via telemetry#2862
ineagu wants to merge 1 commit into
developmentfrom
feat/track-block-add-remove

Conversation

@ineagu

@ineagu ineagu commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an editor-side tracker that emits a telemetry event whenever an Otter block is added to or removed from a post, so we finally have visibility into block add/remove behaviour (not just a local, add-only snapshot).

Background. Today the only block-usage signal is src/blocks/plugins/data-logging/index.js, which writes a cumulative, monotonically-increasing instance count per themeisle-blocks-category block into the otter_blocks_logger_data option on post publish/save. That option is read/written only inside the editor — nothing POSTs it off-site (Otter doesn't hook the SDK's _logger_data filter), and by design it can only ever add (removals are invisible). So we currently cannot answer "how often are blocks removed" or "which blocks get added during editing."

Approach. This mirrors what Feedzy already ships in js/FeedzyLoop/tracking.js:

  • subscribe() to the block-editor store, recursively count every block in the themeisle-blocks category (the same category filter data-logging/index.js already uses), and on each change emit the signed delta per changed block type.
  • The first store tick only seeds the baseline (existing blocks are not reported as additions); a 1s delay lets the post load first.
  • Events are sent through the already-initialised window.oTrk (tiTrk.with( 'otter' )) accumulator, using the same feature: 'block-usage' shape Feedzy sends — so Otter and Feedzy block usage line up under one schema, and this does not collide with the existing per-block action: 'block-created' events (the 5 Pro blocks).

Minimal by design: one new file + one import line. No PHP, no new enqueue, no SDK registration, no new option. Reuses window.oTrk, the themeisle-blocks category filter, and the existing otter_blocks_logger_flag opt-in.

Event payload (per changed block type, per change tick):

window.oTrk?.set( `${blockType}:${Date.now()}`, {
    feature: 'block-usage',
    featureComponent: blockType,   // e.g. 'themeisle-blocks/advanced-heading'
    featureValue: String( change ) // signed delta: "2" added, "-1" removed
} );

Test instructions

  1. Build (npm run build) and load the plugin with the tracking opt-in enabled (otter_blocks_logger_flag = 'yes', i.e. window.themeisleGutenberg.canTrack === true; Pro/licensed sites are opted in by default).
  2. Open the block editor and add a couple of Otter blocks (try a nested one, e.g. a block inside a Section/Group). In the console/network, confirm window.oTrk.base.events accumulates feature: 'block-usage' entries with a positive featureValue, and that events flush on Save / tab close to api.themeisle.com/tracking/events.
  3. Remove an Otter block → confirm a block-usage event with a negative featureValue.
  4. Reload a post that already contains Otter blocks → confirm no events fire on initial load (baseline skip).
  5. Set the opt-in off (canTrack false) → confirm the subscriber never attaches and no events fire.

Checklist before the final review

  • Included E2E or unit tests for the changes in this PR.
  • Visual elements are not affected by independent changes.
  • It is at least compatible with the minimum WordPress version.
  • It loads additional script in frontend only if it is required. (editor-only; gated on isBlockEditor + canTrack)
  • Does not impact the Core Web Vitals. (no frontend script)
  • In case of deprecation, old blocks are safely migrated. (n/a)
  • It is usable in Widgets and FSE. (env is auto-tagged by the SDK: post-editor / site-editor / widgets — worth a quick FSE smoke test)
  • Copy/Paste is working if the attributes are modified. (n/a — no attribute changes)

Notes for reviewers / telemetry side

  • New feature: 'block-usage' rows will start arriving for slug: 'otter' — heads-up to whoever owns the Metabase events table so a block-usage breakdown can be added. Same schema as Feedzy's, so they can be compared by slug.
  • Like Feedzy, this reports net deltas per store tick: a simultaneous add+remove of the same type that nets to zero emits nothing, and move/replace is indistinguishable from add+remove. That's an accepted trade-off for the minimal scope; per-clientId identity was intentionally left out.
  • I did not call tiTrk.start() / change eventsLimit (Feedzy does); Otter already flushes on post save (css-handler) and on beforeunload, so the global timer behaviour is left untouched.

🤖 Generated with Claude Code

Add an editor-side tracker that watches the block-editor store and emits a
signed-delta telemetry event whenever an Otter block (any block in the
`themeisle-blocks` category) is added to or removed from a post.

Until now Otter only stored a cumulative, add-only instance snapshot in the
`otter_blocks_logger_data` option, which is never sent off-site and cannot
represent removals. This mirrors the approach Feedzy already ships in
`js/FeedzyLoop/tracking.js`, reusing the existing `window.oTrk`
(`tiTrk.with( 'otter' )`) accumulator, so no new SDK wiring, enqueue or option
is required. Events use the same `feature: 'block-usage'` shape Feedzy sends and
are gated on the existing tracking opt-in (`otter_blocks_logger_flag`).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pirate-bot pirate-bot added the pr-checklist-incomplete The Pull Request checklist is incomplete. (automatic label) label Jun 13, 2026
@pirate-bot

Copy link
Copy Markdown
Contributor

Bundle Size Diff

Package Old Size New Size Diff
Animations 178.24 KB 178.24 KB 0 B (0.00%)
Blocks 1.47 MB 1.47 MB 716 B (0.05%)
CSS 7.87 KB 7.87 KB 0 B (0.00%)
Dashboard 108.48 KB 108.48 KB 0 B (0.00%)
Onboarding 68.14 KB 68.14 KB 0 B (0.00%)
Export Import 4.7 KB 4.7 KB 0 B (0.00%)
Pro 299.31 KB 299.31 KB 0 B (0.00%)

@pirate-bot

Copy link
Copy Markdown
Contributor

Plugin build for 767e52b is ready 🛎️!

@pirate-bot

Copy link
Copy Markdown
Contributor

E2E Tests

Playwright Test Status: See serial and parallel matrix jobs

Performance Results serverResponse: {"q25":396.1,"q50":421.7,"q75":427,"cnt":10}, firstPaint: {"q25":560.7,"q50":681.7,"q75":835.6,"cnt":10}, domContentLoaded: {"q25":3285.5,"q50":3330.45,"q75":3391.5,"cnt":10}, loaded: {"q25":3286.1,"q50":3330.85,"q75":3392.1,"cnt":10}, firstContentfulPaint: {"q25":8860.9,"q50":8944,"q75":9048.3,"cnt":10}, firstBlock: {"q25":13526.7,"q50":13749.75,"q75":13782.3,"cnt":10}, type: {"q25":21.55,"q50":24.26,"q75":26.21,"cnt":10}, typeWithoutInspector: {"q25":20.09,"q50":20.69,"q75":21.54,"cnt":10}, typeWithTopToolbar: {"q25":26.31,"q50":28.67,"q75":29.51,"cnt":10}, typeContainer: {"q25":12.5,"q50":13,"q75":14.81,"cnt":10}, focus: {"q25":103.99,"q50":106.23,"q75":113.08,"cnt":10}, inserterOpen: {"q25":36.43,"q50":37.67,"q75":37.98,"cnt":10}, inserterSearch: {"q25":12.44,"q50":12.55,"q75":12.67,"cnt":10}, inserterHover: {"q25":5.01,"q50":5.13,"q75":5.27,"cnt":20}, loadPatterns: {"q25":1443.16,"q50":1468.66,"q75":1495.16,"cnt":10}, listViewOpen: {"q25":203.27,"q50":205.37,"q75":213.21,"cnt":10}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-checklist-incomplete The Pull Request checklist is incomplete. (automatic label)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants