Skip to content

VueStripeCheckout

A button component that redirects users to Stripe's hosted checkout page for completing payments.

Simple Integration

StripeCheckout requires only a VueStripeProvider wrapper - no VueStripeElements or clientSecret needed. It's the simplest way to accept payments with Stripe.

What is Stripe Checkout?

Stripe Checkout provides a hosted, pre-built payment page:

FeatureDescription
Hosted by StripeSecure, PCI-compliant payment page
Automatic Payment MethodsCards, wallets, bank transfers based on customer location
Built-in FeaturesDiscounts, taxes, shipping, receipts included
No Custom UIZero frontend payment UI development needed

How It Works

┌─────────────────────────────────────────────────────────────┐
│  1. Create Checkout Session on your backend                 │
│     Returns: session_id (cs_...)                            │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│  2. StripeCheckout component renders a button               │
│     Pass: sessionId OR priceId + mode                       │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│  3. User clicks the checkout button                         │
│     StripeCheckout calls redirectToCheckout()               │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│  4. User redirected to Stripe's hosted checkout page        │
│     - Stripe handles payment UI                             │
│     - Stripe handles 3D Secure                              │
│     - Stripe handles payment method selection               │
└─────────────────────────────────────────────────────────────┘

              ┌───────────────┴───────────────┐
              ▼                               ▼
┌─────────────────────────┐     ┌─────────────────────────────┐
│  Payment Successful     │     │  Payment Cancelled          │
│                         │     │                             │
│  → successUrl           │     │  → cancelUrl                │
└─────────────────────────┘     └─────────────────────────────┘

Usage

vue
<template>
  <VueStripeProvider :publishable-key="publishableKey">
    <VueStripeCheckout
      :session-id="sessionId"
      button-text="Pay $49.99"
      @click="onCheckoutClick"
      @error="onCheckoutError"
    />
  </VueStripeProvider>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { VueStripeProvider, VueStripeCheckout } from '@vue-stripe/vue-stripe'

const publishableKey = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY
const sessionId = ref('')

onMounted(async () => {
  // Create Checkout Session on your server
  const response = await fetch('/api/create-checkout-session', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ priceId: 'price_xxx' })
  })
  const data = await response.json()
  sessionId.value = data.sessionId
})

const onCheckoutClick = () => {
  console.log('Redirecting to checkout...')
}

const onCheckoutError = (error) => {
  console.error('Checkout error:', error.message)
}
</script>

Price-Based Checkout

vue
<template>
  <VueStripeProvider :publishable-key="publishableKey">
    <VueStripeCheckout
      :price-id="priceId"
      mode="payment"
      :success-url="successUrl"
      :cancel-url="cancelUrl"
      button-text="Subscribe Now"
    />
  </VueStripeProvider>
</template>

<script setup>
import { VueStripeProvider, VueStripeCheckout } from '@vue-stripe/vue-stripe'

const publishableKey = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY
const priceId = 'price_xxx'
const successUrl = 'https://example.com/success'
const cancelUrl = 'https://example.com/cancel'
</script>

Props

PropTypeRequiredDefaultDescription
sessionIdstringNo*-Checkout Session ID (starts with cs_)
priceIdstringNo*-Price ID for client-side session creation
mode'payment' | 'subscription'No'payment'Checkout mode (only with priceId)
successUrlstringNowindow.location.origin + '/success'Redirect URL after successful payment
cancelUrlstringNowindow.location.origin + '/cancel'Redirect URL when user cancels
customerEmailstringNo-Pre-fill customer's email
clientReferenceIdstringNo-Reference ID for your application
submitType'auto' | 'book' | 'donate' | 'pay'No'auto'Button text on Stripe's checkout page
buttonTextstringNo'Checkout'Text displayed on the button
loadingTextstringNo'Redirecting...'Text shown during redirect
disabledbooleanNofalseDisable the checkout button
buttonClassstringNo'vue-stripe-checkout-button'Custom CSS class for the button
optionsPartial<RedirectToCheckoutOptions>No-Additional Stripe options

*Either sessionId or priceId is required.

Events

EventPayloadDescription
@click-Emitted when checkout button is clicked
@success-Emitted when redirect initiates successfully
@errorErrorEmitted when checkout fails

Error Event

ts
interface CheckoutError extends Error {
  message: string
  // Common error messages:
  // - "sessionId or priceId is required"
  // - "Stripe not initialized"
  // - "Session expired"
}

Slots

Default Slot

Customize the button content:

