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
- User clicks "Start Free Trial" on your pricing page
- They're redirected to Stripe Checkout (card required, but not charged)
- Subscription is created with
status: "trialing" - After trial ends, Stripe automatically charges the card
- If payment fails, subscription moves to
past_duestatus
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:
{
name: "pro",
priceId: "price_xxx",
trial: {
enabled: true,
days: 14, // Trial length
},
// ...
}Trial Options
| Option | Type | Description |
|---|---|---|
enabled | boolean | Enable/disable trial for this plan |
days | number | Number 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
| Status | Meaning |
|---|---|
trialing | In free trial period |
active | Paying customer |
past_due | Payment failed, retrying |
canceled | Subscription ended |
incomplete | Initial payment failed |
Trial Lifecycle Emails
You can send emails at key trial moments. Configure these in 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:
"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
| Duration | Best For |
|---|---|
| 7 days | Simple products, quick value realization |
| 14 days | Most SaaS products (recommended) |
| 30 days | Complex products, enterprise |
Conversion Tips
- Require a card - Stripe does this by default, improves conversion
- Send reminder emails - 3 days and 1 day before trial ends
- Show value early - Onboard users to key features quickly
- 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:
- Go to Subscriptions
- Filter by Status: Trialing
- See trial end dates and upcoming conversions
Common Issues
FAQ
Next Steps
- Lifecycle Emails - Set up trial notification emails
- Billing Portal - Let users manage their subscription
Plans & Pricing
Configure subscription plans, pricing tiers, features, and limits in Vibestacks. Learn how to create products in Stripe and sync them with your app.
Webhooks
Understand how Stripe webhooks work in Vibestacks. Learn about automatic event handling, custom event processing, and webhook security.