🪟 Windows TippsHow to Enable Windows 11 Screen Savers(07.09.2026 um 12:41 Uhr)
🪟 Windows TippsMicrosoft Phone Link Not Showing Messages on Windows 11? Fix It(09.09.2026 um 07:52 Uhr)
⚠️ Malware / Trojaner / VirenPost-DEF CON phishing campaign delivered AMOS and NetSupport malware(24.08.2026 um 09:42 Uhr)
💾 IT Security ToolsHow to Use BloodHound Active Directory Setup Attack Path Analysis(10.09.2026 um 14:35 Uhr)
🕵️ SicherheitslückenCompliance Alert: EU Cyber Resilience Act 24-Hour Reporting Enforced(11.09.2026 um 06:25 Uhr)
🕵️ SicherheitslückenAWS IAM Privilege Escalation: Cheat Sheet And Defense(11.09.2026 um 07:43 Uhr)
🕵️ SicherheitslückenArista warns customers ahead of next week’s security disclosures(02.09.2026 um 23:34 Uhr)
🕵️ SicherheitslückenKARR Security vulnerability(02.09.2026 um 03:15 Uhr)
🪟 Windows TippsHow to Enable Windows 11 Screen Savers(07.09.2026 um 12:41 Uhr)
🪟 Windows TippsMicrosoft Phone Link Not Showing Messages on Windows 11? Fix It(09.09.2026 um 07:52 Uhr)
⚠️ Malware / Trojaner / VirenPost-DEF CON phishing campaign delivered AMOS and NetSupport malware(24.08.2026 um 09:42 Uhr)
💾 IT Security ToolsHow to Use BloodHound Active Directory Setup Attack Path Analysis(10.09.2026 um 14:35 Uhr)
🕵️ SicherheitslückenCompliance Alert: EU Cyber Resilience Act 24-Hour Reporting Enforced(11.09.2026 um 06:25 Uhr)
🕵️ SicherheitslückenAWS IAM Privilege Escalation: Cheat Sheet And Defense(11.09.2026 um 07:43 Uhr)
🕵️ SicherheitslückenArista warns customers ahead of next week’s security disclosures(02.09.2026 um 23:34 Uhr)
🕵️ SicherheitslückenKARR Security vulnerability(02.09.2026 um 03:15 Uhr)

🔧 Programmierung 🕛 vor 2 Monaten 5 Min Lesezeit
0

Stop relying on `timeupdate`: Building battery-efficient video analytics in the browser

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Sunday mornings are for pour-over coffee and catching up on tech courses. A few months ago, I was working through an advanced Rust module on one of the big e-learning platforms. I paused, scrubbed back to re-watch a tricky section on lifetimes, and then skipped ahead.



When I checked my dashboard later, the platform told me I was 85% done with the course.



I wasn't. I was maybe 40% done. The platform's progress tracking was essentially just looking at the highest timestamp I'd reached, completely ignoring the scrubbing and re-watching. It was garbage data.



That specific frustration is what pushed me to build CourseSpeed. I wanted actual, granular learning analytics and better playback speed controls across Udemy, Coursera, and the rest. But building a browser extension that tracks video engagement accurately without turning the user's laptop into a space heater taught me a hard lesson about how we traditionally handle video events in the DOM.



If you're building anything that interacts with HTML5 video—whether it's a custom player, an analytics script, or a browser extension—you need to stop using the timeupdate event.



Here is what you should be doing instead.






The timeupdate trap



If you open the dev tools on almost any video player and attach a listener to timeupdate, you'll see it firing constantly.




CODE
// The old, bad way
videoElement.addEventListener('timeupdate', (e) => {
logAnalytics(e.target.currentTime);
});






The problem? The HTML5 spec doesn't dictate exactly how often timeupdate should fire. It just says it should fire when the playback position changes. In practice, browsers fire it anywhere from 4 to 60 times a second.



If you're just updating a UI progress bar, that's fine. But if you're doing what I do in CourseSpeed—calculating watch-time density, tracking playback speed changes, and syncing local analytics to a backend—that unpredictable firing rate is a nightmare. You end up doing heavy computations on the main thread at random intervals, causing micro-stutters in the video playback and draining battery life on mobile.






Enter requestVideoFrameCallback



