Hi, how can I use a single discount code to apply both a percentage discount on the order and free shipping? I tried checking if it was possible to do it using the Discount APIs as well, but I couldn’t find any solution.
Topic summary
A Shopify developer is trying to create a single discount code that applies both a percentage discount and free shipping.
Initial Challenge:
- Standard Shopify requires separate discount codes for product discounts and shipping discounts
- Suggested workaround: Use an automatic free shipping discount based on a collection, plus a percentage-off code
- Alternative: Use a paid app like Discount Ninja for multi-perk codes
Shopify Plus Function Attempt:
The developer is working on a custom function to detect discount codes with a specific prefix (“AUG”) and automatically apply free shipping. However, they’re encountering a technical issue:
- The
fetchResultingenerate_delivery_run.tsalways returnsnull - Console logs from both the fetch function and backend aren’t appearing
- Backend was initially returning a plain JavaScript object instead of a proper HTTP Response object
Current Status:
Even after correcting the backend to return a properly formatted Response object with JSON body and headers, the fetchResult remains undefined and console logs aren’t showing. The issue appears to be in the communication between the fetch function and the backend endpoint, preventing the delivery discount function from receiving the necessary data to apply free shipping.
This will have to be two discounts because shipping discounts are separate from product discounts. You could set up one of them to be automatic based on a Collection (I’d recommend the free shipping), and then have a code that does the % off. Advertise them together and from a UX standpoint there won’t be much difference.
If you’re ok paying for an app, I believe you could use Discount Ninja to set up multiple perks with one code.
But if I have a Shopify Plus is it possible to use a function? For example, create a 20% discount coupon and if it starts with a specific prefix with the function also give free shipping
I try to use shopify Discount Api function and this is my code:
- generate_delivery_fetch.graphql
query FetchInput {
enteredDiscountCodes
}
- generate_delivery_fetch.ts:
import {
FetchInput,
CartDeliveryOptionsDiscountsGenerateFetchResult,
HttpRequestMethod
} from “../generated/api”;
export function generateDeliveryFetch (input: FetchInput
CartDeliveryOptionsDiscountsGenerateFetchResult {
const hasAUG = input.enteredDiscountCodes?.some(code =>
code.toUpperCase().startsWith(“AUG”)
);
console.log(JSON.stringify(input, null ,2))
return {
request: {
method: HttpRequestMethod.Get,
url: “https://my-backend/api/return-has-aug?hasAug=” + hasAUG,
headers: ,
policy: {
readTimeoutMs: 1000
}
}
};
};
- generate_delivery_run.graphql:
query DeliveryInput {
cart {
deliveryGroups {
id
deliveryOptions {
handle
cost {
amount
}
}
}
}
fetchResult{
body
jsonBody
status
}
}
- generate_delivery_run.ts:
import {
DeliveryInput,
CartDeliveryOptionsDiscountsGenerateRunResult,
DeliveryDiscountSelectionStrategy,
} from ‘../generated/api’;
export function generateDeliveryRun(
input: DeliveryInput
CartDeliveryOptionsDiscountsGenerateRunResult {
console.log("Input: " + JSON.stringify(input, null ,2))
const hasAugCode = false;
return {
operations: [
],
};
}
the ruslt of console.log in generate_delivery_run.ts is always :
Input: {
“cart”: {
“deliveryGroups”: [
{
“id”: “gid://shopify/CartDeliveryGroup/xxx”,
“deliveryOptions”: [
{
“handle”: “handlecode”,
“cost”: {
“amount”: “0.0”
}
},
{
“handle”: “handlecode”,
“cost”: {
“amount”: “5”
}
}
]
}
]
},
“fetchResult”: null
}
It would technically be possible to write a function. But if you can’t figure it out yourself and would need to hire a dev or something, Discount Ninja would be the best move. Much easier and, at that point, cheaper.
As for your code, you may be running into an issue where the fetchResult is always null in generateDeliveryRun.ts, which likely means your generateDeliveryFetch.ts isn’t properly returning a result that the run function can use.
So for a couple things to try:
- Confirm your generateDeliveryFetch backend returns proper JSON.
- Check fetchResult parsing in generateDeliveryRun.ts. Since your current generateDeliveryRun.ts function does not parse or use fetchResult, it remains null and does nothing. You need to check for input.fetchResult?.jsonBody?.hasAug (assuming your backend returns a hasAug flag).
My backend do this:
export async function loader({ request }: LoaderFunctionArgs) {
try {
console.log("
Shopify fetch received:", request.url);
const url = new URL(request.url);
const params = url.searchParams;
const hasAug = params.get(‘hasAug’);
return {
hasAug: hasAug
}
} catch (error) {
console.error(“Errore nella richiesta:”, error);
return new Response(JSON.stringify({ error: “Internal Server Error” }), {
status: 500,
headers: {
“Content-Type”: “application/json”,
},
});
}
}
and in generate_delivery_run.ts I inserted this line:
console.log("Input: " + input.fetchResult?.jsonBody?.hasAug)
But the result of console.log() is Input: undefined and I don’t see in the console the results of console.log in my backend and in generate_delivery_fetch.ts
So looks like your backend isn’t returning a valid Response object. Shopify expects a proper Response object from generateDeliveryFetch, not just a plain JS object. Right now, your backend returns:
return {
hasAug: hasAug
};
This needs to be a properly formatted Response with a JSON body and correct headers.
You could try changing your backend to this:
export async function loader({ request }: LoaderFunctionArgs) {
try {
console.log(":robot_face: Shopify fetch received:", request.url);
const url = new URL(request.url);
const hasAug = url.searchParams.get("hasAug") === "true";
return new Response(
JSON.stringify({ hasAug }),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
} catch (error) {
console.error("Errore nella richiesta:", error);
return new Response(JSON.stringify({ error: "Internal Server Error" }), {
status: 500,
headers: {
"Content-Type": "application/json",
},
});
}
}
Then you’re returning a valid HTTP response object, which Shopify Functions will understand and pass into fetchResult.
Thanks for the response i have apply how you say, but i have always the same problem, i think the problem is before because i don’t see the result of console log in fetch and in my backend.