Skip to content
Web Development22 September 2026 · 10 min readUpdated 30 September 2026

Why Mobile Safari Reloads Video-Heavy Pages

The reload is not a crash. It is WebKit reclaiming a tab that got too expensive. What actually costs memory on an iPhone, how to measure it on real hardware, and the pattern that fixed mine.

Why Mobile Safari Reloads Video-Heavy Pages

What you'll learn

  • Why does Safari keep reloading a page on iPhone when it has several videos?
  • How do you measure this instead of guessing?
  • What pattern keeps a video-heavy page alive on iOS?
Article contents

The page did not crash at random; the iPhone was protecting itself from the page.

That distinction changes what you go looking for. A crash is a defect in your code. A reload is a decision WebKit made on your behalf, under pressure, after the tab asked for more memory than the system was willing to keep handing it. Safari's banner about a problem repeatedly occurring reads like a crash report. The honest translation is that the tab got too expensive and the operating system took the money back.

You have probably shipped this bug. Desktop is fine, Lighthouse is green, then someone opens the site on an iPhone, scrolls past the section with four autoplaying clips, and the page blinks white and starts over from the top.

How many video elements does your heaviest section mount at once? Most people cannot answer that, which is the actual problem. Count them first, then read on.

Why does Safari keep reloading a page on iPhone when it has several videos?

Safari keeps reloading the page because WebKit discards a tab whose memory footprint exceeds what the device can hold, and several decoded videos push a tab over that line quickly.

A heavy concrete freight-lift door jammed half-open against an overloaded pallet of grey blocks, its black rubber seal deformed where it presses into the top block, with a chain coiled on the gritty threshold

There is no single published number you can code against. The ceiling moves with the device, the iOS version, how much pressure other apps are putting on the system, and what your page is holding in graphics memory at that moment. Anyone quoting you a hard megabyte limit is repeating one measurement from one device on one afternoon.

What you can reason about is the shape of the pressure. WebKit's own memory debugging guide for Web Inspector splits a page into four lanes: JavaScript, Images ("decoded image data"), Layers ("WebKit's tile grid, page content using compositing layers"), and Page for everything else. A media-heavy landing page pushes on three of those at once. Your JavaScript heap is usually the innocent one, which is why heap profiling alone finds nothing and everyone concludes the framework is haunted.

A smooth desktop scroll animation can still be a mobile memory leak

A smooth desktop scroll animation can still be a mobile memory leak with good frame timing. Sixty frames per second tells you the compositor kept up. It tells you nothing about how much memory the compositor had to allocate to get there.

A polished concrete ramp lit by low sun, its top surface mirror-smooth while the joint where it meets the ground falls into deep shadow, a chipped enamel mug left on the raw concrete handrail

Pinned sections are the usual culprit. You take a tall scroll container, pin a stack of project cards inside it, and animate between them as the user scrolls. On a desktop GPU with gigabytes of headroom that is a pleasant effect. On a phone it means every card in the stack is laid out at once, composited into its own layer, and holding a decoded frame buffer if the card carries a video.

The frame timing stays good right up to the moment the page disappears. That is the trap. Your performance instinct is trained on jank, and this failure mode has none.

What actually stacks up in memory?

Decoded video frames, poster images and compositing layers stack up, and a small file on the wire becomes a large allocation once decoded.

The clearest public numbers here are old and still directionally useful. In an August 2014 WHATWG mailing-list thread, Duan Yao measured per-element video memory with 720p to 1080p H.264 files and reported that "for each playing or paused or preload=auto video element, the memory usage is up to 3080MB; for those with preload=metadata, memory usage is 613MB; for those with preload=none, memory usage is not notable."

Six clips at preload="auto" would add up to 180 to 480 MB on that measurement. Treat it as a direction rather than a budget, because it comes from 2014 browsers and hardware, and posters and compositing layers are separate line items on top.

What the element holdsPer-element cost (2014 measurement)When it is the right call
preload="none"Not notableAny clip that is not currently on screen
preload="metadata"6–13 MBA clip whose duration or dimensions you need before playback
preload="auto", playing or paused30–80 MBThe one clip the user is actually looking at

Read the third column first. The decision is not which value is best, but how many elements are allowed to sit in the expensive row at the same time.

The same message contains the sentence most people get wrong: "Even if a video element is or becomes invisible, either by being out of viewport, having display:none style, or being removed from the active DOM tree (but not released), almost same amount of memory is still occupied."

Hiding is not unloading.

How do you measure this instead of guessing?

Measure by removing one media system at a time on a physical iPhone until the reload stops, then adding each one back until it returns.

