Regarding highly customized special offer (discount) functionality

How does shopify recommend we implement custom special offers (also called discounts)

In the past we have meet with shopify reps and shopify partners and they recommended our current approach to special offers as the only option that meets our requirements. Is there a more correct approach now that shopify has added these functions. Our requirements:

  1. we must be allowed to apply multiple special offers to each item in the cart

  2. we must be able to control who has what offers and what products the customer can apply them to using complex logic outside of shopify

    1. we use app proxy currently to get offers from our own service and what products they are for

    2. we have a rules engine that must run in our service as it requires sensitive user data that we can not send to shopify for compliance reasons

  3. We must allow the customer to apply the offers manually to cart items in whatever order they like (not auto applying offers at checkout)

    1. The customer must be allowed to check out without using all or any of the offers if they like so they can save them for a future purchase
  4. We must receive a webhook with metadata about each line item and what offers/amount were applied to that line item

  5. We need to make sure they cant use the same special offer more than once while we wait for the order created webhook that tells our system they used an offer.

That’s an interesting problem. I wonder if you could do this all in cart before going to checkout. Once you get to checkout it’s kinda locked down but while on the cart page you could prompt for the verification data that you need to validate with your external system, present the offers, and then if a customer accepts dynamically create a discount code that only works for their email and automatically apply that code. Then once the order has been created you could read the order data to record in your external system which offers they have actually redeemed. I’m curious to hear what the official Shopify response is too!

yeah we already had to move everything to the cart page since they deprecated the checkout pages. At this point it feels like one hacky workaround after another to meet our business requirements. In the cart page we

  1. call our own internal api using the shopify app proxy to get a custom list of special offers (discounts) for the logged in user. Every user might get special offers based on things like who they work for, and a hundred other conditions (we have a rules engine to determine on our side)
  2. We present all options on the cart page and let the customer select which special offers they want to apply
  3. If a member adds a special offer there is ajax call to the shopify cart api that adds line item properties about the offer, then we trigger a refresh which invokes the line item scripts.
  4. The line item script will read the line item properties added in the previous step and apply one or more discounts per line item
  5. On the checkout page it does show a note by each line item showing the N discounts applied at the line item level.
  6. Since this is all very front end driven and very subject to front end tampering we have checks when we receive the order created webhook to make sure users are not abusing front end tools and getting offers they should not. But basically this means after the user completes checkout we wont fulfill it and its very brittle.

So we have a very hacky solution and Im now asking in this new world of shopify functions is there a good way to do it. Some issues I think are the functions dont seem make it possible to apply multiple price discounts on a single item or if they do its too confusing. IMO if there was a line item function to reduce the price by X then that needs to be possible in the function as well. The issue shopify is going to find their customers complaining about is all because the functions dont have feature parity with the line item scripts.

And I would give my left arm to get any kind of server to server secure calls in these functions. My company wont pay for an enterprise account - its just out of the question.

I am the solution architect not the lead dev but I think he also mentioned it was very difficult or impossible to add or update line item properties in the shopify function. So we need to do both - update multiple price discounts for individual line items and read/update the line item properties in a simple way. He tried some crazy options that required several functions but we couldnt figure it out.

Hey @GeorgeHoffman great question, and this might be something that would benefit from some 1:1 conversations on your specific use case.

In general, a strategy I’ve seen done in instances similar to this is to pass in line item properties (attributes) to the cart with some sort of secure hashing mechanism to validate that no tampering was done client side.

On the Functions side of things you’d be validating that the input wasn’t tampered with, applying multiple discounts (only one per line item, so you’d need to combine the total and messages appropriately similar to what you did in Scripts.)

You could also try out the Dev Assistant to try migrating your existing Shopify Script to Functions.

Currently, Functions cannot update the line item properties as part of their output. However, you can update line item properties in the cart or during checkuot using checkout UI extensions.

Can you explain more about what your Script’s add or update line item properties functionality does and how it’s being used?

Thanks for the reply!

For ~5 years I’ve tried to figure out a way using hmac hashes and come up empty. I definitely tried many concepts with hashes and found these issues:

  1. Line item scripts (ruby) can not import any crypto packages so its not possible to set any hash server side
  2. even if we could generate a hash in the line item script it would require a secure secret and would probably have to be hard coded in the script since we cant access any global attributes from what I can remember and there is no secure way to store secrets in shopify that could also be used in line item scripts (unless something has changed). By secure I mean no one with access to the liquid source code should be able to see the secret.
  3. I believe my dev also tried to import crypto packages in the functions and its blocked (even if we could I would not be comfortable putting the secret directly as a hardcoded string in the function. I believe he mentioned the funtion is compiled and run on the browser so any secret we put in their is immediately compromised. Its a bit confusing in your documentation what runs server side vs client side and really will cause confusion and security issues if people assume these functions run in a secure container on the service. Anything that runs client side can be compromised with tools built directly into the browser.
  4. Encryption/signing on the client side is pointless because it requires you to generate the signature with a secret that you must share with the browser / client. Since there is no server side way to update the cart we would have to generate the hash in javascript and pass it to the cart javascript api (and hence any bad actor can just create whatever hash they want and game the system).

But right now I’m not as primarily concerned about the security and more about how we can just get the thing working per requirements. We have checks in the webhook listener that make it relatively secure (though it did require a lot of iteration on our side to find good options).

I might have misinterpreted this from our dev but is there a mechanism to add multiple discounts in a single call to the function? That was the biggest deal breaker. Also those individual discounts need to appear in the checkout page (fitbit has discounts A, B, C).

The properties we are adding to line item properties are the details related to the offer (discount) mainly so the line item script can apply the discounts. We also create a total amount that is used to set the price since we must tally up all the discounts and subtract from the line item initial cost. The solution I think you are proposing is to move all our logic to the browser so we set the price from the browser using the cart ajax endpoint. I guess since its already difficult to secure moving our entire logic to javascript is just one more thing that can be manipulated by a bad actor and we have to add additional checks on our webhook endpoint. I feel like this is again more hacky than what we even already have.

happy to do a 1:1 sometime as you seem very well versed. I would need my dev since he is much closer to the code now than I am. LMK. Thanks

You won’t be able to visually show them as separate discounts on the same line item (this is a constraint that exists today in Scripts as well)

Just for a point of clarification, Shopify Functions execute within the backend request flow and do not execute in the browser. They execute as if they are part of Shopify’s code base, and therefore the code that we execute is not visible to a buyer in the checkout flow.

Let’s connect async on how to drive some more clarity on your use case.

sure thanks - what is the process to connect async and do you have specific timelines in mind? This week is a bit crazy but we can squeeze in time if needed or next week would be better if that is an option

I sent you a direct message if you can check that.