Mastering Shopify App Bridge Sidekick: Solving the 'Tool Not Found' Race Condition
Mastering Shopify App Bridge Sidekick: Solving the 'Tool Not Found' Race Condition
As a Shopify app developer, you're constantly pushing the boundaries of what's possible within the Shopify Admin. The App Bridge library, especially its newer features like Sidekick and the intent API, offers powerful ways to integrate your app deeply into the merchant's workflow. However, with new power comes new challenges, and one particularly frustrating issue that can arise is the dreaded "tool not found" error.
At Shopping Cart Mover, we specialize in seamless e-commerce solutions, including advanced Shopify development and integrations. We recently observed a critical discussion in the Shopify Community that perfectly illustrates a common pitfall with App Bridge's `shopify.tools.register` method and full-page navigations. Understanding this issue is crucial for building robust and reliable Shopify apps.
The Problem: A 'Tool Not Found' Mystery
Our fellow developer, blueliner, encountered a classic race condition while implementing `sidekick-import` with `admin.app.intent.link`. The scenario was straightforward: a merchant, while using another embedded app (e.g., an eBay Importer), would trigger an intent that caused a full-page navigation to blueliner's app. The expectation was that Sidekick would then call their registered tool, `preview_amazon_product`, to perform an action. Instead, Sidekick returned a "tool not found" error.
What made this particularly puzzling was that the tool *did* register successfully, as confirmed by logs, but only after a significant delay. The tool worked perfectly in other scenarios: when the merchant was already on a native Shopify Admin page or already inside blueliner's app. The failure occurred specifically after a full-page navigation from *another* embedded app.
The Smoking Gun: A Timing Race
The crucial piece of information blueliner provided was that their tool registration was happening approximately 2380 milliseconds (2.38 seconds) from page load. This, as Mindaugas_LM astutely pointed out, was the "smoking gun."
Here's why this delay is critical:
- Full-Page Navigation Reloads Everything: When an intent triggers a full-page navigation, your app reloads from scratch. This means your entire JavaScript bundle needs to be downloaded, parsed, and executed again.
- Sidekick is Eager: Sidekick, part of the Shopify Admin, dispatches the tool call almost immediately after the navigation completes. It doesn't wait for your app to fully boot up.
- Bundle Load Time is Your Race Window: Those 2380ms represent your app's bundle parse and evaluation time. Even if your `shopify.tools.register(...)` call is at the very top of your entry file, module-level, and before React mounts, the entire bundle must process first. During this window, Sidekick calls for a tool that simply hasn't been registered yet. The `shopify.tools` API, especially for Sidekick intents, does not queue incoming calls; it drops them if the tool isn't immediately available.
The Elegant Solution: Decoupling 'Tool Exists' from 'Tool is Ready'
The fix lies in decoupling when the tool is *registered* from when it's *ready to perform its work*. The goal is to make the tool exist almost instantly, even if its underlying logic and dependencies are still loading.
Mindaugas_LM's recommended approach is to register a thin wrapper for your tool outside your main JavaScript bundle, in a tiny inline This code does two critical things: This resolves the Promise, allowing any buffered Sidekick calls to proceed with their actual work. This solution effectively separates the concerns of tool registration (which must be instant) from tool execution (which can be deferred). It ensures that Sidekick always finds a registered tool, preventing the "tool not found" error, while gracefully handling the app's boot-up time. Key Best Practices for Shopify App Developers: The Shopify platform offers incredible flexibility for merchants, and well-integrated apps are at the heart of that experience. Understanding these subtle timing nuances in App Bridge is crucial for building apps that are not just functional but also reliable and performant. For developers looking to build powerful, integrated apps on the Shopify platform, or for merchants considering to start your Shopify store today, these technical insights ensure a smoother journey. At Shopping Cart Mover, we're committed to helping businesses leverage the full potential of Shopify. From complex migrations to custom app development and integration, our expertise ensures your e-commerce operations run flawlessly.
// Inside your main app bundle (e.g., index.js, after React mounts and dependencies are ready)
// ... after Redux/api are ready
if (window.__resolveAppReady) {
window.__resolveAppReady({
previewAmazonProduct: (input) => {
// Your actual tool logic, e.g., calling an API and dispatching to Redux
const result = await previewProductApi(input.amazonProductUrl);
// ... dispatch to Redux store
return {ok: true, title: result.title};
}
});
}Why This Works and Best Practices
Building Reliable Shopify Integrations