Skip to content

Conversation

@sethfowler-datadog
Copy link
Contributor

@sethfowler-datadog sethfowler-datadog commented Dec 4, 2025

Motivation

The current DOM serialization algorithm produces two kinds of attributes on elements:

  1. Real DOM attributes, like foo="bar" in <div foo="bar">.
  2. "Virtual" attributes representing metadata about the element. For example, rr_scrollLeft and rr_scrollTop are used to capture information about the initial scroll position of an element.

Many of these virtual attributes are primarily of interest in full snapshots; later, when the values change incrementally, we represent them using dedicated records. For example, later changes to rr_scrollLeft and rr_scrollTop are represented as BrowserIncrementalSnapshotRecord records with IncrementalSource.Scroll. (Speculating on the reasoning for the different representation in full snapshots, I'd guess this was done because there's no easy way to bundle multiple changes into a single, atomic full snapshot record except to include them in the DOM snapshot itself. Incremental snapshots can bundle together many changes at once, so they don't have the same issue.)

The new DOM serialization algorithm doesn't have a special record type for full snapshots; everything uses a representation comparable to our current incremental snapshots. For that reason, the new algorithm doesn't need these virtual attributes; it makes more sense to encode these values in the same way we do today for incremental snapshots.

To make it easier to share code between the current DOM serialization algorithm and the new one, let's separate the code that serializes real DOM attributes from the code that serializes virtual attributes.

Changes

This PR:

  • Renames safeAttrs to attrs in serializeAttributes() as a minor opportunistic refactor. I'm not a big fan of the name safeAttrs since it implies that everything in safeAttrs satisfies our privacy rules and is safe to record, but in fact that's not true until the end of the function.
  • Splits serializeAttributes() into two functions, serializeDOMAttributes() and serializeVirtualAttributes(). (serializeAttributes() survives as a trivial wrapper around these two functions.)
  • Tweaks the types in a few places to more accurately reflect the kinds of values that serializeDOMAttributes() can now return.
  • Removes the call to getValidTagName() from both functions since it contains a regular expression which it would be wasteful to invoke in two places. getValidTagName() doesn't really provide any benefit since we are only comparing the tag name with exact known strings in this code; we can just use Element#tagName directly.
  • Updates the tests for serializeAttributes() to call serializeDOMAttributes() or serializeVirtualAttributes(), as appropriate. (I wrote the tests with this in mind, so making the switch is easy.)

Checklist

  • Tested locally
  • Tested on staging
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.

@sethfowler-datadog sethfowler-datadog requested a review from a team as a code owner December 4, 2025 16:13
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.

2 participants