A high refund rate signals trouble—whether that's payment processing errors, product issues, or fraud. Stripe makes it straightforward to see how many charges end up refunded. Here's how to pull that data and track it over time.
View refunds in the Stripe Dashboard
The fastest way to spot refund patterns is Stripe's built-in dashboard. You can filter by date range and payment method to see where refunds cluster.
Navigate to the Refunds view
Log into your Stripe account and go to Payments > Refunds. You'll see a table listing all refunds, sorted by date. Filter by Status, Payment method, Application, or Date range to narrow results. This view is read-only and updated in real time.
Export refund data for analysis
Click the More button (⋯) above the refund table and select Export to CSV. This exports the full list with timestamps, amounts, and reasons. Use this for importing into analytics tools or calculating metrics in a spreadsheet.
// After exporting, calculate refund rate in your analytics tool:
const refundRate = (totalRefunds / totalCharges) * 100;
console.log(`Refund rate: ${refundRate.toFixed(2)}%`);
// Example: 45 refunds out of 1000 charges = 4.5% refund ratePull refund data programmatically via the Stripe API
For continuous monitoring or automated reporting, query the Stripe API directly. You can fetch refunds with filters and calculate rates in real time.
Fetch all refunds using the Stripe SDK
Use the Stripe Node SDK to list all refunds within a date range. The refunds.list() method returns paginated results, so use limit and starting_after to handle large datasets. Always set a specific date range to keep response times reasonable.
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const refunds = await stripe.refunds.list({
limit: 100,
created: {
gte: Math.floor(Date.now() / 1000) - 30 * 24 * 60 * 60 // Last 30 days
}
});
console.log(`Found ${refunds.data.length} refunds in the last 30 days`);
refunds.data.forEach(r => {
console.log(`Refund: $${(r.amount / 100).toFixed(2)} - ${r.reason}`);
});Count charged vs. refunded transactions
Fetch all charges in the same period, then calculate what percentage were refunded. Stripe's Charge object includes refunded: true or refunded: false, so you can count directly. Note that a charge with a partial refund still counts as refunded.
const charges = await stripe.charges.list({
limit: 100,
created: {
gte: Math.floor(Date.now() / 1000) - 30 * 24 * 60 * 60
}
});
const refundedCharges = charges.data.filter(c => c.refunded).length;
const totalCharges = charges.data.length;
const refundRate = (refundedCharges / totalCharges) * 100;
console.log(`Total charges: ${totalCharges}`);
console.log(`Refunded: ${refundedCharges}`);
console.log(`Refund rate: ${refundRate.toFixed(2)}%`);Store results for trend tracking
Save refund counts and rates to your database or analytics backend on a schedule (e.g., daily cron job). This lets you spot trends over weeks or months, not just point-in-time snapshots. Store the raw numbers and calculated rate.
const metric = {
date: new Date().toISOString(),
refundRate: refundRate,
totalRefunds: refundedCharges,
totalCharges: totalCharges,
refundedAmount: charges.data
.filter(c => c.refunded)
.reduce((sum, c) => sum + c.amount, 0) / 100
};
await database.refundMetrics.insert(metric);
console.log(`Stored metric: ${metric.refundRate.toFixed(2)}% refund rate`);starting_after, or use the export CSV approach instead.Set up automated refund monitoring
Rather than manually checking refunds, set up webhooks to track refunds in real time and alert you to unusual activity.
Enable refund webhooks
Go to Developers > Webhooks in your Stripe dashboard. Click Add endpoint and subscribe to charge.refunded events. This fires whenever a refund is created, so you can log it immediately to your monitoring system.
const express = require('express');
const app = express();
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
sig,
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
res.status(400).send(`Webhook Error: ${err.message}`);
return;
}
if (event.type === 'charge.refunded') {
const refund = event.data.object;
console.log(`Refund: $${(refund.amount / 100).toFixed(2)} on charge ${refund.id}`);
// Log to your analytics backend
}
res.json({ received: true });
});Alert on spike in refunds
In your webhook handler, compare the refund count to a rolling average. If refunds exceed 10% above normal, send a Slack or email alert. This catches sudden issues (failed payment flow, fraud) before they spiral.
const dailyRefundCount = await database.getDailyRefundCount();
const avgRefundRate = (dailyRefundCount.sum / dailyRefundCount.days);
const threshold = avgRefundRate * 1.1; // Alert if 10% above average
if (dailyRefundCount.today > threshold) {
await slack.send({
text: `⚠️ Refund rate is high today: ${dailyRefundCount.today} refunds (avg: ${avgRefundRate.toFixed(2)})`
});
}Common Pitfalls
- Not accounting for partial refunds: A charge with multiple refunds is still counted as one refunded charge in Stripe's data. If you're tracking revenue impact, sum the refund amounts instead of counting refunds.
- Ignoring the reason field: Refunds due to
fraudulentorduplicateare fundamentally different fromcustomer_request. Slice your analysis by reason to see what's actually driving your refund rate. - Not filtering by payment status: Some charges fail before settlement. Include only settled or successful charges when calculating refund rate, or your denominator will be inflated.
- Missing timezone issues: Stripe uses UTC for timestamps. If you're reporting by day, be careful about off-by-one errors when converting to your local timezone.
Wrapping Up
Tracking refund rate in Stripe is essential—it's the fastest signal that something's wrong with payments, your product, or fulfillment. Pull data from the dashboard for quick checks, use the API for programmatic tracking, and set up webhooks to catch spikes early. If you want to track this automatically across tools, Product Analyst can help.