Testing

IntersectionObserver: Browser Support, Features, Issues

IntersectionObserver is a W3C JavaScript API for tracking element visibility. Learn which browsers support it, how to use it, and the known issues to plan for.

Author

Prince Dewani

May 1, 2026

IntersectionObserver is a W3C JavaScript API that asynchronously reports when an element enters or leaves the viewport or a chosen ancestor. It works in Chrome 58+, Edge 16+, Firefox 55+, Safari 12.1 on macOS, Safari 12.2 on iOS, Opera 45+, and Samsung Internet 7.2+, while Internet Explorer never added support.

This guide covers what IntersectionObserver is, its browser support, key features, use cases, how to use it in JavaScript, the differences from MutationObserver, and known issues.

What is IntersectionObserver?

IntersectionObserver is a JavaScript API standardized by the W3C that watches when a target element crosses into or out of a chosen viewport or ancestor element. The constructor takes a callback and an options object, and the browser fires the callback whenever the target's visibility crosses one of the configured thresholds.

Which browsers does IntersectionObserver support?

IntersectionObserver works in every modern browser, including Chrome, Edge, Firefox, Safari, Opera, and Samsung Internet. Internet Explorer is the only major browser that never added support.

Loading browser compatibility data...

IntersectionObserver compatibility in Chrome

Chrome supports IntersectionObserver from Chrome 58 on desktop and Android. Chrome 51 to 57 had partial support, and Chrome 50 and earlier did not include the API.

IntersectionObserver compatibility in Edge

Edge supports IntersectionObserver from Edge 16 on desktop, and the Chromium-based Edge releases that followed inherit the same support. Edge 15 had partial support, and Edge 12 to 14 did not support it.

IntersectionObserver compatibility in Firefox

Firefox supports IntersectionObserver from Firefox 55 on desktop and Android. Firefox 52 to 54 included the implementation but kept it disabled by default behind the dom.intersection-observer.enabled flag, and Firefox 51 and earlier did not support it.

IntersectionObserver compatibility in Safari

Safari supports IntersectionObserver from Safari 12.1 on macOS and from Safari 12.2 on iOS and iPadOS. Earlier Safari versions on either platform did not support the API, so iOS 12.1 and below need the WICG polyfill.

IntersectionObserver compatibility in Opera

Opera supports IntersectionObserver from Opera 45 on desktop and from Opera Mobile 80 on Android. Opera 38 to 44 had partial support, and Opera Mini does not support IntersectionObserver in any version.

IntersectionObserver compatibility in Samsung Internet

Samsung Internet supports IntersectionObserver from Samsung Internet 7.2 on. Versions 5 to 6.4 had partial support, and Samsung Internet 4 and earlier did not support it.

IntersectionObserver compatibility in Android Browser

The WebView-based Android Browser supports IntersectionObserver from version 147 on. Older Android Browser versions did not include the API.

IntersectionObserver compatibility in Internet Explorer

Internet Explorer does not support IntersectionObserver in any version, including Internet Explorer 11. Microsoft has retired Internet Explorer, so apps that still rely on IE must ship the WICG polyfill or migrate users to Edge.

Note

Note: IntersectionObserver behavior shifts across browsers, OS, and viewport sizes. Test it on real browsers and OS with TestMu AI. Try TestMu AI free!

What are the key features of IntersectionObserver?

IntersectionObserver gives you asynchronous, batched callbacks tied to the browser's render pipeline, plus configurable visibility thresholds that fire only when the target crosses them.

  • Asynchronous, batched callbacks: The browser groups intersection updates and delivers them on its render path, so the callback never blocks the main thread the way scroll listeners do.
  • Configurable thresholds: The threshold option accepts a number or array of values from 0 to 1 representing how much of the target must be visible before the callback fires.
  • Custom root element: The root option lets you measure intersection against any scrollable ancestor instead of the viewport, which is useful for nested scroll containers and modals.
  • Root margin offsets: The rootMargin option grows or shrinks the intersection rectangle in CSS-style units, letting you trigger callbacks before the target reaches the visible edge.
  • Per-entry visibility data: Each IntersectionObserverEntry exposes isIntersecting, intersectionRatio, intersectionRect, boundingClientRect, rootBounds, target, and time for fine-grained reactions.
  • Multi-target observation: A single observer can watch many targets, and the observe, unobserve, and disconnect methods control the watch list at runtime.

What are the use cases of IntersectionObserver?

IntersectionObserver replaced expensive scroll-based visibility checks across the modern web stack and now powers a handful of patterns every team ships.

  • Lazy loading images and iframes: Defer downloading offscreen media until the target gets close to the viewport, cutting initial page weight on image-heavy pages.
  • Infinite scroll feeds: Observe a sentinel element near the end of the list and fetch the next page when it intersects, the pattern Twitter, Pinterest, and Reddit ship at scale.
  • Scroll-triggered animations and reveal effects: Add CSS classes when sections enter the viewport, without listening for every scroll frame on the main thread.
  • Video autoplay and pause: Start playback when a video clears a 50% threshold and pause when it leaves, the technique Facebook and TikTok use for inline video feeds.
  • Sticky headers and progress indicators: Detect when a heading or section anchor crosses the top of the viewport to drive sticky UI state and reading-progress bars.
  • Ad impression and engagement tracking: Confirm that an ad slot was actually visible for an IAB-compliant minimum duration before counting an impression.