Tooling first. Connect the phone by cable, enable Web Inspector on the device, and attach Safari on the Mac. In Timelines, the Memory lane gives you that four-category breakdown and the JavaScript Allocations lane gives you heap snapshots. WebKit's guide also describes how to separate a real leak from normal churn: repeat a memory-neutral action and compare snapshots. "If you perform the action five times and memory only increased the first time, then there likely isn't a problem, but if you saw a steady increase each time, then you've likely uncovered a leak."

Then the plan itself:

  1. Reproduce on a real device, three times, on the same route. A reload you cannot trigger twice is not yet a bug you can fix.
  2. Record a Memory timeline across the failing scroll and note which lane climbs. Layers climbing points at compositing. Images climbing points at decode. Page climbing usually points at retained DOM.
  3. Turn off autoplay on every video and scroll again. If the reload stops, the problem is concurrent decode rather than your animation code.
  4. Restore autoplay and remove the pinned scroll section instead. If the reload stops now, the problem is layer count.
  5. Restore both and halve your poster dimensions. If that alone buys stability, you were paying to decode posters far larger than the box they render into.
  6. Add one system back at a time until the reload returns. The last thing you added is the thing to redesign, not the thing to micro-optimize.

Desktop responsive mode will not reproduce any of this. It has your laptop's memory.

Is this a WebKit bug or my bug?

Usually yours, because in my reading, discarding a page under memory pressure is expected behavior on a memory-constrained device rather than a defect you can file. The exceptions have known signatures. Developers reported in 2021 and 2022 that from Safari 15 on iOS, pointing a video src at a blob URL caused the blob to be re-fetched repeatedly until Safari reloaded the page, with no equivalent on macOS, and the thread records no fix. Search your exact symptom before you rewrite an architecture.

What pattern keeps a video-heavy page alive on iOS?

Attach a video source only to the card the visitor is looking at and unload every other source, because pausing a video does not release the memory it holds.

Here is how that went on this portfolio.

On my portfolio, the iPhone repeatedly became unstable around the media-heavy project and ecosystem sections even though desktop performance looked fine. The fix was architectural: mobile stopped using the giant pinned project stack, and only the visible project card kept a video source attached. Pausing hidden videos was not enough; unloading their sources was what stopped decoded media from accumulating.

Unloading means clearing the source and telling the element to forget it, not merely pausing:

function unload(video) {
  video.pause();
  video.removeAttribute("src");
  while (video.firstChild) video.removeChild(video.firstChild);
  video.load(); // forces the element to drop the previous resource
}

The load() call is the part people skip. Without it the element can hold onto the previous resource, and on some iOS versions it will re-fetch the URL you thought you had just removed.

Four rules came out of that work, and I apply them by default now:

  • One source at a time. Only the active card gets a src. Every other card is an empty <video> with a poster, waiting its turn.
  • Mobile gets document flow, not a pinned stack. Scroll choreography is a desktop feature. On a phone those sections render as ordinary stacked blocks, which are cheaper to composite and easier to read with one thumb. The Elpida Solutions real-estate website goes a step further and ships separate landscape and portrait media, and I wrote up the crop side of that decision in portrait vs landscape hero media on mobile.
  • Posters stay small. A poster is decoded image data in the Images lane whether or not the clip ever plays. Size it for its container.
  • Respect prefers-reduced-motion. Users who set it get the static composition, which is also the low-memory path.

None of this is exotic. It is the same discipline as keeping a Flutter list smooth when it is full of images and animations: decide what is allowed to be expensive right now, and make everything else cheap by construction.

Which fixes are not fixes?

Four things look like solutions and are not.

Setting display: none. The element keeps its memory, as the measurement above spells out. If your fix was a CSS class, you did not fix it.

Preloading every clip so playback feels instant. By the 2014 numbers above, every preload="auto" element is one of the most expensive rows on the page. Instant playback on a page that reloads is a worse experience than two hundred milliseconds of delay on a page that survives.

Validating in desktop responsive mode. It catches layout bugs and tells you nothing about memory.

Blaming the framework. If the site is a Next.js build, the framework is not deciding how many video elements you mount. You are.

What did Safari 26 change?

Safari 26.0, released on 15 September 2025, shipped scroll-driven animations, which tie a CSS animation to scroll position or to an element's progress through the viewport via animation-timeline and animation-range.

Scroll-driven animations do not shrink your videos. What they can remove is the scaffolding built around scroll effects: the tall pinned container, the JavaScript scroll listener, the extra wrapper elements that each earn a compositing layer. This suggests less work in the Layers lane, though you should confirm that in your own Memory timeline rather than assume it.

Do not read that as permission. If the cheaper animation tempts you into a longer, denser scroll story, you land back where you started with better frame timing.