vue
<VueStripeCheckout :session-id="sessionId">
  <span class="custom-checkout">
    <IconCart /> Complete Purchase
  </span>
</VueStripeCheckout>

Loading Slot

Customize the loading state:

vue
<VueStripeCheckout :session-id="sessionId">
  <template #loading>
    <Spinner /> Please wait...
  </template>
</VueStripeCheckout>

Examples

With Custom Styling

vue
<template>
  <VueStripeProvider :publishable-key="publishableKey">
    <VueStripeCheckout
      :session-id="sessionId"
      button-class="my-checkout-button"
    >
      <span class="button-content">
        <CreditCardIcon />
        <span>Pay $99.00</span>
      </span>
    </VueStripeCheckout>
  </VueStripeProvider>
</template>

<style scoped>
.my-checkout-button {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 1rem 2rem;
  border: none;
  border-radius: 8px;
  font-size: 1rem;
  cursor: pointer;
}

.button-content {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
</style>

Subscription Checkout

vue
<template>
  <VueStripeProvider :publishable-key="publishableKey">
    <div class="pricing-card">
      <h3>Pro Plan</h3>
      <p class="price">$29/month</p>

      <VueStripeCheckout
        :price-id="proPriceId"
        mode="subscription"
        :success-url="successUrl"
        :cancel-url="cancelUrl"
        :customer-email="userEmail"
        button-text="Start Pro Plan"
      />
    </div>
  </VueStripeProvider>
</template>

With Error Handling

vue
<template>
  <VueStripeProvider :publishable-key="publishableKey">
    <div class="checkout-container">
      <VueStripeCheckout
        :session-id="sessionId"
        :disabled="!sessionId"
        @error="handleError"
      />

      <div v-if="error" class="error-message">
        {{ error }}
      </div>
    </div>
  </VueStripeProvider>
</template>

<script setup>
import { ref } from 'vue'

const error = ref(null)

const handleError = (err) => {
  error.value = err.message

  // Handle specific error types
  if (err.message.includes('Session expired')) {
    // Refresh the session
    refreshSession()
  }
}
</script>

Conditional Rendering

vue
<template>
  <VueStripeProvider :publishable-key="publishableKey">
    <div v-if="loading">
      Creating checkout session...
    </div>

    <VueStripeCheckout
      v-else-if="sessionId"
      :session-id="sessionId"
      button-text="Complete Purchase"
    />

    <div v-else class="error">
      Failed to create checkout session
    </div>
  </VueStripeProvider>
</template>

Backend Setup

Create Checkout Session (Node.js)

js
const stripe = require('stripe')('sk_test_...')

app.post('/api/create-checkout-session', async (req, res) => {
  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    line_items: [
      {
        price: req.body.priceId,
        quantity: 1
      }
    ],
    mode: 'payment', // or 'subscription'
    success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
    cancel_url: 'https://example.com/cancel'
  })

  res.json({ sessionId: session.id })
})

Using Stripe CLI

bash
# Create a one-time payment session
stripe checkout sessions create \
  --line-items[0][price]=price_xxx \
  --line-items[0][quantity]=1 \
  --mode=payment \
  --success-url=https://example.com/success \
  --cancel-url=https://example.com/cancel

TypeScript

ts
import { VueStripeProvider, VueStripeCheckout } from '@vue-stripe/vue-stripe'
import type { RedirectToCheckoutOptions } from '@stripe/stripe-js'

// Props typing
const sessionId: string = 'cs_test_...'
const priceId: string = 'price_xxx'
const mode: 'payment' | 'subscription' = 'payment'

// Additional options
const options: Partial<RedirectToCheckoutOptions> = {
  // Custom options if needed
}

// Event handlers
const handleClick = () => {
  console.log('Checkout started')
}

const handleError = (error: Error) => {
  console.error('Checkout failed:', error.message)
}

Session-Based vs Price-Based

AspectSession-BasedPrice-Based
SetupRequires backendFrontend only
FlexibilityFull control over session optionsLimited to basic options
SecurityMore secure (server-side)Less secure (client-side)
Use CaseProduction appsPrototypes, simple products
RecommendedYesFor testing only

Checkout vs Payment Element

FeatureCheckoutPayment Element
IntegrationSimple (redirect)Complex (embedded)
CustomizationLimitedFull control
LocationStripe-hostedYour site
PCI ComplianceStripe handlesYou manage
Development TimeMinutesHours/Days

Choose Checkout when you want the fastest integration with minimal code. Choose Payment Element when you need full UI customization.

See Also

Released under the MIT License.