Vibestacks LogoVibestacks
IntegrationsStripe & Payments

Free Trials

Configure free trial periods for your subscription plans. Learn how trials work, prevent abuse, and handle trial lifecycle events.

Vibestacks supports free trials out of the box. Users can try your premium features before being charged.

How Trials Work

  1. User clicks "Start Free Trial" on your pricing page
  2. They're redirected to Stripe Checkout (card required, but not charged)
  3. Subscription is created with status: "trialing"
  4. After trial ends, Stripe automatically charges the card
  5. If payment fails, subscription moves to past_due status

Card Required

Stripe requires a payment method to start a trial. This reduces abuse and improves conversion rates since users are already set up for payment.

Enabling Trials

Add a trial configuration to any paid plan:

config/app.ts
{
  name: "pro",
  priceId: "price_xxx",
  trial: {
    enabled: true,
    days: 14,       // Trial length
  },
  // ...
}

Trial Options

OptionTypeDescription
enabledbooleanEnable/disable trial for this plan
daysnumberNumber of trial days (typically 7-30)

Disabling Trials

Set trial: null to disable trials for a plan:

{
  name: "starter",
  trial: null,  // No trial for this plan
  // ...
}

UI Changes

When a plan has a trial enabled, the pricing UI automatically:

  • Shows a "14-day free trial" badge on the card
  • Changes button text to "Start 14-Day Trial"

No additional code changes needed.

Trial Abuse Prevention

Better Auth's Stripe plugin automatically prevents trial abuse:

  • One trial per user - Users can only get one free trial, ever
  • Across all plans - If they trial Plan A, they can't trial Plan B
  • Tracks by account - Based on user ID, not email or card

This is enforced automatically. When a user who's had a trial tries to start another one, they'll be charged immediately instead.

No Configuration Needed

Trial abuse prevention is built into Better Auth. You don't need to configure anything - it just works.

Checking Trial Status

Use the subscription data to check if a user is trialing:

// In a server component or API route
const subscription = await getActiveSubscription(userId);

if (subscription?.status === "trialing") {
  // User is in trial
  const trialEnd = subscription.trialEnd;
  const daysLeft = Math.ceil(
    (new Date(trialEnd).getTime() - Date.now()) / (1000 * 60 * 60 * 24)
  );
}

Subscription Status Values

StatusMeaning
trialingIn free trial period
activePaying customer
past_duePayment failed, retrying
canceledSubscription ended
incompleteInitial payment failed

Trial Lifecycle Emails

You can send emails at key trial moments. Configure these in lib/auth.ts:

lib/auth.ts
// Inside the stripe plugin configuration
...(plan.trial?.enabled && {
  freeTrial: {
    days: plan.trial.days,
    onTrialStart: async (subscription) => {
      // Send welcome email
      await sendTrialStartEmail({
        email: subscription.user.email,
        planName: plan.name,
        trialDays: plan.trial.days,
      });
    },
    onTrialEnd: async ({ subscription }) => {
      // Send "trial ending" email (3 days before)
      await sendTrialEndingEmail({
        email: subscription.user.email,
        planName: plan.name,
      });
    },
    onTrialExpired: async (subscription) => {
      // Send "trial expired" email (if they didn't convert)
      await sendTrialExpiredEmail({
        email: subscription.user.email,
        planName: plan.name,
      });
    },
  },
}),

TODO

Trial lifecycle emails are marked as TODO in the codebase. See Lifecycle Emails for implementation details.

Displaying Trial Status in UI

Show users their trial status in your dashboard:

components/trial-banner.tsx
"use client";

import { useSubscription } from "@/hooks/use-subscription";

export function TrialBanner() {
  const { subscription, isTrialing } = useSubscription();
  
  if (!isTrialing || !subscription?.trialEnd) {
    return null;
  }
  
  const daysLeft = Math.ceil(
    (new Date(subscription.trialEnd).getTime() - Date.now()) / 
    (1000 * 60 * 60 * 24)
  );
  
  return (
    <div className="bg-blue-50 border-l-4 border-blue-400 p-4">
      <p className="text-sm text-blue-700">
        Your free trial ends in <strong>{daysLeft} days</strong>.
        <a href="/dashboard/billing" className="underline ml-1">
          Upgrade now
        </a>
      </p>
    </div>
  );
}

Best Practices

Trial Length

DurationBest For
7 daysSimple products, quick value realization
14 daysMost SaaS products (recommended)
30 daysComplex products, enterprise

Conversion Tips

  1. Require a card - Stripe does this by default, improves conversion
  2. Send reminder emails - 3 days and 1 day before trial ends
  3. Show value early - Onboard users to key features quickly
  4. Display trial status - Always show days remaining in UI

Don't Offer Trials On

  • Free plans - Doesn't make sense
  • Lowest paid tier - Consider just lowering the price instead
  • Enterprise plans - Handle these with custom sales process

Stripe Dashboard

You can see trial subscriptions in Stripe Dashboard:

  1. Go to Subscriptions
  2. Filter by Status: Trialing
  3. See trial end dates and upcoming conversions

Common Issues

FAQ

Next Steps