Back

How to Add Stripe Embedded Checkout to Rails 8

Deloris ThompsonMonday, August 18, 2025
How to Add Stripe Embedded Checkout to Rails 8

Stripe's embedded checkout allows you to accept payments directly within your Rails app, eliminating the need to redirect users to external pages. This guide will help you to get it working with Rails 8 and Hotwire.

What You'll Build

A page that renders Stripe's embedded checkout form directly in your Rails app. That's it. No database, no user management, no webhooks - just the core integration.

Prerequisites

  • Rails 8 app with Hotwire
  • Stripe account (test mode or sandbox)

Step 1: Set up Dependencies

Add the following directly to your Gemfile and run bundle install:
Ruby Gems: Stripe

gem 'stripe', '~> 15.3' gem 'dotenv-rails', '~> 3.1', '>= 3.1.8'

Add the JavaScript SDK:

NPM npm install @stripe/stripe-js yarn yarn add @stripe/stripe-js

Step 2: Configure Stripe

Add the following to your .env file

STRIPE_PUBLISHABLE_KEY=pk_test_your_publishable_key_here
STRIPE_SECRET_KEY=sk_test_your_secret_key_here
STRIPE_PRICE_ID=price_your_product_price_id_here

Create the initializer:

# config/initializers/stripe.rb
Stripe.api_key = ENV["STRIPE_SECRET_KEY"]

Step 3: Create the Checkout Service

This service class handles the Stripe API integration with clean, focused responsibility

# app/services/checkout_service.rb class CheckoutService def initialize(return_url:) @return_url = return_url end def create_checkout_session Stripe::Checkout::Session.create({ line_items: [{ price: ENV["STRIPE_PRICE_ID"], quantity: 1 }], mode: "payment", payment_method_types: ["card"], return_url: @return_url, ui_mode: "embedded" }) end end

Step 4: Create the Stimulus Controller & Register it

Run the following command in your terminal to generate the controller and register it in the app/javascript/controllers/index.js file

./bin/rails generate stimulus stripeCheckout
// 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 } async connect() { const stripe = await loadStripe(this.publishableKeyValue) const checkout = await stripe.initEmbeddedCheckout({ clientSecret: this.clientSecretValue }); checkout.mount(this.element); } }

This Stimulus controller handles the frontend payment interface with minimal code:
Configuration: The controller expects two data attributes from the Rails view:

  • publishableKey - Your Stripe public key for client-side operations
  • clientSecret - The checkout session secret from your Rails controller

The connect() method runs automatically when the controller connects to a DOM element and:

  • Loads the Stripe JavaScript library using your publishable key
  • Initializes Stripe's embedded checkout component with the client secret
  • Mounts the complete checkout form directly into the HTML element

Step 5: Update the Desired Controller

This Rails controller handles the core functionality of a Stripe checkout flow in just two actions:
The show action initiates the checkout process by:

  • Creating a new CheckoutService instance with a return URL for post-payment redirects
  • Generating a Stripe checkout session through the service
  • Extracting the client_secret from the session to pass to the frontend for payment processing

The return action handles the post-payment flow by:

  • Processing successful payments (this is where you'd typically update order status, send confirmation emails, etc.)
  • Redirecting users back to the homepage with a success message
# app/controllers/checkout_controller.rb class CheckoutController < ApplicationController def show checkout_service = CheckoutService.new(return_url: return_checkout_url) checkout_session = checkout_service.create_checkout_session @client_secret = checkout_session.client_secret end def return # Handle successful payment redirect_to root_path, notice: "Payment successful!" end end

Step 6: Set up Routes

# config/routes.rb Rails.application.routes.draw do root "checkout#show" resource :checkout, only: [:show] do get :return, on: :collection end end

Step 7: Create the View

<!-- app/views/checkout/show.html.erb --> <div class="container mx-auto px-4 py-8"> <h1 class="text-2xl font-bold mb-6">Complete Your Purchase</h1> <div class="max-w-md mx-auto"> <div data-controller="stripe-checkout" data-stripe-checkout-publishable-key-value="<%= ENV['STRIPE_PUBLISHABLE_KEY'] %>" data-stripe-checkout-client-secret-value="<%= @client_secret %>"> <!-- Stripe embedded checkout loads here --> </div> </div> </div>

Simple Stripe Checkout View
This minimal Rails view creates a clean checkout page with just a few lines of HTML:
The Structure:

  • Uses Tailwind CSS for styling with a centered container layout
  • Displays a "Complete Your Purchase" heading
  • Contains a div that connects to the Stimulus controller

The Magic Happens in the data-controller div:

  • data-controller="stripe-checkout" connects to your Stimulus controller
  • data-stripe-checkout-publishable-key-value passes your Stripe public key from environment variables
  • data-stripe-checkout-client-secret-value passes the checkout session secret from your Rails controller

The Result: When the page loads, the Stimulus controller automatically transforms the empty div into a complete Stripe checkout form with card fields, payment buttons, and error handling.
Pro Tip: You can extract this into a partial for reusability:

Testing

  1. Start your server: ./bin/dev
  2. Visit http://localhost:3000
  3. Test with card: 4242 4242 4242 4242

Don't Forget - Additional Setup Required

This guide gets Stripe embedded checkout working, but for a production application, you'll need:

Required for Production

  • Webhooks - Handle payment events (checkout.session.completed, payment_intent.succeeded)
  • Database models - Store orders, payments, and customer data
  • User authentication - Track who made purchases
  • Error handling - Handle Stripe API failures gracefully

That's it! You now have Stripe embedded checkout working in Rails 8. The checkout form renders directly in your app without any redirects. At Echobind, we have experience working with Stripe and can help you integrate it in a new or exisiting application.

Share this post

twitterfacebooklinkedin

Interested in working with us?

Give us some details about your project, and our team will be in touch with how we can help.

Get in Touch