One more thing that is not a bug. WebKit's inline video policy for iOS states that autoplay elements "will only begin playing when visible on-screen" and "will pause if they become non-visible." That pausing is correct behavior, and it is not the same as releasing memory. Reading the policy and assuming the platform cleans up for you is an easy mistake.

What should you check on an iPhone before you ship?

Run a repeatable pass on a physical iPhone in portrait and landscape, scrolling in both directions, and watch the Memory timeline for a staircase that signals a leak.

Use a physical device rather than the simulator.

  1. Portrait, full page top to bottom, twice.
  2. Landscape, same route, same two passes.
  3. Scroll back upward through every media section. Upward passes re-enter sections in a different order and catch cleanup that only ever runs one way.
  4. Switch to another Safari tab, wait thirty seconds, switch back. A page discarded here suggests it was already sitting near the ceiling.
  5. Lock the phone, wake it, and return to the tab.
  6. Repeat your worst section five times while watching the Memory timeline. A flat line is fine. A staircase is not.
  7. Re-run the whole list with Low Power Mode on.

If step 6 draws a staircase, stop optimizing and go back to the architecture question: how many media elements are alive at once, and who is responsible for killing them?

That is the question every real fix answers. The static, tracker-free chess club website for Šahovski klub Dubica keeps its hero video paused offscreen and gives reduced-motion or data-saving visitors a still image, so constraint is the default and cleanup is the exception. Load cost matters on the same devices, and getting a Webflow site under one second covers that side.

Open your own site on an iPhone now, scroll to the heaviest section, and count the video elements currently holding a source. If that number is larger than one, you already know what you are doing this afternoon.

Free resource

Free SaaS MVP Scope Template

A Notion document with the full feature checklist, MVP vs. nice-to-have table, pre-build questions, and cost signals — so you walk into any developer call knowing exactly what to ask for.

Get the template →
DL

Dusko Licanin

Full-Stack Developer · Banja Luka, Bosnia

Full-stack developer shipping SaaS MVPs, web apps, and mobile apps using AI-augmented workflows — without agency coordination overhead. Live portfolio: BookBed, Callidus, Pizzeria Bestek.

Frequently Asked Questions

Why does Safari keep reloading a page on my iPhone while I scroll?

Scrolling is when the page finally asks for everything it was always going to need, so that is usually where WebKit runs out of room and discards the tab. Sections below the fold mount their video elements, decode their posters and build compositing layers as they enter the viewport. A page that opens cleanly can cross the ceiling halfway down. The useful diagnostic is repetition. If the reload lands at the same section on every pass, that section owns the problem and the rest of the page is fine. If it lands in a different place each time, you are leaking rather than overspending, and the Web Inspector heap snapshot workflow is the faster route.

Does pausing a video free memory on iOS Safari?

No, a paused video element holds roughly the same memory as a playing one, and hiding it with display:none does not help either. The clearest public figure is still Duan Yao's 2014 WHATWG measurement, which put a playing, paused or preload=auto element at up to 30-80 MB each and noted that an invisible or detached element keeps almost the same footprint. To actually release the resource you clear the element's source and call load(), which tells it to drop what it was holding. Pausing changes playback state. Unloading changes memory, and only the second one keeps you under the ceiling.

How many videos can one mobile Safari page safely hold?

There is no safe number you can look up, but the practical design target is one element holding a source at any given moment. The ceiling moves with the device, the iOS version, what other apps are doing and how much graphics memory your own layout already consumes, so any fixed megabyte figure is one measurement from one phone on one day. Build for the constraint instead. Give the visible element a source, leave every other element as an empty tag with a small poster, and unload sources as cards leave the viewport. A page built that way survives the phone you never got to test on.

How do I debug Safari video memory pressure on a real iPhone?

Connect the iPhone by cable, enable Web Inspector on the device, and record a Memory timeline in Safari on the Mac while you reproduce the reload. The Memory lane separates JavaScript, Images, Layers and Page, which tells you whether you are paying for decode, for compositing or for retained DOM. Then repeat the same interaction five times and compare heap snapshots. Memory that rises once and settles is normal churn; memory that rises on every pass is a leak. Do all of it on hardware. Desktop responsive mode runs on your laptop's memory and will never reproduce the failure you are chasing.

Will lazy loading videos stop an iOS website from reloading?

Only if it also unloads, because the reload is caused by how many elements hold decoded media at once, not by how many were fetched at startup. Deferring the initial request lowers your first-load cost and does nothing for the steady state once a user has scrolled through every section and mounted all of them. The pattern that actually works runs in both directions: attach a source when a card becomes active, and clear that source when it stops being active. Most lazy-loading implementations only ever do the first half, which is why the reload survives them.