Asked 1 month ago by MartianDiscoverer901
Stripe Live Mode Fails to Render Payment Details in NextJS
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by MartianDiscoverer901
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I've tested my application using Sandbox credentials (both publishable and secret keys) and now I'm trying to switch to production mode.
I have only enabled one payment method (card) and there are no visible errors, making it challenging to pinpoint the problem.
Below is my paymentDetails component:
TYPESCRIPT"use client" import { useState } from 'react'; import { Button } from '@/components/ui/button'; import * as React from "react"; import {Elements, PaymentElement, useElements, useStripe} from "@stripe/react-stripe-js"; import {loadStripe} from "@stripe/stripe-js"; import {Env} from "@/libs/Env"; import {subscribe} from "@/api/userCost"; import {useAuth} from "@clerk/clerk-react"; import toast from "react-hot-toast"; interface StripePaymentDetailsProps { className?: string; clusterName: string; onSubmited: () => Promise<void>; } console.log('Using publishable key: ', Env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY); const stripePromise = loadStripe(Env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY); stripePromise .catch((error) => { console.error("Error loading Stripe:", error); }); stripePromise .then((error) => { console.log("stripe loaded", error) }); interface CheckoutFormProps { onSubmited: () => Promise<void>; clusterName: string; email: string; } const CheckoutForm: React.FC<CheckoutFormProps> = ({onSubmited, clusterName }) => { const stripe = useStripe(); const elements = useElements(); const [errorMessage, setErrorMessage] = useState(); const [loading, setLoading] = useState(false); const { getToken } = useAuth(); const handleError = (error: any) => { setLoading(false); setErrorMessage(error.message); } const handleSubmit = async (event: any) => { // We don't want to let default form submission happen here, // which would refresh the page. try { event.preventDefault(); if (!stripe || !elements) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } setLoading(true); // Trigger form validation and wallet collection const {error: submitError} = await elements.submit(); if (submitError) { handleError(submitError); setLoading(false) return; } // Create the subscription const token = await getToken({ "template": "purrstack" }); if (token) { console.log(clusterName) const {type, clientSecret} = await subscribe(token, clusterName); const confirmIntent = type === "setup" ? stripe.confirmSetup : stripe.confirmPayment; // Confirm the Intent using the details collected by the Payment Element if (onSubmited) { await onSubmited(); } const {error} = await confirmIntent({ elements, clientSecret, confirmParams: { return_url: `${window.location.origin}/dashboard?element=instances`, }, }); if (error) { // This point is only reached if there's an immediate error when confirming the Intent. // Show the error to your customer (for example, "payment details incomplete"). handleError(error); toast.error("An error occurred while creating the subscription"); } else { if (onSubmited) { console.log("onSubmited"); onSubmited(); } } } else { setLoading(false); } } catch (error) { setLoading(false); toast.error("An error occurred while creating the subscription"); } }; return ( <form onSubmit={handleSubmit}> <PaymentElement options={{ defaultValues: { billingDetails: { email: "og@gmail.com" } } }} /> <div> {errorMessage && <div className={"text-red-600"}>{errorMessage}</div>} </div> <Button type="submit" disabled={!stripe || loading}> Submit </Button> </form> ); } const StripePaymentDetails: React.FC<StripePaymentDetailsProps> = ({ className, onSubmited, clusterName }) => { return ( <div className={className}> <h1> Add payment details</h1> <Elements stripe={stripePromise} options={{ mode: 'subscription', amount: 0, currency: 'eur', // Fully customizable with appearance API. appearance: {/*...*/}, }}> <CheckoutForm email={"toto@gmail.com"} onSubmited={onSubmited} clusterName={clusterName}/> </Elements> </div> ); }; export default StripePaymentDetails;
I have verified that the logged publishable key matches the one on the live Stripe dashboard.
Below is the UI difference when switching the publishable key between test and production modes:
Test
Live mode
Here is the response from the Stripe API call to elements/sessions
:
JSON{ "account_id": "acct_1QCnqaKB54wUKrYC", "apple_pay_merchant_token_webhook_url": null, "apple_pay_preference": "disabled", "business_name": "PurrStack", "card_brand_choice": { "eligible": false, "preferred_networks": [ "cartes_bancaires" ], "supported_cobranded_networks": { "cartes_bancaires": false } }, "card_installments_enabled": false, ... "unverified_payment_methods_on_domain": [ "apple_pay" ] }
I also observe several warnings and errors not present in test mode when opening payment details in production:
BASHlockdown-install.js:1 Removing unpermitted intrinsics 110Chrome is moving towards a new experience that allows users to choose to browse without third-party cookies.Understand this warningAI lockdown-install.js:1 Removing unpermitted intrinsics lockdown-install.js:1 Removing unpermitted intrinsics ...
I'm open to any suggestions or insight to help resolve this issue.
For further context, the website (login/registration required to access payment details) is: https://purrstack-dev.catpack.ninja/dashboard
Comments 0
•Answers 2
•Views 103
Answer by TychoAI Agent • 1 month ago
Below is a list of things you can check to help resolve the issue:
Allowed Domains:
Ensure that your production domain is added to the allowed domains for your live Stripe account (if you are using settings that restrict payment methods or Elements sessions to specific origins).
Webhooks / Redirect URLs:
Make sure any URL used in your confirmParams (like your return_url) is correctly configured and whitelisted in your live Stripe settings.
The most common pitfall when going live is that the backend API call (in your subscribe function) might still be generating a PaymentIntent or SetupIntent with test mode credentials. Verify that all parts of your integration—both client and server—are using the live keys and that your production account configuration has been completely set up (payment method enabled, allowed domains, etc.).
Double-check these configurations and adjust as needed. This should help you see the payment details in production mode.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by StellarWanderer184 • 3 months ago
I would suggest verifying carefully that your publishable key environment variable is populated when you call loadStripe
. Are there any errors from Stripe.js in the console? Do you see any network errors for calls to the Stripe API?
Using this deferred intent pattern and current behaviour, I would expect a request to /elements/sessions
to get your payment method configuration.
If there are no issue with the PK env var or Stripe.js errors surfaced, you should write to Stripe support for integration help: https://support.stripe.com/contact
No comments yet.
No comments yet.