...

How do you use IntersectionObserver in JavaScript?

Create an observer with a callback and an options object, then call observe on each target element. The browser invokes the callback every time a target crosses one of your thresholds.

  • Pick a target element: Get a reference to the DOM node you want to watch with document.querySelector or any other selector.
  • Define the options object: Set root (the scroll container or null for the viewport), rootMargin (CSS-style margins around the root), and threshold (a single value or array between 0 and 1).
  • Write the callback: Receive an array of IntersectionObserverEntry objects and react based on isIntersecting and intersectionRatio.
  • Construct the observer: Pass the callback and options to new IntersectionObserver and store the returned instance.
  • Observe the target: Call observer.observe(target). When you no longer need updates, call observer.unobserve(target) or observer.disconnect() to release every target at once.
// Lazy-load images as they approach the viewport
const target = document.querySelector(".lazy-image");

const options = {
  root: null,                       // null means the browser viewport
  rootMargin: "0px 0px 200px 0px",  // pre-load 200px before the bottom edge
  threshold: 0.1,                   // fire when at least 10% is visible
};

const observer = new IntersectionObserver((entries, self) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      self.unobserve(img);          // stop watching after the swap
    }
  });
}, options);

observer.observe(target);

If the callback never fires, log entries inside it first; the observer is silent until at least one threshold is crossed, including the implicit 0 threshold on the very first paint.

IntersectionObserver vs MutationObserver: What is the difference?

IntersectionObserver tracks when an element becomes visible inside a viewport or ancestor; MutationObserver tracks when the DOM tree changes. They solve different problems and often run side by side in the same app.

DimensionIntersectionObserverMutationObserver
WatchesElement visibility against a rootDOM tree changes (childList, attributes, characterData)
Common use casesLazy loading, infinite scroll, ad trackingDetecting injected DOM, attribute changes, third-party widgets
Constructor optionsroot, rootMargin, threshold, plus delay and trackVisibility for V2Passed to observe(): childList, attributes, subtree, characterData, attributeOldValue
Callback payloadIntersectionObserverEntry array (isIntersecting, intersectionRatio, rootBounds)MutationRecord array (type, addedNodes, removedNodes, attributeName)
Scope controlobserve(target), unobserve(target), disconnect()observe(target, options), disconnect(), takeRecords()
Browser support floorChrome 58, Firefox 55, Safari 12.1, Edge 16Chrome 26, Firefox 14, Safari 7, Edge 12

What are the known issues with IntersectionObserver?

IntersectionObserver covers most visibility tracking, but a few edge cases trip up even experienced teams.

  • Chrome background tabs do not fire callbacks: Chrome throttles intersection updates in inactive tabs, so the callback you expect on tab switch never arrives until the tab gets focus.
  • Cross-origin iframes return null rootBounds: When an observer runs inside an iframe with a different origin, rootBounds is null to prevent leaking layout data, so you cannot measure absolute intersection rectangles.
  • First fire happens on observe, not on intersection: The browser delivers an initial entry when you call observe, even if the target is not yet intersecting, so callbacks must check isIntersecting before reacting.
  • trackVisibility (V2) is Chromium-only: The isVisible signal that ignores occlusion and visual effects ships only in Chromium-based browsers; Safari and Firefox do not implement it.
  • Throttling on low-power devices: In my experience, mid-range Android devices delay intersection updates under heavy main-thread work, so an animation triggered at the 0.5 ratio can stutter or fire late on the first scroll.
  • Polyfill performance trails native: The WICG polyfill restores support on legacy browsers but uses scroll and resize listeners under the hood, so it loses the main performance benefit of the native API.
...

Citations

All IntersectionObserver version numbers and platform notes in this guide come from these primary sources:

Author

Prince Dewani is a Community Contributor at TestMu AI, where he manages content strategies around software testing, QA, and test automation. He is certified in Selenium, Cypress, Playwright, Appium, Automation Testing, and KaneAI. Prince has also presented academic research at the international conference PBCON-01. He further specializes in on-page SEO, bridging marketing with core testing technologies. On LinkedIn, he is followed by 4,300+ QA engineers, developers, DevOps experts, tech leaders, and AI-focused practitioners in the global testing community.

Open in ChatGPT Icon

Open in ChatGPT

Open in Claude Icon

Open in Claude

Open in Perplexity Icon

Open in Perplexity

Open in Grok Icon

Open in Grok

Open in Gemini AI Icon

Open in Gemini AI

Copied to Clipboard!
...

3000+ Browsers. One Platform.

See exactly how your site performs everywhere.

Try it free
...

Write Tests in Plain English with KaneAI

Create, debug, and evolve tests using natural language.

Try for free

Frequently asked questions

Did you find this page helpful?

More Related Hubs

TestMu AI forEnterprise

Get access to solutions built on Enterprise
grade security, privacy, & compliance

  • Advanced access controls
  • Advanced data retention rules
  • Advanced Local Testing
  • Premium Support options
  • Early access to beta features
  • Private Slack Channel
  • Unlimited Manual Accessibility DevTools Tests