Handling repeated trial periods in Shopify Billing (Remix App)

Here’s the situation:

  • A user installs the app and gets a free plan.

  • They upgrade to a monthly paid plan with a 3-day trial.

  • Before the trial ends, they cancel the subscription.

  • Then they re-subscribe to the same or different plan (like yearly) — and again receive the 3-day trial.

  • This can be repeated indefinitely, giving them free access repeatedly.

Questions:

  • Is this the default behavior of Shopify’s Billing API?

  • How can I prevent repeated trials for the same shop/user?

  • Is there any Shopify-supported way to detect if a shop has already used their trial?

  • Or should I manually track trial usage on my backend?

  • What’s the best way to implement this check in a Shopify Remix app?


Any help, guidance, or code examples would be super appreciated :folded_hands:
Thanks in advance!

1 Like

Hi @damonrcr

Great question — this is a known loophole when using Shopify’s Billing API with trials, and it’s something app developers need to handle carefully.

1. Is this default behavior?
Yes, this is the default behavior of Shopify’s Billing API. Shopify does not prevent shops from getting the trial period again if they cancel and re-subscribe — even on the same plan.

2. Can Shopify detect previous trial usage?
Shopify currently does not provide a built-in way to check whether a shop has previously used a trial for a specific app or plan. The platform treats each subscription as a new record.

3. Recommended approach: Track it manually
The best practice is to track trial usage manually in your backend. When a shop first installs the app or subscribes to a trial, store their shop domain and the date of trial usage in your database.

Then, before creating a new billing plan, check if they’ve already used a trial — and if so, present a plan with trial_days: 0 to skip the trial.

4. How to implement this in a Shopify Remix app?
In your Remix app:

When a shop initiates a plan upgrade, query your backend (e.g., a PostgreSQL or MongoDB record) to check for a previous trial.

Based on that, call the Shopify Billing API with trial_days: 0 if they’ve already used their free trial.

You might also log cancellations and re-subscriptions to make sure you’re handling edge cases properly.

1 Like

Thank you @Dotsquares

Please can you give some code for reference and how i use subscription webhook for real time updation in db? this is my app.upgrade code

export const loader = async ({ request }) => {
await connectDB();
const { billing, session } = await authenticate.admin(request);
const { shop, accessToken } = session;
const myShop = shop.replace(“.myshopify.com”, “”);

const url = new URL(request.url);
const planType = url.searchParams.get(“plan”) || “monthly”;
const selectedPlan = planType === “annual” ? ANNUAL_PLAN : MONTHLY_PLAN;

// Check for active subscription
const check = await billing.check({
plans: [selectedPlan],
isTest: true,
});

if (check.hasActiveSubscription) {
// Already subscribed → assign and return
const subscription = check.appSubscriptions[0];
await assignPaidPlan(shop, accessToken, subscription);
return redirect(“/app/plans”);
}

// Otherwise, initiate billing flow
const { confirmationUrl } = await billing.request({
plan: selectedPlan,
isTest: true,
trialDays: 3,
returnUrl: [https://admin.shopify.com/store/](https://admin.shopify.com/store/)${myShop}/apps/${process.env.APP_NAME}/app/plans,
});

return redirect(confirmationUrl);
};