Add a payment button to your Next.js app
The Next.js docs hand you a 2,000-line Stripe Elements walkthrough. You don't need that. Two lines of HTML, an anchor and a stylesheet — no SDK, no API route, no client component required.

Why Stripe in Next.js is harder than it should be
Next.js App Router is built around React Server Components, but Stripe.js is a client-only SDK. The moment you reach for it you have to mark a component "use client", load a heavy script, juggle a publishable key, set up an API route to create payment intents, build a webhook handler to confirm them, and then style a checkout that almost-but-not-quite matches your brand. For the 90% of Next.js apps that just want a Pay button on a marketing page, this is laughably overkill.
- Stripe.js forces a 'use client' boundary, breaking your App Router server tree.
- Client SDKs ship 90KB+ of JavaScript — Lighthouse hates it.
- API route + webhook + secret rotation + retry logic, just for one button.
- Stripe Checkout is hosted, but the redirect URL is opaque and the styling lives in the dashboard, not your codebase.
The fix: a static anchor that lands on a branded checkout
PayRequest's Payment Button is a plain HTML link styled by a single CSS file. It renders inside a Server Component (no "use client" needed), ships zero JavaScript to the browser, and respects every CSP rule you've set. Customers click the anchor and land on your branded PayRequest checkout — handle, colours, payment methods all served from your dashboard.
Renders in a Server Component
It's an <a> tag and a <link>. No 'use client', no useState, no client-side hydration cost.
Zero JavaScript on your bundle
The button adds 0 bytes to your Next.js JS bundle. The stylesheet loads from PayRequest's CDN — separate from your build.
No API routes, no webhooks
Payment intent creation, confirmation, fulfilment emails and dunning all happen on PayRequest. Your /api folder stays empty.
App Router, Pages Router, both fine
Same snippet works in app/, pages/, route handlers, server actions — anywhere you can render HTML.
The whole integration, in two lines of HTML
Paste the <link> in your root layout.tsx (or app/layout.tsx) <head>. Drop the <a> wherever you want a button — in any RSC, MDX file, or layout fragment.
// app/layout.tsx — once per project
<head>
<link rel="stylesheet"
href="https://payrequest.app/embed/button.css" />
</head>
// any Server Component (app/page.tsx, MDX, etc.)
<a href="https://payrequest.me/yourhandle/pro-plan"
className="pr-btn pr-btn--default"
target="_blank"
rel="noopener">Pay €19</a>Three button styles ship with the stylesheet — pick one to match your Next.js theme.
Step-by-step: from npm install to live payment
Create a Smart Link in PayRequest
Sign in → Payment Page → Smart Links → New. Set the amount, pick your methods (card, Apple Pay, iDEAL, PayPal), copy the URL.
Add the stylesheet to app/layout.tsx
Inside your root <head>, drop a <link rel="stylesheet" href="https://payrequest.app/embed/button.css" />. Once per project — every page picks up the styles.
Drop the anchor in any page or component
Pricing page, hero, blog post — wherever the CTA lives. The anchor is a server-renderable <a> with a className. No client wrapper required.
Set the href to your Smart Link
Use an environment variable if you want to swap test/live URLs: process.env.NEXT_PUBLIC_PAYREQUEST_LINK. Treat it like any other public URL.
Deploy to Vercel
vercel --prod (or your usual flow). The button is static HTML — Vercel caches it, the stylesheet loads from PayRequest's CDN, and the click hands off to your branded checkout. Done.
Next.js + Payment Button vs the alternatives
| Method | Setup time | Client JS | API routes | Branded checkout | Payment methods |
|---|---|---|---|---|---|
Stripe Elements | Half a day | ~90 KB | 2+ required | Manual styling | Configurable |
Stripe Checkout (redirect) | 1–2 hours | Stripe.js (~90 KB) | 1 + webhook | Limited | Card + wallets |
PayPal Buttons SDK | 1 hour | ~150 KB | 1 (capture) | PayPal-branded | PayPal + cards |
PayRequest Payment ButtonBest | 1 minute | 0 KB | None | Yours | 20+ including iDEAL, SEPA, Klarna |
What Next.js teams ship with the Payment Button
Pricing pages on marketing sites
RSC-rendered pricing tier with a Pay button per plan. No client component, no API route, no boilerplate.
MDX blog posts and tutorials
Drop the <a> directly into MDX content. Sell prompt packs, courses or tip jars from any post without ejecting to a custom layout.
Server actions + payment confirmations
Use server actions to create the Smart Link on the fly, then render the button server-side. Full RSC stream, no client hydration penalty.
Static blogs and documentation
Next.js export-mode sites and docs.your-domain.com get a real payment CTA without bringing the runtime back.
Why this beats every Stripe-in-Next.js tutorial
Read any "Stripe with Next.js App Router" article and you'll find at least 12 files: a server action, a pages route, a webhook handler, a success page, a metadata file, a client wrapper, a price-id constants file, a Stripe utility, a webhook signing helper, a customer-portal redirect... and a comment explaining what got broken when Stripe moved to Stripe.js v3. The Payment Button replaces all of that with a CSS class.
- Works in app/, pages/, MDX, route handlers, server actions, edge runtime — same snippet, everywhere.
- No publishable or secret keys in your repo. The link is the integration.
- CSP-friendly: same-origin <a>, no inline scripts, no third-party iframes.
- Provider-agnostic: switch between Stripe, Mollie, PayPal or Ponto on PayRequest without redeploying Next.js.
Frequently asked questions
Do I need to mark the component "use client" to use the Payment Button?+
Where do I put the stylesheet — in app/layout.tsx or every page?+
Will the button hurt my Lighthouse scores?+
Can I use the Payment Button with Tailwind classes for layout but keep the PayRequest styles?+
Does this work on Vercel's Edge runtime?+
How do I track conversions from a specific Next.js page?+
Ship payments in your Next.js app today
Sign up, create a Smart Link, paste the snippet into app/layout.tsx and any page. Five minutes, zero SDK, real money.