Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 [RUM-8606] Track First Hidden before init #3391

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

RomanGaignault
Copy link
Contributor

@RomanGaignault RomanGaignault commented Mar 4, 2025

Motivation

When a page is in background, the browser can pause or slow down its execution to preserve resources. This is known to screw page-load related metrics (ex: vitals like FCP/FID and other like @view.loading_time): when the user opens a page in background (ex: middle click), those timings can be arbitrary long (as long as the tab stays in background). This is why we try to detect that a page was hidden/in background and discard those timings in this case.

But we only do so once init is called: we don’t know whether a page was in background before init is called, or even before the SDK was loaded.

Changes

Chrome is providing Performance entries called visibility-state that are notified whenever a page gets hidden/visible: VisibilityStateEntry - Web APIs | MDN . It is possible to query past entries using performange.getEntriesByType('visibility-state'). When the browser support this, it could be used as initial state in trackFirstHidden .

Testing

  • Local
  • Staging
  • Unit
  • End to end

I have gone over the contributing documentation.

@RomanGaignault RomanGaignault requested a review from a team as a code owner March 4, 2025 10:13
@codecov-commenter
Copy link

codecov-commenter commented Mar 4, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.75%. Comparing base (ac9b316) to head (71880fa).
Report is 9 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3391   +/-   ##
=======================================
  Coverage   92.75%   92.75%           
=======================================
  Files         299      299           
  Lines        7852     7855    +3     
  Branches     1792     1793    +1     
=======================================
+ Hits         7283     7286    +3     
  Misses        569      569           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@RomanGaignault RomanGaignault changed the title [RUM-8606] Track FIrst Hidden before init 🐛 [RUM-8606] Track FIrst Hidden before init Mar 4, 2025
Copy link

cit-pr-commenter bot commented Mar 4, 2025

Bundles Sizes Evolution

📦 Bundle Name Base Size Local Size 𝚫 𝚫% Status
Rum 147.99 KiB 148.19 KiB 207 B +0.14%
Logs 52.20 KiB 52.20 KiB 0 B 0.00%
Rum Slim 106.66 KiB 106.86 KiB 203 B +0.19%
Worker 24.50 KiB 24.50 KiB 0 B 0.00%
🚀 CPU Performance
Action Name Base Average Cpu Time (ms) Local Average Cpu Time (ms) 𝚫
addglobalcontext 0.002 0.002 0.000
addaction 0.037 0.039 0.003
addtiming 0.001 0.001 -0.000
adderror 0.073 0.054 -0.019
startstopsessionreplayrecording 0.012 0.009 -0.002
startview 0.485 0.370 -0.115
logmessage 0.025 0.020 -0.004
🧠 Memory Performance
Action Name Base Consumption Memory (bytes) Local Consumption Memory (bytes) 𝚫 (bytes)
addglobalcontext 31.13 KiB 29.38 KiB -1790 B
addaction 57.10 KiB 55.65 KiB -1479 B
addtiming 27.55 KiB 28.30 KiB 766 B
adderror 62.63 KiB 60.57 KiB -2109 B
startstopsessionreplayrecording 26.71 KiB 26.00 KiB -730 B
startview 428.79 KiB 424.13 KiB -4776 B
logmessage 61.44 KiB 61.21 KiB -240 B

🔗 RealWorld

@RomanGaignault RomanGaignault marked this pull request as draft March 4, 2025 13:27
@RomanGaignault RomanGaignault force-pushed the romanG/check-page-hiden-before-init branch from e275848 to e21ce2c Compare March 4, 2025 14:26
@RomanGaignault RomanGaignault force-pushed the romanG/check-page-hiden-before-init branch from e21ce2c to a43463c Compare March 4, 2025 14:27
@RomanGaignault RomanGaignault changed the title 🐛 [RUM-8606] Track FIrst Hidden before init 🐛 [RUM-8606] Track First Hidden before init Mar 5, 2025

if (typeof performance !== 'undefined' && 'getEntriesByType' in performance && supportsVisibilityStateEntries()) {
Copy link
Member

Choose a reason for hiding this comment

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

💬 suggestion:
You can use supportPerformanceTimingEvent from

export function supportPerformanceTimingEvent(entryType: RumPerformanceEntryType) {

Suggested change
if (typeof performance !== 'undefined' && 'getEntriesByType' in performance && supportsVisibilityStateEntries()) {
if (supportPerformanceTimingEvent('visibility-state')) {

No need to test for performance being defined, as all browsers we support support it.

Comment on lines 13 to 20
const visibilityEntries = performance.getEntriesByType('visibility-state')
if (visibilityEntries && visibilityEntries.length > 0) {
for (const entry of visibilityEntries) {
if (entry.name === 'hidden') {
earliestHidden = Math.min(earliestHidden, entry.startTime)
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

💬 suggestion: ‏entries are ordered in the buffer so you could just get the first one

    performance.getEntriesByType('visibility-state').find(entry => entry.name === 'hidden')?.startTime

Comment on lines 22 to 27
if (document.visibilityState === 'hidden') {
timeStamp = 0 as RelativeTime
} else if (earliestHidden < Infinity) {
timeStamp = earliestHidden as RelativeTime
} else {
timeStamp = Infinity as RelativeTime
Copy link
Member

Choose a reason for hiding this comment

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

💬 suggestion: maybe change the function design like the following to make it clearer:

function trackFirstHidden(configuration: RumConfiguration, eventTarget: Window = window): { timeStamp: TimeStamp, stop: () => void } {
  if (document.visibilityState === 'hidden') {
    return { timeStamp: 0, stop: noop }
  }

  if (supportPerformanceTimingEvent('visibility-state')) {
    const firstHiddenEntry = performance.getEntriesByType('visibility-state').find(entry => entry.name === 'hidden')
    if (firstHiddenEntry) {
      return { timeStamp: firstHiddenEntry.startTime, stop: noop }
    }
  }
  
  let timeStamp = Infinity
  const { stop } = addEventListeners(...)
  return { get timeStamp() { return timeStamp }, stop }
}

@RomanGaignault RomanGaignault marked this pull request as ready for review March 7, 2025 15:53
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