DaaS / Products / Branded SaaS Onboarding with Custom Stripe Elements

Branded SaaS Onboarding with Custom Stripe Elements

Build a complete SaaS onboarding flow where users authenticate via Clerk and subscribe via Stripe, with the Stripe payment form fully customized using the Appearance API to achieve pixel-perfect brand consistency across the entire auth-to-payment journey.

Products involved

Scenario

Use this workflow when building a SaaS application requiring a seamless, fully branded onboarding journey. Developers need this when users must authenticate via a custom Clerk flow and immediately transition to a Stripe subscription checkout without breaking the app’s design system, ensuring pixel-perfect brand consistency from sign-up to payment.

Integration steps

  1. Initialize Clerk with Custom Routing: Install @clerk/nextjs and create /app/auth/sign-up/page.tsx. Mount <SignUp routing="path" path="/auth/sign-up" /> to bypass hosted pages.
  2. Apply Clerk Appearance Tokens: Pass the appearance prop to enforce brand consistency:
  3. ``tsx <SignUp appearance={{ variables: { colorPrimary: '#0F172A', fontFamily: 'Inter, sans-serif' }, elements: { formButtonPrimary: { fontWeight: 600 } } }} /> ``

  4. Capture Authenticated User ID: After sign-up, redirect to /onboarding. Use useUser() to extract user.id and securely POST it to your backend.
  5. Provision Stripe Customer & SetupIntent: On your backend, call stripe.customers.create({ email: user.email }), then stripe.setupIntents.create({ customer: customerId }). Return the clientSecret to the frontend.
  6. Initialize Stripe Elements with Appearance API: Load @stripe/stripe-js and wrap your checkout in <Elements> with matching theme variables:
  7. ``tsx const options = { clientSecret, appearance: { variables: { colorPrimary: '#0F172A', fontFamily: 'Inter, sans-serif', borderRadius: '8px' } } }; ``

  8. Render & Confirm Payment: Mount <PaymentElement /> inside <Elements>. Handle submission with stripe.confirmSetup({ elements, confirmParams: { return_url: '/dashboard' } }).
  9. Sync Subscription Status: Configure a Stripe webhook (customer.subscription.created) to map stripeCustomerId to clerkUserId in your database, enabling role-based access control.

Architecture

Clerk manages identity lifecycle, session generation, and JWT issuance. Upon successful auth, the frontend passes the Clerk userId to your backend, which provisions a Stripe Customer and returns a SetupIntent clientSecret. Stripe Elements renders the payment UI, using the Appearance API to mirror Clerk’s CSS variables. Post-payment, Stripe webhooks activate the subscription, while Clerk middleware continues validating session tokens for protected routes.

Prerequisites

Common pitfalls

Typical questions

FAQ

Q: How do I customize the Stripe payment form to match my app's branding during a Clerk-authenticated SaaS onboarding flow? A: You can fully customize the Stripe payment form using the Appearance API to achieve pixel-perfect brand consistency across the entire auth-to-payment journey. This configuration integrates Clerk authentication with Stripe subscriptions, allowing you to style the checkout experience so it seamlessly matches your application's design.