Learn how to set up and manage subscription trials with Stripe API, including trial periods, handling trial ends, cancellations, and analytics. Step-by-step guide.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
How to Implement Subscription Trials with Stripe API
Step 1: Set Up Your Stripe Account
Before implementing subscription trials, you need to set up your Stripe account and install the Stripe library in your project.
For Node.js, install the Stripe library:
npm install stripe
For PHP:
composer require stripe/stripe-php
For Python:
pip install stripe
Step 2: Initialize Stripe in Your Project
Initialize the Stripe client with your secret key.
For Node.js:
const stripe = require('stripe')('sk_test_YourSecretKey');
// For ES modules
// import Stripe from 'stripe';
// const stripe = new Stripe('sk_test_YourSecretKey');
For PHP:
\Stripe\Stripe::setApiKey('sk_test_YourSecretKey');
For Python:
import stripe
stripe.api_key = 'sk_test\_YourSecretKey'
Step 3: Create Products and Prices with Trial Parameters
Before setting up subscriptions with trials, you need to create a product and a price.
For Node.js:
// Create a product
const product = await stripe.products.create({
name: 'Premium Plan',
description: 'Access to premium features',
});
// Create a price with recurring parameters
const price = await stripe.prices.create({
product: product.id,
unit\_amount: 1999, // Amount in cents (19.99 USD)
currency: 'usd',
recurring: {
interval: 'month', // 'day', 'week', 'month' or 'year'
},
});
Step 4: Create a Subscription with a Trial Period
There are two main ways to implement trials with Stripe:
trial_period_days
when creating a subscriptiontrial_end
with a specific timestampMethod 1: Using trial_period_days
// Create a customer first
const customer = await stripe.customers.create({
email: '[email protected]',
name: 'Jenny Rosen',
payment_method: 'pm_card\_visa', // Obtained from Stripe.js
});
// Set the payment method as the default
await stripe.customers.update(customer.id, {
invoice\_settings: {
default_payment_method: 'pm_card_visa',
},
});
// Create a subscription with a 14-day trial
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [
{
price: price.id,
},
],
trial_period_days: 14, // 14-day trial
payment\_settings: {
payment_method_types: ['card'],
save_default_payment_method: 'on_subscription',
},
expand: ['latest_invoice.payment_intent'],
});
Method 2: Using trial_end with a specific timestamp
// Calculate trial end date (e.g., 30 days from now)
const trialEnd = Math.floor(Date.now() / 1000) + (30 _ 24 _ 60 \* 60); // 30 days in seconds
// Create a subscription with a specific trial end date
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [
{
price: price.id,
},
],
trial\_end: trialEnd,
payment\_settings: {
payment_method_types: ['card'],
save_default_payment_method: 'on_subscription',
},
});
Step 5: Handle the Trial End
When a trial ends, Stripe automatically attempts to charge the customer. You should set up webhook handling to detect trial-related events.
// Express route handler for webhooks
app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
request.body,
sig,
'whsec\_YourWebhookSecret'
);
} catch (err) {
response.status(400).send(`Webhook Error: ${err.message}`);
return;
}
// Handle specific events
switch (event.type) {
case 'customer.subscription.trial_will_end':
// Triggered 3 days before trial ends
const subscription = event.data.object;
console.log(`Trial for subscription ${subscription.id} will end soon.`);
// Notify the customer that their trial will end soon
break;
case 'customer.subscription.updated':
const updatedSubscription = event.data.object;
// Check if the subscription has moved from trial to active
if (event.data.previous\_attributes.status === 'trialing' &&
updatedSubscription.status === 'active') {
console.log(`Subscription ${updatedSubscription.id} has converted from trial to active.`);
// Handle successful trial to paid conversion
}
break;
case 'invoice.payment\_failed':
// Handle failed payment at the end of the trial
const invoice = event.data.object;
console.log(`Payment failed for invoice ${invoice.id}`);
// Notify the customer about the failed payment
break;
}
response.send();
});
Step 6: Implement a Free Trial Without Requiring Payment Information
If you want to offer a trial without collecting payment information upfront, you can use Stripe Checkout with a trial and collect payment information later.
// Create a Checkout Session with a trial
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line\_items: [
{
price: price.id,
quantity: 1,
},
],
mode: 'subscription',
subscription\_data: {
trial_period_days: 14,
},
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel\_url: 'https://example.com/cancel',
});
Alternatively, you can create a subscription with a trial without requiring immediate payment:
// Create a customer
const customer = await stripe.customers.create({
email: '[email protected]',
name: 'Jenny Rosen',
});
// Create a subscription with trial but no payment method yet
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [
{
price: price.id,
},
],
trial_period_days: 14,
payment\_settings: {
save_default_payment_method: 'on_subscription',
},
collection_method: 'send_invoice', // This prevents automatic charge attempts
days_until_due: 14, // Number of days before the invoice is due
});
Step 7: Handle Trial Cancellations
Allow customers to cancel during the trial period without being charged.
// Cancel a subscription immediately
const canceledSubscription = await stripe.subscriptions.del(
'sub\_1234567890'
);
// Cancel at the end of the trial period
const subscription = await stripe.subscriptions.update(
'sub\_1234567890',
{
cancel_at_period\_end: true,
}
);
Step 8: Extend a Trial Period
Sometimes you may want to extend a customer's trial:
// Extend trial by updating the trial\_end timestamp
const extendedTrialTimestamp = Math.floor(Date.now() / 1000) + (30 _ 24 _ 60 \* 60); // 30 more days
const subscription = await stripe.subscriptions.update(
'sub\_1234567890',
{
trial\_end: extendedTrialTimestamp,
proration\_behavior: 'none', // Don't create prorations for this change
}
);
Step 9: Track Trial Conversions and Analytics
To track how well your trials convert to paid subscriptions, use Stripe's Analytics or implement custom tracking:
// Get all subscriptions that were on trial and are now active
const subscriptions = await stripe.subscriptions.list({
status: 'active',
limit: 100,
});
// Filter subscriptions that converted from trial
const convertedSubscriptions = subscriptions.data.filter(
sub => sub.trial_start && sub.trial_end && Date.now() / 1000 > sub.trial\_end
);
console.log(`Trial conversion rate: ${convertedSubscriptions.length / subscriptions.data.length * 100}%`);
Step 10: Implement Trial-Specific User Interfaces
Create front-end elements to show trial status to users:
// Client-side JavaScript to display trial information
async function displayTrialInfo() {
// Fetch subscription data from your backend
const response = await fetch('/api/subscription-status');
const subscription = await response.json();
const trialEndDate = new Date(subscription.trial\_end \* 1000);
const today = new Date();
const daysRemaining = Math.ceil((trialEndDate - today) / (1000 _ 60 _ 60 \* 24));
if (subscription.status === 'trialing') {
document.getElementById('trial-banner').innerHTML = \`
Your trial ends in ${daysRemaining} days on ${trialEndDate.toLocaleDateString()}.
\`;
}
}
Conclusion
Implementing subscription trials with Stripe involves creating products and prices, setting up subscriptions with trial parameters, and handling the end of the trial period. By using Stripe's robust API and webhook system, you can offer flexible trial options to your customers while ensuring a smooth transition to paid subscriptions when the trial ends.
Remember to test thoroughly in Stripe's test mode before moving to production. Additionally, make sure to handle edge cases such as failed payments at the end of trials and provide clear communication to your users about their trial status and expiration.
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.