Matthew Thompson

Matthew Thompson

Software Architect | Craftsman | Mentor

Stripe Embedded Checkout with Rails Stimulus

Published on March 24, 2025

Implementing Stripe Embedded Checkout with Rails and Stimulus.js

Stripe's Embedded Components revolutionize the checkout experience by allowing developers to create seamless, secure payment flows directly within their applications. Unlike traditional redirect-based checkouts, embedded components keep users in your application while maintaining Stripe's robust security and reliability.

In this guide, we'll walk through implementing Stripe's Embedded Checkout in a Ruby on Rails application using Stimulus.js. We'll create a complete checkout flow that can be customized to match your application's design while leveraging Stripe's powerful payment infrastructure.

Prerequisites

Before we begin, ensure you have:

  • A Rails application (Rails 7+ recommended)
  • Stimulus.js installed
  • A Stripe account with API keys
  • The stripe gem installed

Setting Up Stripe

First, add the Stripe gem to your Gemfile:

# Gemfile
gem 'stripe'

Then install the required JavaScript packages:

yarn add @stripe/stripe-js

Implementation Steps

1. Create the Checkout Controller

First, let's create a controller to handle the checkout session creation:

# app/controllers/checkout_controller.rb
class CheckoutController < ApplicationController
  def create
    @checkout_session = Stripe::Checkout::Session.create({
      ui_mode: 'embedded',
      payment_method_types: ['card'],
      line_items: [{
        price: 'price_H5ggYwtDq4fbrJ', # Replace with your price ID
        quantity: 1,
      }],
      mode: 'payment',
      return_url: "#{request.base_url}/checkout/success",
      metadata: {
        order_id: '123' # Add any relevant metadata
      }
    })

    respond_to do |format|
      format.json { render json: { client_secret: @checkout_session.client_secret } }
    end
  end
end

2. Create the Stimulus Controller

Next, create a Stimulus controller to handle the embedded checkout:

// app/javascript/controllers/stripe_checkout_controller.js
import { Controller } from "@hotwired/stimulus"
import { loadStripe } from '@stripe/stripe-js'

export default class extends Controller {
  static values = {
    publishableKey: String,
    clientSecret: String
  }

  connect() {
    this.initializeCheckout()
  }

  async initializeCheckout() {
    try {
      this.stripe = await loadStripe(this.publishableKeyValue)
      const checkout = await this.stripe.initEmbeddedCheckout({
        clientSecret: this.clientSecretValue
      });

      // Mount the checkout element
      checkout.mount(this.element);
    } catch (error) {
      console.error('Error initializing Stripe checkout:', error);
      // Handle error appropriately
    }
  }
}

3. Create the View

Create a view to display the checkout:

app/views/checkout/show.html.erb

<div class="checkout-container">
  <div
    data-controller="stripe-checkout"
    data-stripe-checkout-publishable-key-value="<%= Rails.application.credentials.stripe[:publishable_key] %>"
    data-stripe-checkout-client-secret-value="<%= @checkout_session.client_secret %>"
  ></div>
</div>

Security Considerations

  • Always use environment variables or Rails credentials for sensitive keys
  • Implement proper CSRF protection
  • Use HTTPS in production
  • Validate all incoming webhook events
  • Implement proper error handling and logging

Additional Resources

Conclusion

By implementing Stripe's Embedded Checkout with Rails and Stimulus.js, you can create a seamless payment experience that keeps users in your application while maintaining the highest security standards. The embedded components handle all the complex payment logic, allowing you to focus on creating a great user experience.

Remember to test thoroughly in Stripe's test mode before going live, and always follow security best practices when handling payment information.