---
title: Remove or optimize apps causing render-blocking issues
description: >-
  Identify, remove, or defer third-party apps that inject render-blocking
  JavaScript or CSS to reduce the latency those resources add to the critical
  rendering path.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/remove-render-blocking-apps
  md: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/remove-render-blocking-apps.md
api_name: liquid
---

# Remove or optimize apps causing render-blocking issues

Third-party apps that inject render-blocking JavaScript or CSS can significantly delay page rendering, increasing First Contentful Paint and Largest Contentful Paint times. Identifying and optimizing or removing these apps improves the initial page load performance.

***

## Why

Render-blocking resources prevent the browser from displaying content until the resource has been downloaded, parsed, and executed. Each render-blocking app adds latency to the critical rendering path, delaying when customers see meaningful content.

Third-party apps are common culprits because:

* **Synchronous script loading**: Many apps inject `<script>` tags without `async` or `defer` attributes.
* **Critical CSS bloat**: Apps often add CSS that blocks rendering even if it's not immediately visible.
* **Multiple HTTP requests**: Each app typically requires separate resource requests.
* **Unoptimized delivery**: Third-party resources might not be served from optimized CDNs.
* **Cascading dependencies**: Apps can load additional resources synchronously.

Third-party code is a large part of that latency. The [Web Almanac 2022 third parties chapter](https://almanac.httparchive.org/en/2022/third-parties) reports an average median blocking time of 1.4 seconds across the 10 most popular third parties, so a page that loads several of them can spend seconds blocked before it paints.

***

## How

### Audit installed apps

Identify render-blocking resources:

1. Run a Lighthouse audit:

   * Open Chrome DevTools.
   * Navigate to the **Lighthouse** tab.
   * Run the **Performance** audit.
   * Check **Eliminate render-blocking resources**.
   * Note all third-party scripts and stylesheets.

2. Use WebPageTest:

   * Test the page at [`https://webpagetest.org`](https://webpagetest.org).
   * Review the waterfall chart.
   * Identify resources that block rendering (red bars).
   * Note third-party domains.

3. Check the **Network** panel:

   * Open the Chrome DevTools **Network** tab.
   * Reload the page.
   * Filter by **JS** and **CSS**.
   * Sort by **Waterfall** to see blocking resources.
   * Identify third-party domains from Shopify app vendors.

Common render-blocking app types:

* **Chat widgets**: Intercom, Drift, Zendesk Chat.
* **Review apps**: Yotpo, Judge.me, Loox.
* **Email capture**: Klaviyo, Privy, Justuno.
* **Analytics**: Google Analytics, Facebook Pixel, Hotjar.
* **A/B testing**: Optimizely, VWO.
* **Recommendation engines**: LimeSpot, Wiser, Nosto.

### Evaluate app necessity

Decision framework:

For each render-blocking app, ask:

1. Is this app actively used? Check usage metrics in the app dashboard, review the last configuration date, and confirm the business value.
2. Does it need to load on every page? Can it be limited to specific pages or loaded conditionally?
3. Is there a lighter alternative? Consider native Shopify features, theme-integrated solutions, or more performant apps.
4. Can it be deferred? Does it need to render immediately, or can it load after the initial paint?

Priority for removal:

1. **High priority** (remove immediately):

   * Unused or rarely used apps.
   * Apps with duplicate functionality.
   * Apps with native Shopify alternatives.
   * Apps causing 500 ms or more of blocking time.

2. **Medium priority** (optimize or replace):

   * Apps used occasionally.
   * Apps with async loading options.
   * Apps that can be conditionally loaded.

3. **Low priority** (optimize only):

   * Business-critical apps.
   * Apps with no alternatives.
   * Apps with minimal blocking time (under 100 ms).

### Optimize remaining apps

Defer non-critical apps:

```liquid
{%- comment -%}
Load app scripts after page interactive
{%- endcomment -%}


<script>
  // Defer app loading until after the page loads
  window.addEventListener('load', function() {
    // Load the chat widget after the page loads
    var script = document.createElement('script');
    script.src = 'https://widget.app.com/script.js';
    script.async = true;
    document.head.appendChild(script);
  });
</script>
```

Conditional loading by page type:

```liquid
{%- comment -%}
Load the review app only on product pages
{%- endcomment -%}


{% if template.name == 'product' %}
  {{ 'review-app.css' | asset_url | stylesheet_tag }}
  <script src="https://reviews.app.com/widget.js" defer></script>
{% endif %}
```

Lazy load apps outside the initial viewport:

```liquid
{%- comment -%}
Load the email capture dialog only when the customer scrolls
{%- endcomment -%}


<script>
  var emailAppLoaded = false;


  function loadEmailApp() {
    if (emailAppLoaded) return;
    emailAppLoaded = true;


    var script = document.createElement('script');
    script.src = 'https://email.app.com/popup.js';
    document.head.appendChild(script);
  }


  // Load on scroll
  window.addEventListener('scroll', loadEmailApp, { once: true });


  // Fallback: load after 5 seconds
  setTimeout(loadEmailApp, 5000);
</script>
```

Use the facade pattern for heavy widgets:

```liquid
{%- comment -%}
Show a lightweight placeholder, then load the real widget on interaction
{%- endcomment -%}


<div id="chat-facade" onclick="loadRealChat()">
  <button class="chat-button">Chat with us</button>
</div>


<script>
  function loadRealChat() {
    var facade = document.getElementById('chat-facade');
    facade.style.display = 'none';


    var script = document.createElement('script');
    script.src = 'https://chat.app.com/widget.js';
    script.onload = function() {
      // Initialize chat widget
      ChatApp.init({ /* config */ });
    };
    document.head.appendChild(script);
  }
</script>


<style>
  .chat-button {
    position: fixed;
    bottom: 20px;
    right: 20px;
    padding: 12px 24px;
    background: #0066cc;
    color: white;
    border: none;
    border-radius: 24px;
    cursor: pointer;
  }
</style>
```

### Replace with native alternatives

Review apps to standard review metafields:

If an app writes to the standard `reviews` metafield namespace, then you can render the rating and review count from Liquid, so the summary displays without waiting for the app's script. `reviews.rating` is a [`rating`](https://shopify.dev/docs/api/liquid/objects/rating) type metafield, so its value is an object: read the number from `.value.rating` and the scale from `.value.scale_max`. Outputting the metafield directly renders the raw stored JSON.

```liquid
{%- comment -%}
Render the rating from standard metafields instead of a third-party widget
{%- endcomment -%}


{% if product.metafields.reviews.rating.value != blank %}
  <div class="product-reviews">
    <h3>Customer reviews</h3>
    <span class="stars">
      {{ product.metafields.reviews.rating.value.rating }} out of
      {{ product.metafields.reviews.rating.value.scale_max }}
    </span>
    <span class="count">({{ product.metafields.reviews.rating_count }} reviews)</span>
  </div>
{% endif %}
```

Email capture to a native email signup form:

```liquid
{%- comment -%}
Simple native email form instead of a heavy popup app
{%- endcomment -%}


{% form 'customer' %}
  <div class="newsletter-signup">
    <h3>Join our newsletter</h3>
    <input type="email" name="contact[email]" placeholder="Your email">
    <button type="submit">Subscribe</button>
  </div>
{% endform %}
```

Analytics to Shopify Analytics:

Use Shopify's native analytics instead of multiple third-party tracking scripts. Shopify Analytics provides traffic sources, conversion tracking, customer behavior, and sales attribution.

For advanced needs, use Google Analytics 4 with async loading:

```html
<!-- Google Analytics 4 with async loading -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX');
</script>
```

***

## Examples

### Example 1: Remove an unused review app

Before (render-blocking):

```html
<!-- Yotpo reviews loading synchronously -->
<link rel="stylesheet" href="https://staticw2.yotpo.com/widget.css">
<script src="https://staticw2.yotpo.com/widget.js"></script>
<!-- Blocks rendering by 450 ms -->
```

After (removed, using native reviews):

```liquid
{% if product.metafields.reviews.rating.value != blank %}
  <div class="product-rating">
    <span class="stars">
      {{ product.metafields.reviews.rating.value.rating }} out of
      {{ product.metafields.reviews.rating.value.scale_max }}
    </span>
    <span class="count">({{ product.metafields.reviews.rating_count }} reviews)</span>
  </div>
{% endif %}
<!-- No render blocking, instant display -->
```

### Example 2: Defer a chat widget

Before (render-blocking):

```html
<!-- Intercom loading synchronously -->
<script src="https://widget.intercom.io/widget/{app_id}"></script>
<!-- Blocks rendering by 320 ms -->
```

After (deferred with facade):

```html
<!-- Lightweight facade -->
<div id="chat-facade" onclick="loadIntercom()">
  <svg class="chat-icon"><!-- icon --></svg>
</div>


<script>
  var intercomLoaded = false;
  function loadIntercom() {
    if (intercomLoaded) return;
    intercomLoaded = true;


    var script = document.createElement('script');
    script.src = 'https://widget.intercom.io/widget/{app_id}';
    document.head.appendChild(script);


    document.getElementById('chat-facade').style.display = 'none';
  }


  // Auto-load after 10 seconds if not clicked
  setTimeout(loadIntercom, 10000);
</script>
<!-- No initial render blocking -->
```

### Example 3: Conditional app loading

Before (loads everywhere):

```liquid
<!-- Size chart app loads on all pages -->
{{ 'size-chart.css' | asset_url | stylesheet_tag }}
<script src="{{ 'size-chart.js' | asset_url }}"></script>
<!-- Blocks rendering on all pages by 180 ms -->
```

After (product pages only):

```liquid
{% if template.name == 'product' and product.type == 'Apparel' %}
  <!-- Only load on apparel product pages -->
  <link rel="stylesheet" href="{{ 'size-chart.css' | asset_url }}" media="print" onload="this.media='all'">
  <script src="{{ 'size-chart.js' | asset_url }}" defer></script>
{% endif %}
<!-- No blocking on other pages, minimal blocking on relevant pages -->
```

***

## Testing

1. **Lighthouse audit**:

   * Run before and after optimization.
   * Check **Eliminate render-blocking resources**.
   * Verify FCP and LCP improvements.
   * Target: Remove all non-critical blocking resources.

2. **WebPageTest**:

   * Compare waterfall charts before and after.
   * Check the Start Render time improvement.
   * Verify that no new blocking resources were introduced.
   * Target: 500 ms or more of improvement in Start Render.

3. **Chrome DevTools Coverage**:

   * Open the **Coverage** tab (Cmd+Shift+P, then `Coverage`).
   * Record a page load.
   * Identify unused CSS and JavaScript from apps.
   * Verify that removed apps no longer appear.

4. **Real user monitoring**:

   * Monitor FCP and LCP in Shopify Analytics.
   * Track before and after metrics for two or more weeks.
   * Check the conversion rate impact.
   * Target: 10 to 20 percent improvement in Core Web Vitals.

5. **Functionality testing**:

   * Test that all remaining apps work correctly.
   * Verify that deferred apps load properly.
   * Check that conditional loading triggers correctly.
   * Test on multiple devices and browsers.

6. **Business metrics**:

   * Monitor app-specific metrics, such as reviews and chat.
   * Verify no drop in app engagement.
   * Check that conversion rates remain stable or improve.
   * Track customer feedback.

***

## References

* [Shopify app performance best practices](https://shopify.dev/docs/apps/best-practices/performance).
* [Eliminate render-blocking resources](https://web.dev/render-blocking-resources/) on web.dev.
* [Chrome DevTools Coverage tool](https://developer.chrome.com/docs/devtools/coverage/).
* [HTTP Archive: third-party impact](https://almanac.httparchive.org/en/2022/third-parties).
* [Managing apps](https://help.shopify.com/en/manual/apps/managing-apps) in the Shopify Help Center.

***
