The journey began in January 2024. The goal? Shopify’s coveted BFS (Built for Shopify) badge—a mark of excellence for apps on Shopify App Store that meet Shopify’s highest standards for performance, design, and user experience. For Swym, it wasn't just about the badge. It was about diving headfirst into Shopify Admin and leaving behind the shores of our old standalone Swym Admin site.
First Dive: Leaving the Old Behind
Like any real adventure, we had to start by shedding the weight of the past. The standalone Swym Admin had served us well, but it was time for the Shopify Admin embed. That meant leaving behind hundreds of lines of legacy code, carefully built features, and familiar workflows.
It felt like packing for a long trip—choosing only what was essential and saying goodbye to the rest. With the new embed app, we embraced Shopify's App Bridge and Polaris. It was a lot of hard work and a ton of coding, but everything looked promising until we checked the LCP (Largest Contentful Paint).
LCP 10 seconds.
That wasn’t just slow—it was glacial. We needed to move fast, but we were swimming upstream.
The CDN Current: Picking Up Speed
Next, we tackled how we served our app. Instead of hosting React assets on a traditional server, we leaned on a CDN. With some digging around in Vite docs we found the perfect config.
export default defineConfig({
base: "{CDN_URL}",
...
build: {
outDir: "dist",
rollupOptions: {
...
output: {
assetFileNames: ({ name }) => {
return "assets/[name][extname]";
},
chunkFileNames: "assets/[name]-[hash].js",
entryFileNames: "assets/[name]-[hash].js"
}
}
...
},
...
});
We hosted the built files on our CDN and with CDN delivery and code splitting, we cut LCP from 10 seconds to 6 seconds. Faster—but not nearly fast enough.
React Shores and API Currents
We then turned to our app's architecture. API calls were scattered, state management was fragmented, and duplicate requests were dragging us down. We leaned on ReactContext
, defining critical states and unifying their getters and setters.
Next, we uncovered an issue with Shopify's authentication packages. Every API call triggered a Shop
API request to validate the Shopify AccessToken—completely unnecessary.
So, we built our own authentication packages, bypassing the redundant Shop
API and saving 200ms per call. We also switched from the Shop
API to the Themes
API, storing data in context for onboarding and theme extension enablement.
LCP dropped to 4 seconds. Progress, but the gold still shimmered out of reach.
The "10/10" Moment
Out of ideas but still full of hope, I knew I needed help. That’s when the team made BFS the north star. We assembled a team—fellowship of sorts.
I had worked with this team before on big challenges, and if anyone could do it, it was them. In that assembly, someone asked: "How confident are we, on a scale of 1 to 10, that we can hit 2.5 seconds LCP?"
The answer? "10/10. Once this team sets its mind, no one can stop us."
Lost in Measurement: Sentry vs. Shopify
We brainstormed many ideas and created several POCs but here’s where the waters got murky. We used Sentry to measure LCP, but its scores never matched Shopify’s dashboard. Shopify just measured LCP in a different way than the other third party tools. It felt like navigating with a broken compass.
Then, Shopify released their own LCP measurement tool. Suddenly, the path cleared. We understood what Shopify truly cared about.
The new tool showed us exactly what was causing the Largest paint. And what the actual LCP was realtime.
Final Sprint: Static Rendering and Fewer Calls
The main finding—LCP was measured only on the first loading page when the merchant opened the App.
And to reduce the LCP we just needed to optimize this page. The breakthrough came with static rendering. We stopped waiting for API calls in the Home Page. Instead, we pre-rendered everything possible. Only critical buttons—like those for navigating to onboarding or metrics showed loading states.
And the results:
LCP <2 seconds.
The current had turned. We weren’t swimming upstream anymore—we were gliding.
Gold at Last
LCP was just one of the optimizations needed for the perfect app. There was another BFS requirements to tackle still.
Working with the Shopify team we had to redesign many critical components to follow the App design guidelines. Making these changes made our UI much more aligned with Shopify Admin’s UI which ultimately lead to a better merchant experience.
In the end, the Shopify BFS badge wasn’t just a trophy—it was proof of resilience, teamwork, and relentless optimization. We didn’t just build a faster app; we built a better one.
Every stroke counted. And when we finally reached the shore, we looked back and realized: the swym itself had made us better.
Awesome work Yashit and the Team @Swym!!