Blog
/
Guides & Tutorials

Building for Shopify: How to improve your LCP score when developing apps with Gadget

Published
June 13, 2024
Last updated
December 20, 2024
Get some key tips and insights on how to achieve page load scores that will earn the Built for Shopify badge for your public app.
TL;DR: Lowering your LCP score is one of the biggest factors in reducing load times for your app, and we’ve got tips to help you keep it as low as possible.

Whether you’re a developer, consumer, or a merchant, we can all agree on one thing: webpage load times need to be fast. And when it comes to building Shopify apps, it’s not just a preference, it’s a necessity.

No one wants to wait around for images and data to load. People expect speed, and when apps or webpages take more than 5 seconds to load, the probability of users just walking, clicking, tapping, or swiping away dramatically increases. Studies and user research from the past decade (1, 2, some 2 data but not paywalled) make it clear that an efficient first render is a crucial part of the user experience for many people. 

There are a myriad of factors that can affect page speed, so app developers should track their core web vitals to measure app loading speeds to understand which areas need improvement. One of these web vitals is the LCP score.

What is LCP?

Your app’s LCP score, or largest contentful paint, helps measure the perceived loading speed of a web page. It measures the time it takes for the largest content element, such as an image or block of text, to be fully rendered for users.

LCP is a good indicator of when users can start interacting with a page. A good score is typically under 2.5 seconds, with lower being better. Some ecosystems even use this LCP target as a requirement for any certifications. For example, when building a public Shopify app, an average LCP score of under 2.5 seconds is required in order to achieve the lucrative “Built for Shopify” badge, which will be added to an app listing as a sign of quality, making it more attractive to potential users.

Measuring your LCP

The first step when looking into page load performance is always to measure your app’s current web vital scores, including LCP. For many web apps, Google’s PageSpeed Insights or Lighthouse scores make it easy to get an initial measurement. Plus, these tools will give you suggestions for what you can do to improve your scores.

For some apps, however, this can be a challenge. Merchant-facing Shopify apps are embedded in an <inline-code>iframe<inline-code>, and since PageSpeed Insights and Lighthouse measure vitals for the whole page, that includes the Shopify store admin in addition to your application. So we need a way to only measure the web vitals and LCP score for an application, not the whole window.

To do this, we can install the <inline-code>web-vitals<inline-code> npm package from Google in our app. Open the Gadget command palette and run the following command:

Terminal

Once this package is installed, we can get our app’s LCP score by using the provided <inline-code>onLCP()<inline-code> function:

JavaScript

When measuring LCP on a production app, you want to capture and send the LCP values back to a database so the scores can be analyzed for real users over time.

Once you have your baseline LCP score, you can start making improvements.

Gotta draw fast (improve your LCP score)

We have 4 tips for improving your LCP on any Gadget app, plus a Shopify-app specific suggestion for getting that “Built for Shopify” badge:

  1. Update Gadget-provided packages and framework version
  2. Optimize image loading
  3. Optimize font loading
  4. Make your bundle smaller
  5. (Shopify) Use the <inline-code>/api/shopify/install-or-render<inline-code> app URL

1. Keep your app up to date on the latest Gadget-provided packages and Gadget framework version

We’re constantly improving the size and speed of our Gadget-provided npm packages used to power your app. This includes your app’s API client, and upgrading to Gadget framework v1.1 can reduce client package size by up to 30%! Keeping these packages up-to-date is an easy way to make sure you are getting the best performance out of Gadget.

Upgrading Gadget-provided packages to the latest version can be done in a single step. Just open the Gadget command palette and run the Update Gadget-provided packages command. Gadget will update the packages, <inline-code>yarn<inline-code> will run, and your app will automatically get any performance improvements we’ve baked into the newest version.

It’s a similar story for framework version upgrades, just go to Settings → Framework version → Edit and select the latest version. Once again, everything will be updated for you automatically, and you will get any performance updates included without having to manually update any under-the-hood dependencies.

2. Optimize image loading

Images are often the largest content element on a landing or home page. And high-resolution images on modern websites can be hefty. Making sure images are an appropriate size (don’t use CSS to scale down huge images!) and file format (<inline-code>.webp<inline-code> for smaller storage size), and compressing images using tools like TinyPNG can all help to improve LCP.

Lazy-loading images that are not immediately visible can also be helpful, and are easy to add with a simple <inline-code>loading=”lazy”<inline-code> attribute to an <inline-code>img<inline-code> element:

