I have a public app, is there a way to make it free to use in Dev stores for e.g it will show test charge for Development stores only?
Hi Bilal,
It sounds like you want to set your app up so it would be a “partner friendly app” - essentially free on all dev stores?
You should be able to set up free testing on devs stores with this technique: Offer free trials
Can you help me with the code?
In appSubscriptionCreate
, set test
to true for dev stores.
Just to add to @Gulam_Hussain_Quinn 's comment, you first need to identify if the current store is a Development store.
You can use the shop.plan
object for this in the Admin GraphQL API. The name
of the plan is the Shopify plan.
Currently I have following code in app.jsx
export const loader = async ({ request }) => {
const { admin, billing, session } = await authenticate.admin(request);
const { shop } = session;
const subscriptions = await getSubscriptionStatus(admin.graphql);
const { activeSubscriptions } = subscriptions.data.app.installation;
if (activeSubscriptions.length < 1) {
await billing.require({
plans: [MONTHLY_PLAN],
isTest: false,
onFailure: async () =>
billing.request({
plan: MONTHLY_PLAN,
returnUrl: `https://${shop}/admin/apps/bbd-big-bulk-discount/app`,
isTest: false
}),
});
}
return json({ apiKey: process.env.SHOPIFY_API_KEY || "" });
};
And I tried following to skip billing in development store
export const loader = async ({ request }) => {
const { admin, billing, session } = await authenticate.admin(request);
const { shop } = session;
// Fetch shop details to check if it's a development store
const shopDetails = await admin.graphql(`
query {
shop {
plan {
partnerDevelopment
}
}
}
`);
// Fix: Compare as a boolean, not a string
const isDevelopmentStore = shopDetails.data.shop.plan.partnerDevelopment === true;
if (!isDevelopmentStore) {
const subscriptions = await getSubscriptionStatus(admin.graphql);
const { activeSubscriptions } = subscriptions.data.app.installation;
if (!activeSubscriptions || activeSubscriptions.length < 1) {
await billing.require({
plans: [MONTHLY_PLAN],
isTest: false,
onFailure: async () =>
billing.request({
plan: MONTHLY_PLAN,
returnUrl: `https://${shop}/admin/apps/bbd-big-bulk-discount/app`,
isTest: false,
}),
});
}
}
return json({ apiKey: process.env.SHOPIFY_API_KEY || "" });
};
But it is not working I am getting application error
What error are you getting from your application?
Also have you considered using Managed Pricing? That automatically makes it free for dev stores Managed App Pricing
It just shows “Application Error” and does not show details of that error. I think I will have to console.log in order to get what the issue is.
Managed Pricing shopify documentation is redundant does not actually what to do. Have you found any more details on that? Like if I need to add any code on the APP to trigger Managed Pricing page
Managed Pricing is configured in the Partner Dashboard, in your app under Distribution and Pricing. Where you can decide if you want to use it or not, the pros/cons of which are in the docs Managed App Pricing
In terms of how to use it, if someone is not subscribed, you just redirect them to the managed pricing page that is hosted for you, the URL format of which is in the docs. It couldn’t be simpler. And deals with your test charges Managed App Pricing
I tried following code which works and serve the purpose. It’s not showing billing page on development stores now the only issue is that if Development store becomes Live store. How can I handle that via this code:
export const loader = async ({ request }) => {
const { admin, billing, session } = await authenticate.admin(request);
const { shop } = session;
const subscriptions = await getSubscriptionStatus(admin.graphql);
const { activeSubscriptions } = subscriptions.data.app.installation;
// Skip billing in development but return necessary data
if (process.env.NODE_ENV === "development") {
console.log("Skipping billing check in development mode.");
return new Response(
JSON.stringify({ apiKey: process.env.SHOPIFY_API_KEY }),
{ headers: { "Content-Type": "application/json" } }
);
}
if (activeSubscriptions.length < 1) {
await billing.require({
plans: [MONTHLY_PLAN],
isTest: false,
onFailure: async () =>
billing.request({
plan: MONTHLY_PLAN
}),
});
}
return new Response(
JSON.stringify({ apiKey: process.env.SHOPIFY_API_KEY }),
{ headers: { "Content-Type": "application/json" } }
);
};
Just change is test to true in your code when the store is development, rather than not handling billing in your current implementation
Finally I was able to do this with following code:
export const loader = async ({ request }) => {
const { admin, billing, session } = await authenticate.admin(request);
const { shop } = session;
const subscriptions = await getSubscriptionStatus(admin.graphql);
const { activeSubscriptions } = subscriptions.data.app.installation;
const shopPlanQuery = `
query GetShopPlan {
shop {
plan {
displayName
partnerDevelopment
}
}
}
`;
const response = await admin.graphql(shopPlanQuery);
const data = await response.json();
const plan = data.data.shop.plan;
const isDevelopmentStore = plan.partnerDevelopment ||
plan.displayName.toLowerCase().includes("development");
if (isDevelopmentStore) {
console.log("Development store detected. Using test billing.");
await billing.require({
plans: [MONTHLY_PLAN],
isTest: true,
onFailure: async () =>
billing.request({
plan: MONTHLY_PLAN,
returnUrl: `https://${shop}/admin/apps/your-app-handle/app`,
isTest: true,
}),
});
}
if (activeSubscriptions.length < 1) {
await billing.require({
plans: [MONTHLY_PLAN],
isTest: false,
onFailure: async () =>
billing.request({
plan: MONTHLY_PLAN,
returnUrl: `https://${shop}/admin/apps/your-app-handle/app`,
isTest: false
}),
});
}
return json({ apiKey: process.env.SHOPIFY_API_KEY || "" });
};