Skip to content

Merge heatmaps into develop#3566

Merged
jonathanmos merged 32 commits into
developfrom
feature/heatmaps
Jun 23, 2026
Merged

Merge heatmaps into develop#3566
jonathanmos merged 32 commits into
developfrom
feature/heatmaps

Conversation

@jonathanmos

Copy link
Copy Markdown
Member

What does this PR do?

Merges the heatmaps feature into develop

Motivation

What inspired you to submit this pull request?

Additional Notes

Anything else we should know when reviewing?

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

gonzalezreal and others added 30 commits February 25, 2026 10:50
Merge develop into feature/heatmaps
…ntity-resolver

PANA-5681: Add `HeatmapIdentifier` infrastructure [1 of 4]
…pdates

PANA-5681: Update RUM and Session Replay schemas for heatmaps [2 of 4]
…maps

PANA-5681: Integrate HeatmapIdentifierRegistry into RUM for heatmaps [3 of 4]
…replay-heatmaps

PANA-5681: Integrate HeatmapIdentifierRegistry into Session Replay for heatmaps [4 of 4]
…rossplatform-prep

[PANA-5681] Preparation for Heatmaps cross-platform integration
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.80726% with 67 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.54%. Comparing base (0d7a259) to head (c009ee6).

Files with missing lines Patch % Lines
.../android/rum/internal/domain/scope/RumViewScope.kt 46.15% 13 Missing and 1 partial ⚠️
...oid/rum/internal/heatmaps/HeatmapActionResolver.kt 79.07% 7 Missing and 2 partials ⚠️
...android/heatmaps/CrossPlatformHeatmapActionData.kt 0.00% 7 Missing ⚠️
...lay/internal/recorder/HeatmapIdentifierResolver.kt 91.57% 6 Missing and 1 partial ⚠️
...nreplay/internal/recorder/SessionReplayRecorder.kt 50.00% 6 Missing and 1 partial ⚠️
...dog/android/internal/heatmaps/HeatmapIdentifier.kt 71.43% 6 Missing ⚠️
...ndroid/rum/internal/domain/scope/RumActionScope.kt 64.71% 4 Missing and 2 partials ⚠️
...essionreplay/internal/recorder/SnapshotProducer.kt 92.68% 0 Missing and 3 partials ⚠️
...onreplay/internal/LazyHeatmapIdentifierRegistry.kt 90.91% 2 Missing ⚠️
...internal/recorder/DefaultOnDrawListenerProducer.kt 50.00% 2 Missing ⚠️
... and 4 more
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3566      +/-   ##
===========================================
+ Coverage    72.38%   72.54%   +0.16%     
===========================================
  Files          967      978      +11     
  Lines        35712    36058     +346     
  Branches      5971     6041      +70     
===========================================
+ Hits         25849    26156     +307     
- Misses        8192     8231      +39     
  Partials      1671     1671              
Files with missing lines Coverage Δ
...ava/com/datadog/android/heatmaps/HeatmapViewKey.kt 100.00% <100.00%> (ø)
...oid/internal/heatmaps/HeatmapIdentifierRegistry.kt 100.00% <100.00%> (ø)
...m/datadog/android/internal/utils/TapTargetUtils.kt 100.00% <100.00%> (ø)
...rum/src/main/kotlin/com/datadog/android/rum/Rum.kt 86.42% <100.00%> (+0.34%) ⬆️
...otlin/com/datadog/android/rum/_RumInternalProxy.kt 68.00% <100.00%> (+2.78%) ⬆️
...lin/com/datadog/android/rum/internal/RumFeature.kt 92.58% <100.00%> (+0.02%) ⬆️
...d/rum/internal/domain/scope/RumApplicationScope.kt 95.35% <100.00%> (+0.11%) ⬆️
...g/android/rum/internal/domain/scope/RumRawEvent.kt 100.00% <100.00%> (ø)
...droid/rum/internal/domain/scope/RumSessionScope.kt 91.14% <100.00%> (+0.06%) ⬆️
...d/rum/internal/domain/scope/RumViewManagerScope.kt 93.25% <100.00%> (+0.11%) ⬆️
... and 27 more

... and 37 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jonathanmos
jonathanmos marked this pull request as ready for review June 23, 2026 14:24
@jonathanmos
jonathanmos requested review from a team as code owners June 23, 2026 14:24

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c009ee6c4d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +54 to +55
override fun setHeatmapIdentifiers(identifiers: Map<Long, HeatmapIdentifier>, screenName: String) {
delegate()?.setHeatmapIdentifiers(identifiers, screenName)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retry identifier publishing after RUM registers

When Session Replay heatmaps start before RUM is enabled, delegate() is null here so the first snapshots are silently dropped, but HeatmapIdentifierResolver.publishIfChanged() still updates lastPublishedScreenName/lastPublishedEntries before calling this method. If RUM registers later and the hierarchy is unchanged, SR will consider the snapshot already published and never call setHeatmapIdentifiers again, leaving the RUM registry empty until some UI change forces a republish; native taps in that common initialization order will therefore miss dd.action.target.permanent_id.

Useful? React with 👍 / 👎.

),
configuration = ActionEvent.Configuration(sessionSampleRate = sampleRate)
configuration = ActionEvent.Configuration(sessionSampleRate = sampleRate),
action = heatmapResolver?.resolve(rumContext.viewUrl.orEmpty())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve native heatmap IDs at tap time

When a tapped View is moved or recycled under the same parent before the action scope is flushed, this late lookup reads the latest Session Replay registry entry for the captured view key rather than the entry that existed at tap time. A RecyclerView row can reuse the same View object and parent with a different path/permanentId, so the RUM action is attributed to the new row instead of the element the user actually tapped; capture the permanentId when the tap is observed or otherwise pin the SR snapshot used for this action.

Useful? React with 👍 / 👎.

val systemInformation = miscUtils.resolveSystemInformation(context)
val item = recordedDataQueueHandler.addSnapshotItem(systemInformation) ?: return

val currentViewUrl = rumContextProvider.getRumContext().viewUrl

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the queued snapshot's RUM URL

After addSnapshotItem() succeeds, the item already contains the RUM context that will be used to serialize this snapshot, but this line reads the volatile provider a second time. If RUM navigates between those two reads, the segment is queued for one view while heatmap identifiers are hashed with another view URL, so the wireframe permanentIds cannot match the RUM actions for the segment; use item.recordedQueuedItemContext.newRumContext.viewUrl instead of re-reading the provider.

Useful? React with 👍 / 👎.

Comment on lines +151 to +152
if (pathNeededForChildren || view.isValidTapTarget()) {
ctx.resolveIdentity(view, nodePath, typeIndex)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Don’t register IDs for nodes without wireframes

For clickable views whose mapper returns emptyList() (for example a transparent clickable ViewGroup with no background), this registers a heatmap identifier even though NodeFlattener has no wireframe on which to stamp the same permanentId. A tap on such a container can therefore send dd.action.target.permanent_id from the RUM registry, but the Session Replay segment contains no matching wireframe, so the heatmap correlation is broken; only publish IDs for tap targets that actually produce a wireframe, or emit a placeholder wireframe for them.

Useful? React with 👍 / 👎.

@jonathanmos
jonathanmos merged commit 2248829 into develop Jun 23, 2026
27 checks passed
@jonathanmos jonathanmos mentioned this pull request Jul 15, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants