npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

stripe-donation-widget

v1.1.1

Published

A complete, reusable donation system for React/Next.js applications with Stripe integration, real-time MRR tracking, and beautiful UI components.

Downloads

135

Readme

🎯 Stripe Donation Widget for React/Next.js

A complete, reusable donation system with Stripe integration, real-time MRR tracking, and beautiful UI components.

✨ Features

  • 🎨 Beautiful UI Components - Pre-built donation widgets and buttons
  • 💳 Stripe Integration - Secure payment processing with automatic product creation
  • 📊 Real-time MRR Tracking - Live subscription analytics and goal progress
  • 🔧 Configuration-driven - Single config object controls all behavior
  • 🎯 Multi-project Support - Isolated configurations per project
  • 📱 Responsive Design - Works perfectly on all devices
  • ⚡ TypeScript Support - Full type safety and IntelliSense
  • 🚀 One-Command Setup - CLI tool generates everything automatically

🚀 Quick Start (30 seconds!)

1. Install & Initialize

# Install the package
npm install stripe-donation-widget

# Generate all necessary files automatically
npx stripe-donation-widget init

That's it! The CLI will:

  • ✅ Create API routes (/api/donation/*)
  • ✅ Generate example support page
  • ✅ Set up environment variables template
  • ✅ Create setup documentation
  • ✅ Detect App Router vs Pages Router automatically

2. Add Your Stripe Keys

Update .env.local with your keys:

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...

3. Customize & Launch

// The CLI creates this file for you at app/support/page.tsx
import { DonationWidget } from 'stripe-donation-widget';

const config = {
  stripePublishableKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
  projectName: "Your Project",
  projectSlug: "your-project",
  monthly: { suggested: 5.00 },
  annual: { suggested: 50.00 },
  goal: { target: 100, showProgress: true }
};

export default function SupportPage() {
  return <DonationWidget config={config} />;
}

🎯 What Gets Generated

The CLI creates everything you need:

your-project/
├── app/api/donation/
│   ├── create-checkout-session/route.ts  # Stripe checkout
│   ├── stats/route.ts                    # MRR analytics  
│   └── webhook/route.ts                  # Webhook handling
├── app/support/page.tsx                  # Example support page
├── .env.example                          # Environment template
├── .env.local                           # Your actual keys
└── DONATION_SETUP.md                    # Setup guide

📦 Manual Installation (Alternative)

If you prefer manual setup:

1. Install the Package

npm install stripe-donation-widget

2. Create API Routes

app/api/donation/create-checkout-session/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { DonationStripeManager } from 'stripe-donation-widget/server';

export async function POST(request: NextRequest) {
  try {
    const sessionData = await request.json();
    const manager = new DonationStripeManager(process.env.STRIPE_SECRET_KEY!);
    const result = await manager.createCheckoutSession(sessionData);
    return NextResponse.json(result);
  } catch (error) {
    return NextResponse.json({ error: 'Failed to create checkout session' }, { status: 500 });
  }
}

app/api/donation/stats/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { DonationStripeManager } from 'stripe-donation-widget/server';

export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url);
    const projectSlug = searchParams.get('projectSlug');
    
    const manager = new DonationStripeManager(process.env.STRIPE_SECRET_KEY!);
    const stats = await manager.getSubscriptionSummary(projectSlug!);
    
    return NextResponse.json(stats);
  } catch (error) {
    return NextResponse.json({ error: 'Failed to fetch stats' }, { status: 500 });
  }
}

3. Use the Components

import { DonationWidget, DonationButton } from 'stripe-donation-widget';
import type { DonationConfig } from 'stripe-donation-widget';

const config: DonationConfig = {
  stripePublishableKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
  projectName: "My Project",
  projectSlug: "my-project",
  monthly: { suggested: 5.00 },
  annual: { suggested: 50.00 },
  goal: {
    target: 100,
    showProgress: true,
    description: "Help keep this project running",
    calculateFromSubscriptions: true
  }
};

export default function SupportPage() {
  return (
    <div className="max-w-2xl mx-auto p-6">
      <h1 className="text-3xl font-bold mb-8">Support Our Project</h1>
      
      {/* Full donation widget */}
      <DonationWidget config={config} />
      
      {/* Quick donation button */}
      <DonationButton 
        config={config} 
        type="monthly" 
        amount={10}
        className="mt-4"
      >
        Support for $10/month
      </DonationButton>
    </div>
  );
}

Components

DonationWidget

The main donation component with slider interface and goal tracking.

<DonationWidget
  config={donationConfig}
  showProgress={true}
  goal={1000}           // Override config goal
  current={250}         // Override current amount
  className="max-w-md"
  onSuccess={(sessionId) => console.log('Success:', sessionId)}
  onError={(error) => console.error('Error:', error)}
/>

Features:

  • Interactive slider for amount selection
  • Preset amount buttons
  • Monthly/Annual tabs
  • Real-time goal progress
  • Responsive design

DonationButton

Simple button for quick donations.

<DonationButton
  config={donationConfig}
  type="monthly"
  amount={25}
  className="w-full bg-gradient-to-r from-purple-500 to-pink-500"
>
  ❤️ Become a Supporter
</DonationButton>

Configuration Options

DonationConfig

interface DonationConfig {
  // Required
  stripePublishableKey: string;
  projectName: string;
  projectSlug: string; // Used for Stripe product IDs
  
  // Amount settings
  monthly: {
    suggested: number;
    min?: number;      // Defaults to 50% of suggested, minimum $1
    max?: number;      // Defaults to 10x suggested
  };
  annual: {
    suggested: number;
    min?: number;
    max?: number;
  };
  
  // Goal tracking
  goal?: {
    target: number;                    // Monthly goal amount
    current?: number;                  // Static current amount
    showProgress?: boolean;            // Show progress bar
    description?: string;              // Goal description
    calculateFromSubscriptions?: boolean; // Use real Stripe data
  };
  
  // Customization
  theme?: 'light' | 'dark' | 'auto';
  customAmounts?: boolean;             // Allow custom amounts
  currency?: string;                   // Default: 'usd'
  successUrl?: string;                 // Post-checkout redirect
  cancelUrl?: string;                  // Checkout cancel redirect
}

Real MRR Calculation

When calculateFromSubscriptions: true, the library automatically:

  1. Fetches active subscriptions from Stripe
  2. Filters by project using projectSlug
  3. Calculates MRR as: Monthly Revenue + (Annual Revenue ÷ 12)
  4. Updates progress in real-time

Example calculation:

  • 5 monthly subscribers at $10/month = $50 MRR
  • 2 annual subscribers at $100/year = $16.67 MRR ($200 ÷ 12)
  • Total MRR: $66.67

Stripe Integration

Automatic Product Creation

The library automatically creates Stripe products using consistent IDs:

  • Monthly: {projectSlug}-monthly-donation
  • Annual: {projectSlug}-annual-donation

Dynamic Pricing

Uses price_data for flexible amount selection without pre-creating prices.

Subscription Tracking

Subscriptions are tagged with projectSlug metadata for accurate filtering.

Multi-Project Usage

Project A Configuration

const projectAConfig: DonationConfig = {
  projectName: "Project Alpha",
  projectSlug: "project-alpha",
  monthly: { suggested: 5.00 },
  annual: { suggested: 50.00 },
  // ... other config
};

Project B Configuration

const projectBConfig: DonationConfig = {
  projectName: "Project Beta", 
  projectSlug: "project-beta",
  monthly: { suggested: 10.00 },
  annual: { suggested: 100.00 },
  // ... other config
};

Each project gets:

  • ✅ Separate Stripe products
  • ✅ Independent MRR tracking
  • ✅ Isolated subscription data
  • ✅ Custom branding and amounts

Styling & Theming

Custom Styling

<DonationWidget 
  config={config}
  className="border-2 border-purple-500 rounded-xl shadow-lg"
/>

<DonationButton
  config={config}
  type="monthly"
  className="bg-gradient-to-r from-blue-500 to-green-500 hover:scale-105"
>
  🚀 Launch Support
</DonationButton>

Theme Support

The library respects your app's theme system through CSS variables.

Error Handling

<DonationWidget
  config={config}
  onError={(error) => {
    // Log to your error tracking service
    console.error('Donation error:', error);
    
    // Show user-friendly message
    toast.error('Something went wrong. Please try again.');
  }}
  onSuccess={(sessionId) => {
    // Track successful checkout initiation
    analytics.track('donation_checkout_started', { sessionId });
  }}
/>

TypeScript Support

Full TypeScript support with comprehensive type definitions:

import type { 
  DonationConfig,
  DonationWidgetProps,
  DonationButtonProps,
  SubscriptionSummary,
  CheckoutSessionData
} from '@/lib/donation';

Best Practices

1. Configuration Management

// config/donations.ts
export const getDonationConfig = (project: string): DonationConfig => {
  const baseConfig = {
    stripePublishableKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
    currency: 'usd',
    customAmounts: true,
  };
  
  switch (project) {
    case 'project-a':
      return { ...baseConfig, projectName: 'Project A', projectSlug: 'project-a', /* ... */ };
    case 'project-b':
      return { ...baseConfig, projectName: 'Project B', projectSlug: 'project-b', /* ... */ };
    default:
      throw new Error(`Unknown project: ${project}`);
  }
};

2. Error Boundaries

import { ErrorBoundary } from 'react-error-boundary';

<ErrorBoundary fallback={<div>Donation widget unavailable</div>}>
  <DonationWidget config={config} />
</ErrorBoundary>

3. Loading States

import { Suspense } from 'react';

<Suspense fallback={<DonationSkeleton />}>
  <DonationWidget config={config} />
</Suspense>

Migration Guide

From Static Goals to Real MRR

Before:

goal: {
  target: 100,
  current: 25, // Static value
  showProgress: true
}

After:

goal: {
  target: 100,
  showProgress: true,
  calculateFromSubscriptions: true // Uses real Stripe data
}

From Text Inputs to Sliders

The new slider interface is automatically enabled. To revert to text inputs, you would need to modify the component (not recommended).

Troubleshooting

Common Issues

1. "Event handlers cannot be passed to Client Component props"

  • Remove onSuccess and onError from server components
  • Move to client components if needed

2. "Stripe product not found"

  • Ensure projectSlug is consistent
  • Check Stripe dashboard for auto-created products

3. "MRR calculation shows 0"

  • Verify calculateFromSubscriptions: true
  • Check that subscriptions have correct metadata
  • Ensure API route is accessible

4. "Slider not working on mobile"

  • Ensure @radix-ui/react-slider is installed
  • Check for CSS conflicts

Debug Mode

const config: DonationConfig = {
  // ... your config
  debug: true // Enable console logging (if implemented)
};

License

MIT License - feel free to use in your projects!

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Submit a pull request

Ready to accept donations in minutes! 🚀