Terminal

3. Optimize font loading

If you’re using fancy fonts for your app, another possible culprit for the largest content element could be a block of text on a webpage. Similar to images, storing fonts in an optimized format, such as <inline-code>WOFF2<inline-code> will help with loading times and LCP. It also helps to reduce the number of custom fonts being loaded onto a single page.

Another option to optimize font loading is to use <inline-code>@font-face<inline-code> to declare fonts in CSS and use a <inline-code>font-display<inline-code> strategy to load fonts faster and prevent blocking during the first paint. For example, <inline-code>font-display: “swap”<inline-code> will use a system font while the custom font is being loaded.

Terminal



  

-->

Finally, you can self-host your fonts in your Gadget apps! By including fonts as static assets, Gadget can load them from its high-performance CDN.

4. Reduce bundle size

All your files and dependencies are bundled together and served to your frontend, and in this context, size definitely matters. A larger bundle takes a longer time to load and parse, so keeping bundles slim and trim helps with LCP.

Gadget optimizes production bundles for you, but you can use a tool like <inline-code>vite-bundle-analyzer<inline-code> to see if there are any unnecessary dependencies that can be removed from your app.

You can also use <inline-code>React.lazy<inline-code> to lazy-load components that aren’t required in the initial render. And don’t forget to use the <inline-code>Suspense<inline-code> component to avoid layout shift!

Terminal

5. Shopify tip: `/api/shopify/install-or-render` app URL

Gadget provides an optimized route for Shopify apps to minimize redirects and eliminate the cold boot time encountered with serverless solutions. Using this URL for your Shopify app URL in the Partners dashboard will improve LCP for any Shopify apps you build, and get you one step closer to that Built for Shopify badge.

For example:

Terminal

This route is used by default on all new Gadget apps. Older apps built with Gadget can change their app URL to take advantage of this route and improve LCP. More information can be found in our Shopify OAuth guide.

Follow these steps to improve your app’s LCP, delight customers, and get that Built with Shopify badge!

If you want to learn more about web vitals and LCP, check out the docs at web.dev and our Gadget guide to LCP optimization.

Building for Shopify: How to improve your LCP score when developing apps with Gadget

Get some key tips and insights on how to achieve page load scores that will earn the Built for Shopify badge for your public app.
Problem
Solution
Result
TL;DR: Lowering your LCP score is one of the biggest factors in reducing load times for your app, and we’ve got tips to help you keep it as low as possible.

Whether you’re a developer, consumer, or a merchant, we can all agree on one thing: webpage load times need to be fast. And when it comes to building Shopify apps, it’s not just a preference, it’s a necessity.

No one wants to wait around for images and data to load. People expect speed, and when apps or webpages take more than 5 seconds to load, the probability of users just walking, clicking, tapping, or swiping away dramatically increases. Studies and user research from the past decade (1, 2, some 2 data but not paywalled) make it clear that an efficient first render is a crucial part of the user experience for many people. 

There are a myriad of factors that can affect page speed, so app developers should track their core web vitals to measure app loading speeds to understand which areas need improvement. One of these web vitals is the LCP score.

What is LCP?

Your app’s LCP score, or largest contentful paint, helps measure the perceived loading speed of a web page. It measures the time it takes for the largest content element, such as an image or block of text, to be fully rendered for users.

LCP is a good indicator of when users can start interacting with a page. A good score is typically under 2.5 seconds, with lower being better. Some ecosystems even use this LCP target as a requirement for any certifications. For example, when building a public Shopify app, an average LCP score of under 2.5 seconds is required in order to achieve the lucrative “Built for Shopify” badge, which will be added to an app listing as a sign of quality, making it more attractive to potential users.

Measuring your LCP

The first step when looking into page load performance is always to measure your app’s current web vital scores, including LCP. For many web apps, Google’s PageSpeed Insights or Lighthouse scores make it easy to get an initial measurement. Plus, these tools will give you suggestions for what you can do to improve your scores.

For some apps, however, this can be a challenge. Merchant-facing Shopify apps are embedded in an <inline-code>iframe<inline-code>, and since PageSpeed Insights and Lighthouse measure vitals for the whole page, that includes the Shopify store admin in addition to your application. So we need a way to only measure the web vitals and LCP score for an application, not the whole window.

