Topics covering webhook creation & management, event handling, Pub/Sub, and Eventbridge, in Shopify apps.
Hey guys,
We are using a third-party freight broker and a multitude of other carriers to generate real-time shipping rates as the user shops. If they add or remove an item, we are pulling rates dynamically and displaying them in the cart, as well as in other parts of the UI. From there, the rates are cached under the customer ID that is created by Shopify at either login or registration. This also allows for near instantaneous rate retrieval in Shopify's locked-down checkout. The major challenge we are facing is having those customer-specific shipping rates available in the callback URL when Shopify hits them due to a data passing issue.
So far, I have come to these conclusions about the process:
Shopify will not allow for a dynamic URL, which means there is no way to pass parameters.
Obviously, session data won't be accessible to the callback because the call is coming from Shopify and not the specific user in question.
Obviously, I don't have any control over the headers, body, or anything else regarding the incoming POST request from Shopify.
So, the overall question is: How can I pull the user's specific customer ID into the callback URL so that I can retrieve the cached results that are stored under that unique identifier? I mean, am I missing something simple or am I going to have to real far to get this to work as intended?
Hey @Liquidator3358 - thanks for getting in touch. One method that may work here is using the checkouts/create webhook subscription topic to collect the relevant data when a checkout is initially created (customer ID, checkout ID, etc.). My understanding is that we wouldn't be able to place these exact values into a dynamic checkout URL, but, it would be possible to use the storefront API to update a checkout with the right shipping rates after pulling the needed info from the webhook payload.
Here's a general high-level overview of what could be done to implement the functionality:
1. Pull the customer and checkout ID from the webhook's callback payload.
2. Implement a function that checks shipping rates against the customer ID (pulling from the data you've already cached).
3. Based on the customer ID/rate combo you could input the relevant shipping rate handle by updating the checkout's shipping rate using the GraphQL storefront API's checkoutShippingLineUpdate mutation.
The one thing I'd note about this method is that it could be a little slower as it would depend on the webhook trigger. The wait time should be minimal generally, though. Hope this helps - happy to look into this more to see if we can find a better answer if need be.
Al | Shopify Developer Support
Developer Support @ Shopify
- Was this reply helpful? Click Like to let us know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog
Hey Al,
I actually did this a different way but now that you are here, I would like to pick your brain about something related. This is how I am currently doing it:
1. The rates get fetched and cached as the user adds/removes items throughout the shopping process. I am displaying them in the UI.
2. When a checkout is created using the checkoutCreate mutation (I am sending over all the customer information in order to fill out the check out inputs), I then call my shipping endpoint where I PATCH/PUT (tried both and they work) the callback_url in the carrier_service object and add the customer id (I parse out the numbers) every time as a param. So basically, I am constantly changing the callback_url per user checkout.
3. I extract that param from the callback_url request, use it to pull my cached rates and respond to Shopify's request with the rates near instantaneously.
Here is the MAJOR issue.. for whatever reason, my rates are not always getting to checkout and it's very hard to pinpoint why. I see the callback_url get hit with the correct params in my logs, I see the rates fire in the logs correctly too, and still, the rates do not show up... it just defaults to the backup rate, which is beyond frustrating.
I am also associating a customer using the associateCustomerWithCheckout mutation, which then allows me to use my current customerAccessToken and the checkoutId I created beforehand to do so.
There are a lot of moving parts, but again, it works damn well other than the random drops...
If all those things are lining up on my end, why would Shopify be missing it RANDOMLY. I say randomly, because there are stretches where it can work 10x in a row... it is very, very odd.
Wait, on your #1, how would I pull the customer's ID from the payload? From what I know, you only get what's inside the req.body (origin/destination, customer's info and cart items - I don't recall seeing the customerId?) and you can't send any extra information over the payload? Naturally, the was my first knee jerk reaction - pull the customer's ID from the payload but it never existed? If I could do that, I wouldn't have to do that hacky PUT request that changes the callback_url everytime.
I completely missed that first suggestion and I see what you are saying. Somehow, use the checkout/create webhook to fire my shipping rates, which will allow for the right data to be in play.
Al,
I'm in the middle of doing something like this and am having an issue trying to call the Storefront API in the post method after receiving the webhook payload because I am used to grabbing the shopify session from the response and using it to make graphql api calls. The issue is that webhooks don't transfer session data so I'm not sure how to make storefront api calls if I don't have a session. I'm still currently looking into how to solve this but if you know how to help that would be great.
Here is my webhook endpoint. On line 93 I need to be able to send the session to cartHandler. But there is no session associated with res.locals.shopify.session
Unfortunately, you are limited to the request body, which is simply shipping info, and nothing more. You're going to need to somehow use that data to then go return what ever data you need via another api call. Since all the session data is tied to the client, Shopify's request will not be able to access any of that data via the callback URL.
My approach was to search for session on the app DB with shop domain sent by webhooks:
If you find a better way, pls let me know.