Hey @kahn - thanks for flagging this. I’ve tried to reproduce this behaviour by navigating to an embedded app (using App Bridge) in my test Shopify admin, but I’m not able to replicate.
If you’re able to, could you share your app’s name/app ID and a HAR (HTTP Archive) file from your browser’s developer tools (guide here on how to do this) showing the network requests when you navigate to your app and see the two requests?
Happy to dig into this a bit more with you - hope to speak soon!
It is not about a specific app. I have tested with multiple ones and all have duplicate embedded url request. As screenshot bellow, Shopify App Flow also have the same issue:
Hi, any update on this? Looks like I have some of the same problem.
Opening the app main page seems to load the app twice. But even worse, when using admin-links, the admin-link page loads, but then the main page is loaded like 1 second later. So this effectively breaks the admin-link page for the user.
To be clear, admin-link and main page are two seperate endpoints. Both endpoints HTTP 302 redirects to the same page, but with different parameters / state (hash / query).
And the behaviour is not completely deterministic, seems not to happen the first/second time the app is loaded, but then on the unwanted behaviour manifests.
So this breaks admin-links, a critical part of my app
Try the “Bring Shipping” app to see for yourself.
Is it possible to roll back to an earlier version of app brigde via CDN?
I’ve made some progress; as I understand it, the following is happening:
iframe loaded twice for every use, in sequence. The first load lasts really short, just enough for the app to be visible and log a few lines.
The second load ditches hash part (i.e. #orders) from the URL, so state infomation is lost for my SPA. I thought this was a redirect but of course this is just the default page for my SPA when not using any hash.
I’ve been able to restore admin-link functionality by serving HTML directly (as opposed to my previous 302 redirect) + adding state parameters in the served HTML document.
Hey folks - just following up on this, I was able to confirm with the team that the two requests we’re seeing are expected behaviour. What’s happening is that the first load is preloading the app but not executing and the second load is the actual execution of the embedded app.
I can’t share too many details, but the intent is that this is to cache the app assets and make loading a bit snappier/fast.
@skjolber - would you be able to share your app ID with me here, and if possible a screen recording of the issue? My understanding is that this shouldn’t affect admin links, but I’m happy to take a look into this more deeply for sure. Hope to hear from you soon!
Hi, my production app is now fixed, but I can roll back the old behaviour on my staging app + invite you to a development store, then you can play all you want to. Can you PM / email me so I can invite you?
We have noticed that when the user returns on the callback to pay the application executes the code twice and I think this is why it is rendered twice. Does anyone else have this problem?
@Alan_G I faced a potential issue for mutation action in local testing.
After the merchant has approve to install the app, Shopify will redirect to the app’s home path.Shopify_app gem will insert the shop record to database. While the 2nd call got an error: Validation failed: Shopify domain has already been taken
I’m experiencing the same issue as many of you, especially after the OAuth flow (similar to what @cesarho mentioned). It seems to be creating two accounts in my database. While I could technically prevent that using a unique constraint on database level, that feels more like a workaround than a proper solution to me.
I’ve tried getting creative to solve it, but so far I haven’t found a good approach.
I’m wondering — is this new behavior? Did I miss any recent updates?
@Alan_G — it would be great to hear your thoughts on this! Thanks in advance!
Hey @cesarho and @appetizer - thanks for waiting on my reply here - happy to take a look at this. The “double loading” issue related to the two requests being sent is expected, but the multiple record creation is odd for sure.
Just to clarify, are you folks seeing TWO successful token exchanges in your logs and then the second fails just because the shop is already entered in your DB, or is the first request different somehow?
If you revert to using version 22.5.1 of the app gem or earlier, does the issue persist? Just trying to narrow down what could be causing the issue we’re seeing - speak with you again soon, we’ll get this looked into!
Would it be possible to add something to help identify the second request?
In my loader, I have a heavy function that handles the initial user setup. The problem is, a second request can sometimes come in and create race conditions when updating the database. Being able to shake that second request in that loader would be super useful.
Also, not a huge deal, but that function also makes GQL calls, and because of this behavior, users can get throttled quickly. That ends up making the initial setup slower than necessary, which impacts the user experience pretty heavily.
Anyways, thanks for your ongoing involvement in this discussion!
Hi @Alan_G the problem is many apps will rely on the request and has its logic on each request. Both ‘double loading’ has the exact same params and values so the app logic must execute twice every time the merchant open the app admin. There would be a param to notice the developer that it is preload request to ignore the logic on backend.
Thanks folks for the clarifications here - really helpful to see this is now happening with 3 requests, it does seem like this may be unexpected behaviour.
@cesarho & @appetizer - if you’re still hitting those token exchange errors, the X-Request-IDs from those failed requests would be super helpful too.
I’ll dig into this more deeply once I have that info and see if we can figure out what’s happening. The jump from 2 to 3 requests does suggest something may have changed on our end.
@Alan_G For my case, the error was not happened in token exchange. The issue is that both requests passed all the logic. Shopify_app gem has insert the shop record in the first request already; when the 2nd request try to insert the shop record again, it failed due to duplicate key.
I cannot similar the error in the installation today, but the similar issue happens on approving the app charge.
This is the example of the duplicate charge approved request.
@Alan_G, I think the root of the problem comes from:
There can be non-idempotent behaviour taking place in response to GET requests. This is not supposed to happen, but it can be complex to work around because…
Some actions do need to change stuff, but they always come in as GET. Ex: merchant confirms subscription, is redirected back to the app. The app needs to be able to do flip a column in a database. It can take the first and ignore the second request… but it doesn’t know which one is which.
Some admin link actions are also inherently creative/destructive. Like “Create something”, “Send something” etc. When the requests hits twice, it inserts 2 records, it sends 2 emails etc. Again, not ideal for it to happen, but I don’t know a good workaround that is simple to implement and maintain. If some requests could be sent as POST that would give apps more structure to work with their routes.
We use the shopify_app gem that includes some JS magic and a specific set up that prevents some of these issues by chance, but certain admin link actions have become a problem.
Is it really necessary to have the double-loading of the app? Aren’t the app’s resources already cached by the merchant’s browser anyway? I don’t know if the extra performance is worth the complexity, but I can say it can be hard to debug and parse what is going on with the double requests.
Note: It is not about any specific app issue, it happens to all apps including Shopify App like on my screenshots. So you can replicate it on your end easily by just open the dev tool and filter ?embedded=1 on Network tab.
Thanks all for your followups here. For those using the shopify_app gem - can you confirm if reverting to v22.5.1 or earlier helps at all? Though, like you said, given this affects all apps, I suspect it won’t fully resolve the issue, just want to see if we can potentially narrow it down to a specific app version
@flavio-b, I do think where you’re coming from here is valid with non-idempotent GET requests. It can create a bit more complexity for developers, especially within admin links and subscription callback contexts. I’d need to do a bit more digging into this to confirm if we do have something on the roadmap to address this, but I’ll keep looking into the initial issue and your architecture questions and loop back with some next steps/more info when I have it!