Skip to main content

Test with real mobile CPU and network throttling

Mobile devices have weaker CPUs, less memory, and higher-latency connections than desktops. These constraints amplify every performance issue. What loads in a fraction of a second on a desktop can take several times longer on a mid-range phone. This page covers mobile-specific concerns that the individual best practice pages on images, scripts, fonts, or responsive design don't address.


Mobile traffic represents the majority of ecommerce visits. Hardware and network differences drive the performance gap between desktop and mobile, and they affect every metric, but especially LCP, INP, and TBT.

Mobile processors parse and execute JavaScript significantly slower than desktop processors. Chrome DevTools uses a 4× CPU slowdown to approximate a mid-range Android phone, which reflects the real gap. A script that executes in 50 ms on a desktop might take 200 ms or more on a phone, turning a minor cost into a noticeable delay.

Even on fast cellular connections, round-trip latency is higher than wired broadband. Each network request carries more overhead. This makes request count and resource prioritization more impactful on mobile than on desktop.

Phones throttle CPU and GPU performance as they heat up during sustained use. A page that performs well on first load can degrade during extended browsing sessions, especially on product-heavy collection pages or stores with complex interactive features.

Mobile browsers operate with less available RAM. Large DOM trees, multiple high-resolution images decoded simultaneously, and heavy JavaScript heaps increase the chance of the browser discarding cached resources or slowing down garbage collection.


Anchor to Test on representative devicesTest on representative devices

Lab testing on a fast desktop with no throttling tells you nothing about mobile performance. Use throttling settings that approximate real-world conditions.

Anchor to Chrome DevTools throttlingChrome DevTools throttling

  1. Open DevTools and switch to the Performance panel.
  2. Set CPU throttling to 4x slowdown. This approximates a mid-range Android phone in the Moto G Power class.
  3. In the Network panel, set throttling to Slow 4G (download 1.6 Mbps, upload 750 Kbps, 150 ms RTT).
  4. Enable Device Mode and select a phone viewport like Moto G Power or Samsung Galaxy S8.

CPU and network throttling stack, so enable both at the same time to get a realistic picture. A 4× CPU slowdown alone still uses your desktop's network, and network throttling alone still uses your desktop's CPU.

Emulation approximates but doesn't replicate real device behavior. Thermal throttling, OS-level background processes, and actual touch input latency only show up on real hardware. Keep a mid-range Android phone for testing. Phones in the Moto G or Samsung Galaxy A series represent a large share of real-world ecommerce traffic.

Anchor to Reduce JavaScript execution on mobileReduce JavaScript execution on mobile

JavaScript execution cost is the single largest multiplier between desktop and mobile performance. The CPU gap amplifies every millisecond of script parsing, compilation, and execution.

Other pages cover the individual techniques: Defer non-critical scripts and Load JavaScript on user interaction. On mobile, the priority is reducing how much JavaScript runs during page load.

Anchor to Conditionally load mobile-specific code with dynamic importConditionally load mobile-specific code with dynamic import

if (window.matchMedia('(max-width: 749px)').matches) {
import('./mobile-nav.js').then(({ init }) => init());
}

This avoids loading desktop-only code on mobile, and avoids loading mobile-only code on desktop.

Anchor to Prioritize visible content for mobile viewportsPrioritize visible content for mobile viewports

Mobile viewports are smaller, so fewer images are visible on initial load. Use mobile-first sizes attributes so the browser selects the smallest appropriate source for the screen.

{{ product.featured_image
| image_url: width: 800
| image_tag:
loading: image_loading,
widths: '200, 400, 600, 800',
sizes: '(min-width: 750px) calc(50vw - 2rem), calc(100vw - 2rem)'
}}

The sizes attribute above tells the browser: on screens narrower than 750px, the image fills nearly the full viewport width. On wider screens, it fills about half. This prevents mobile devices from downloading images sized for desktop layouts.

For detailed sizes patterns, see Use responsive images.

Anchor to Minimize main-thread work during loadMinimize main-thread work during load

On mobile, long tasks, anything over 50 ms, block the main thread and delay interactivity. Common sources in themes:

  • Third-party app scripts that execute synchronously on load.
  • Large inline <script> blocks that serialize settings objects.
  • Event listeners attached to hundreds of DOM elements instead of using delegation.

See Understanding INP and Debounce and throttle event handlers for techniques to reduce main-thread blocking.


Anchor to Mobile-first section loading with ,[object Object]Mobile-first section loading with section.index

On mobile, fewer sections are visible above the fold. Use section.index to eagerly load only the first sections, and defer everything else.

Test the below-the-fold case positively with section.index > 2. section.index is nil in static sections, in the online store editor, and in Section Rendering API responses, and comparisons against nil are falsey, so if section.index <= 2 would lazy-load the first sections in exactly those contexts. See Use section.index for position-aware optimizations:

{%- liquid
# Test the below-the-fold case positively so a nil section.index stays eager.
if section.index > 2
assign section_loading = 'lazy'
else
assign section_loading = 'eager'
endif
-%}

{{ section.settings.image
| image_url: width: 1200
| image_tag:
loading: section_loading,
widths: '400, 600, 800, 1200',
sizes: '(min-width: 750px) 50vw, 100vw'
}}

Anchor to Conditional script loading by templateConditional script loading by template

Avoid loading scripts globally when they're needed only on specific page types:

{% if template.name == 'product' %}
<script src="{{ 'product-media.js' | asset_url }}" defer></script>
{% endif %}

On mobile, where every kilobyte of JavaScript has an outsized cost, this prevents product page scripts from being parsed on collection or homepage loads.


Anchor to Chrome DevTools with throttlingChrome DevTools with throttling

Set CPU to 4x slowdown and network to Slow 4G. Run a Performance panel recording and look at the Total Blocking Time metric. Sort the Bottom-Up tab by Self Time to find the most expensive scripts.

Anchor to WebPageTest with a mobile profileWebPageTest with a mobile profile

Use the Moto G4 test agent with a 4G connection. The filmstrip view shows exactly when content becomes visible. Compare the mobile waterfall against desktop to identify mobile-specific bottlenecks.

Anchor to Lighthouse mobile presetLighthouse mobile preset

Lighthouse's default mobile configuration applies CPU throttling and simulated network throttling. Run it from DevTools or the command line. Focus on the Reduce JavaScript execution time and Minimize main-thread work diagnostics.

Anchor to Field data comparisonField data comparison

In the Shopify Web Performance Dashboard, compare mobile and desktop Core Web Vitals side by side. A large gap between mobile and desktop LCP or INP indicates mobile-specific issues that lab testing can help debug.



Was this page helpful?