Guide

Stripe Checkout Mistakes That Put Your Payments at Risk

· 6 min read

Stripe checkout mistakes like leftover test keys and exposed secret keys often ship unnoticed, and this guide shows how to catch each one fast.

In short

Stripe checkout mistakes almost always come down to three silent failures: a live page still pointed at test keys, a secret key sitting in the page's visible source, and browser security headers that do not protect the checkout flow. None of these throw an error a visitor can see. SiteHealth is plain-English website health monitoring that runs 23 checks on a site, including a payment health check built to catch exactly these three mistakes before a customer does.

What actually goes wrong on a Stripe checkout page?

Most Stripe checkout mistakes fall into one of three categories, and all three look completely normal to a visitor. The page loads, the form renders, the button says "Pay now" — and underneath, something is wrong in a way that only shows up when you check the actual keys and headers involved.

  • pk_test_... — a publishable test key sitting on a live domain. Forms submit and appear to work, but Stripe never processes a real charge.
  • sk_... or rk_... — a secret or restricted key visible in page source, browser devtools, or a public repository. Anyone who finds it can act on your Stripe account.
  • Missing or wrong Content-Security-Policy — the header that tells a browser which domains are allowed to load scripts, frames, and form submissions near your checkout.

Each of these three ships silently. The checkout page does not display a warning, and most owners only find out when a customer emails to say a payment "didn't go through," or when they notice the Stripe dashboard is quiet for a stretch that does not match their traffic.

Why does a test key end up on a live page?

The most common cause is copying a staging environment straight to production without swapping the environment variables. A site built quickly, especially with an AI builder, often starts wired to Stripe's test mode by default, because that lets a developer click through checkout without spending real money.

The mistake happens at the exact moment someone forgets, or does not know, to flip that one setting before pointing a real domain at the build. Nothing in the interface tells them. The page keeps working, the "Pay now" button keeps responding, and every transaction quietly stays fake.

A second cause is a rollback. A hotfix or a redeploy from an older branch can silently restore an old .env file that still has test values, undoing a fix that was made weeks earlier. This is why a one-time check is not enough — the same mistake can reappear after the page was already fixed once.

What can someone do with a secret key from your page source?

A Stripe secret key, prefixed sk_, is meant to live on your server and never reach a browser. If it ends up in your page's HTML, a JavaScript bundle, or a public GitHub repository, anyone who finds it can use it exactly as your own backend would: create charges, issue refunds, list customers, and pull payment history. Stripe's own API documentation is explicit that secret keys must never be exposed client-side or committed to version control.

A restricted key, prefixed rk_, narrows what an exposed key can do, but the safest posture is still to keep any key that can touch money off the page entirely and rotate it the moment you suspect it has leaked. Rotating a key does not require canceling your Stripe account — it invalidates the old key and generates a fresh one, the same pattern covered in an earlier guide on exposed .env and .git files, where the leak path is usually the same misconfigured server, not Stripe itself.

Do your security headers protect the checkout flow?

Not automatically. The Content-Security-Policy header's form-action directive controls which domains a form on your page is allowed to submit to, and if it is missing or too strict, it can either leave the door open for a malicious script to intercept a submission, or accidentally block Stripe's own checkout redirect so the button does nothing at all. The Mozilla Developer Network's documentation on the form-action directive covers exactly this trade-off: a policy that is too loose protects nothing, and one that is too strict breaks the page it was meant to protect.

This is one reason a payment page needs the same header review as the rest of the site. An earlier article on this blog, what security headers like CSP and HSTS actually do, walks through the same headers in general. The checkout page is simply the one place on the site where getting the policy wrong costs you a sale immediately, not just a lower security score.

How would you know if this is already happening on your own site?

Checking all three of these by hand means opening your live checkout page in an incognito window, viewing source for the key prefix, opening devtools to inspect the response headers, and repeating that after every deploy. Most owners do this once, when the site launches, and never again. SiteHealth's payment health check runs this same check automatically, looking specifically for a test key on a live domain and a secret key visible on the page, and reports the finding in one plain sentence with the fix attached. You can see this and the other checks it runs on the features page.

Steps to check your own Stripe checkout page today

  1. Open your live checkout page in a private or incognito browser window, not a tab where you are logged into your own admin panel.
  2. Right-click the page and choose "View Page Source," then search for pk_test_. If you find it, your live page is wired to test mode.
  3. Search the same source for sk_ or rk_. Either one visible in the HTML or a loaded JavaScript file is a leak, not a false alarm.
  4. Open your browser's developer tools, go to the Network tab, reload the page, and check the response headers for Content-Security-Policy.
  5. Confirm the form-action value includes both checkout.stripe.com and billing.stripe.com — Stripe's redirect and billing portal both need to be explicitly allowed.
  6. If you find a leaked secret key, rotate it in your Stripe dashboard immediately, then update the server-side environment variable, not the page itself.

"We already checked this once"

The honest objection here is that checking these three things once, at launch, feels like enough. It is not, and the reason is not carelessness — it is that deploys, template updates, and AI builders that reset environment variables all touch the same files a Stripe integration depends on. A key that was correct in June can be wrong again in September because a redeploy quietly restored an older .env file. A one-time check catches the mistake you made at launch. It does not catch the one a future deploy reintroduces.

Fix a broken Stripe checkout before it costs you a sale

If you already suspect one of these three mistakes is live on your site, the fastest next step is the free checker on the SiteHealth homepage — enter your domain, and it runs a first pass with no account needed. From there, an hourly plan keeps checking after every deploy, so a test key or an exposed secret key gets caught the same day it appears, not the day a customer complains.

FAQ

Questions people ask about this

How do I know if my Stripe checkout page is using a test key?

Open your live checkout page in a private browser window and view the page source. Search for pk_test_ — that prefix means the page is wired to Stripe's test mode, so real customers can fill out the form but no payment ever actually goes through. A live page should only ever show a pk_live_ key.

What is the difference between a Stripe secret key and a publishable key?

A publishable key, prefixed pk_, is meant to sit in your page source and only creates payment tokens. A secret key, prefixed sk_, can move money, issue refunds, and read customer data, so it belongs on your server only. If sk_ ever shows up in page source or a public repository, treat it as compromised.

Why would my security headers matter for a payment page?

A missing or misconfigured Content-Security-Policy header can either fail to stop a malicious script from running near your checkout form, or block Stripe's own checkout redirect outright. Either failure costs you sales, one by scaring off a browser warning, the other by breaking the button that starts the payment.

Can an AI website builder cause a Stripe checkout mistake by itself?

Yes. Builders like Lovable, Bolt, and v0 often generate a working demo against Stripe test keys, and if you publish the site without swapping in live keys and moving the secret key server-side, the mistake ships with the rest of the page. Nobody sees an error, because test mode fails silently.

How often should I recheck my payment page for these mistakes?

Recheck after every deploy that touches checkout, and at least weekly otherwise, because a redeploy, a template update, or a builder resetting an environment variable can quietly restore a test key or drop a header that was previously set correctly.