To do this, we can install the <inline-code>web-vitals<inline-code> npm package from Google in our app. Open the Gadget command palette and run the following command:

Terminal

Once this package is installed, we can get our app’s LCP score by using the provided <inline-code>onLCP()<inline-code> function:

JavaScript

When measuring LCP on a production app, you want to capture and send the LCP values back to a database so the scores can be analyzed for real users over time.

Once you have your baseline LCP score, you can start making improvements.

Gotta draw fast (improve your LCP score)

We have 4 tips for improving your LCP on any Gadget app, plus a Shopify-app specific suggestion for getting that “Built for Shopify” badge:

  1. Update Gadget-provided packages and framework version
  2. Optimize image loading
  3. Optimize font loading
  4. Make your bundle smaller
  5. (Shopify) Use the <inline-code>/api/shopify/install-or-render<inline-code> app URL

1. Keep your app up to date on the latest Gadget-provided packages and Gadget framework version

We’re constantly improving the size and speed of our Gadget-provided npm packages used to power your app. This includes your app’s API client, and upgrading to Gadget framework v1.1 can reduce client package size by up to 30%! Keeping these packages up-to-date is an easy way to make sure you are getting the best performance out of Gadget.

Upgrading Gadget-provided packages to the latest version can be done in a single step. Just open the Gadget command palette and run the Update Gadget-provided packages command. Gadget will update the packages, <inline-code>yarn<inline-code> will run, and your app will automatically get any performance improvements we’ve baked into the newest version.

It’s a similar story for framework version upgrades, just go to Settings → Framework version → Edit and select the latest version. Once again, everything will be updated for you automatically, and you will get any performance updates included without having to manually update any under-the-hood dependencies.

2. Optimize image loading

Images are often the largest content element on a landing or home page. And high-resolution images on modern websites can be hefty. Making sure images are an appropriate size (don’t use CSS to scale down huge images!) and file format (<inline-code>.webp<inline-code> for smaller storage size), and compressing images using tools like TinyPNG can all help to improve LCP.

Lazy-loading images that are not immediately visible can also be helpful, and are easy to add with a simple <inline-code>loading=”lazy”<inline-code> attribute to an <inline-code>img<inline-code> element:

Terminal

3. Optimize font loading

If you’re using fancy fonts for your app, another possible culprit for the largest content element could be a block of text on a webpage. Similar to images, storing fonts in an optimized format, such as <inline-code>WOFF2<inline-code> will help with loading times and LCP. It also helps to reduce the number of custom fonts being loaded onto a single page.

Another option to optimize font loading is to use <inline-code>@font-face<inline-code> to declare fonts in CSS and use a <inline-code>font-display<inline-code> strategy to load fonts faster and prevent blocking during the first paint. For example, <inline-code>font-display: “swap”<inline-code> will use a system font while the custom font is being loaded.

Terminal



  

-->

Finally, you can self-host your fonts in your Gadget apps! By including fonts as static assets, Gadget can load them from its high-performance CDN.

4. Reduce bundle size

All your files and dependencies are bundled together and served to your frontend, and in this context, size definitely matters. A larger bundle takes a longer time to load and parse, so keeping bundles slim and trim helps with LCP.

Gadget optimizes production bundles for you, but you can use a tool like <inline-code>vite-bundle-analyzer<inline-code> to see if there are any unnecessary dependencies that can be removed from your app.

You can also use <inline-code>React.lazy<inline-code> to lazy-load components that aren’t required in the initial render. And don’t forget to use the <inline-code>Suspense<inline-code> component to avoid layout shift!

Terminal

5. Shopify tip: `/api/shopify/install-or-render` app URL

Gadget provides an optimized route for Shopify apps to minimize redirects and eliminate the cold boot time encountered with serverless solutions. Using this URL for your Shopify app URL in the Partners dashboard will improve LCP for any Shopify apps you build, and get you one step closer to that Built for Shopify badge.

For example:

Terminal

This route is used by default on all new Gadget apps. Older apps built with Gadget can change their app URL to take advantage of this route and improve LCP. More information can be found in our Shopify OAuth guide.

Follow these steps to improve your app’s LCP, delight customers, and get that Built with Shopify badge!

If you want to learn more about web vitals and LCP, check out the docs at web.dev and our Gadget guide to LCP optimization.

Interested in learning more about Gadget?

Join leading agencies making the switch to Gadget and experience the difference a full-stack platform can make.