Chrome 83 introduced requestVideoFrameCallback (often abbreviated as rVFC), and it's now supported in all major Chromium-based browsers and Safari. Firefox is still dragging its feet on it, but for extension development and modern web apps, it's a game changer.



Instead of relying on a time-based event, rVFC hooks directly into the browser's rendering pipeline. It fires exactly once per rendered video frame.




CODE
const video = document.querySelector('video');

function trackFrame(now, metadata) {
// metadata.mediaTime gives you the exact presentation timestamp
// metadata.presentedFrames tells you how many frames have been shown

const currentTime = metadata.mediaTime;

// Do your analytics math here
calculateEngagement(currentTime);

// Queue the next frame
video.requestVideoFrameCallback(trackFrame);
}

// Kick it off
video.requestVideoFrameCallback(trackFrame);






Why is this better?





  1. It's battery efficient. It aligns with the display's refresh rate and the video's actual frame rate. If the video is 30fps, it fires 30 times a second. If the user pauses, it stops firing completely. No wasted cycles.


  2. You get metadata. The callback passes a metadata object that includes mediaTime, presentedFrames, and expectedDisplayTime. This lets you detect if the video is actually dropping frames or buffering, which is incredible for diagnosing playback quality issues.



When I migrated CourseSpeed's core tracking loop from timeupdate to requestVideoFrameCallback, CPU usage during a 2-hour course dropped by about 14% on my M1 MacBook. That's not a marginal gain. That's the difference between a user keeping your extension enabled and uninstalling it because it's "slowing down their browser."






Finding the video tag in the wild



Of course, getting the analytics loop right is only half the battle. The other half is actually finding the <video> element.



E-learning platforms don't just hand you a clean <video src="..."> tag. They bury it. Udemy uses nested iframes. Coursera wraps things in complex React trees. Skillshare sometimes throws shadow DOMs into the mix.



If you're writing a content script, document.querySelector('video') is going to fail you 90% of the time.



I ended up writing a recursive walker that pierces same-origin iframes and open shadow roots. It's a bit brute-force, but it works reliably across the platforms I support.




CODE
function findVideoElements(root = document, results = []) {
// Check current root
const videos = root.querySelectorAll('video');
videos.forEach(v => results.push(v));

// Pierce open shadow DOMs
const shadowHosts = root.querySelectorAll('*');
shadowHosts.forEach(el => {
if (el.shadowRoot) {
findVideoElements(el.shadowRoot, results);
}
});

// Pierce same-origin iframes
const iframes = root.querySelectorAll('iframe');
iframes.forEach(iframe => {
try {
// This will throw if cross-origin, which is fine, we just catch it
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
findVideoElements(iframeDoc, results);
} catch (e) {
// Cross-origin iframe.
// If the platform uses postMessage for player control,
// you have to hook into that instead.
}
});

return results;
}






You don't want to run this on every DOM mutation. Run it once on page load, and then set up a highly specific MutationObserver that only watches for the insertion of new iframe or video nodes.






A quick note on Firefox



Since Firefox doesn't support requestVideoFrameCallback yet, you need a fallback. Don't just revert to timeupdate blindly.



Use requestAnimationFrame combined with checking video.currentTime. It's not as perfectly synced to the video decoder as rVFC, but it ties your logic to the browser's paint cycle rather than the video element's internal clock, which is still vastly superior to the random firing of timeupdate.




CODE
function fallbackLoop() {
if (!video.paused) {
calculateEngagement(video.currentTime);
requestAnimationFrame(fallbackLoop);
}
}






Building tools that sit on top of other people's web apps is always a bit of a cat-and-mouse game. The platforms change their DOM structures, they update their player APIs, and things break. But by relying on low-level browser APIs like requestVideoFrameCallback instead of high-level DOM events, you anchor your code to the rendering engine itself.



It makes your analytics smoother, your extension lighter, and your Sunday morning coffee breaks a lot less frustrating.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Kritische „OVERPASS“-Lücke bedroht den SAP-Kernel - it-daily.net
1 Quelle
ChatGPT: Versteckter Prompt konnte Gmail-Daten abgreifen - it-daily.net
1 Quelle
GuardBreaker: Derailing AI-assisted malware analysis with a code comment
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Stop relying on `timeupdate`: Building battery-efficient video analytics in the browser

Thematisch verwandte Begriffe: Stop, relying, timeupdate, Building · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...