<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gábor Pintér</title>
    <description>The latest articles on DEV Community by Gábor Pintér (@gaborpinter).</description>
    <link>https://dev.to/gaborpinter</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1562160%2F920dc9ea-e87c-4b75-bd0e-01429a7d271c.png</url>
      <title>DEV Community: Gábor Pintér</title>
      <link>https://dev.to/gaborpinter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gaborpinter"/>
    <language>en</language>
    <item>
      <title>The central challenge of working with AI</title>
      <dc:creator>Gábor Pintér</dc:creator>
      <pubDate>Fri, 06 Nov 2026 14:17:38 +0000</pubDate>
      <link>https://dev.to/gaborpinter/the-central-challenge-of-working-with-ai-5a9o</link>
      <guid>https://dev.to/gaborpinter/the-central-challenge-of-working-with-ai-5a9o</guid>
      <description>&lt;p&gt;The central challenge of working with AI is speed vs. quality.&lt;/p&gt;

&lt;p&gt;Work too slow and your career/business will get behind.&lt;br&gt;
Work too fast and the quality of your work will suffer.&lt;/p&gt;

&lt;p&gt;This has always been a dilemma, even before AI. What's new with AI is that this tension is amplified. Now you can both go extremely fast and do extremely shitty work too.&lt;/p&gt;

&lt;p&gt;Two steps to fight this: diagnosis and implementation.&lt;/p&gt;

&lt;p&gt;First, diagnose what your real problems are. &lt;/p&gt;

&lt;p&gt;Is speed truly a problem? Did your employer/client really ask you to speed up 10x? Or is it somewhat an artificial fear fueled by billion dollar companies trying to justify their stock? &lt;/p&gt;

&lt;p&gt;The speed problem can be fixed easily. Open ChatGPT, type in your problem and voilà! Now you have a quality problem.&lt;/p&gt;

&lt;p&gt;I see quality problem more often than the speed problem. People (including me) started to rely professionally on AI too much. Speed went up in the short term and quality dropped. Eventually, speed went down in the long term too.&lt;/p&gt;

&lt;p&gt;This clumsy implementation brought in other factors too. I didn't enjoy coding as much as before. I got distracted more easily. I got more comfortable but less confident. I started to work on multiple problems at the same time and the continuous context switching made me exhausted. Copy-paste more and more. &lt;/p&gt;

&lt;p&gt;Eventually I became a meat proxy. A human channel through which AI models communicate. &lt;/p&gt;

&lt;p&gt;So what's the fix? How do I increase the quality of my work and enjoy what I do while staying in business?&lt;/p&gt;

&lt;p&gt;I believe the keys to a successful shift are gradualism and moderation. &lt;/p&gt;

&lt;p&gt;Instead of going from zero-AI to full-AI mode, you take small steps. Instead of jumping from one side of the spectrum (slow but good) to the other extreme (fast but shitty) you navigate towards the middle. &lt;/p&gt;

&lt;p&gt;As a developer I introduced AI-free sessions for myself. I even installed a second IDE with no AI integration in it. During these sessions I look around the codebase more, I text-search more, I make mistakes and I spend time staring at loops. I organise the code, separate blocks, and label them. I treat the code as my craft. Like in the old days. &lt;/p&gt;

&lt;p&gt;The goal is a more human adaptation, without letting hype and fear override my professional responsibility. &lt;/p&gt;

&lt;p&gt;I believe not leveraging AI is a mistake. But letting AI kill your curiosity, your craft, and your confidence is also a mistake. True professionals adapt, but they also reject.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>developers</category>
      <category>mentalhealth</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Blog paywall with Astro, Cloudflare, Clerk and Stripe</title>
      <dc:creator>Gábor Pintér</dc:creator>
      <pubDate>Mon, 04 May 2026 11:48:29 +0000</pubDate>
      <link>https://dev.to/gaborpinter/blog-paywall-with-astro-cloudflare-clerk-and-stripe-1ihe</link>
      <guid>https://dev.to/gaborpinter/blog-paywall-with-astro-cloudflare-clerk-and-stripe-1ihe</guid>
      <description>&lt;p&gt;If you want to introduce a paywall to your Astro blog - &lt;a href="https://gaborpinter.com/sponsorship" rel="noopener noreferrer"&gt;like I do&lt;/a&gt; - then Cloudflare Pages, Clerk, and Stripe offer a pretty sweet setup.&lt;/p&gt;

&lt;p&gt;In this post I'll show you how you gate some of your content with subscriptions or one-time payments. We'll use Astro for our content, Cloudflare Pages for hosting, Clerk for authentication and Stripe for collecting payments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started with Cloudflare Pages and Clerk
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deploy Astro to &lt;a href="https://developers.cloudflare.com/pages/" rel="noopener noreferrer"&gt;Cloudflare Pages&lt;/a&gt;.&lt;/strong&gt; Cloudflare Pages supports SSR for Astro, which means we can evaluate requests on the server side. &lt;a href="https://developers.cloudflare.com/pages/configuration/git-integration/github-integration/" rel="noopener noreferrer"&gt;Deploy directly from GitHub&lt;/a&gt; for continuous integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a free &lt;a href="https://clerk.com/" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; account&lt;/strong&gt;. Clerk will handle creating and authenticating your users. Their &lt;a href="https://clerk.com/pricing" rel="noopener noreferrer"&gt;free tier&lt;/a&gt; is extremely generous.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;a href="https://developers.cloudflare.com/pages/functions/middleware/" rel="noopener noreferrer"&gt;Cloudflare's middleware logic&lt;/a&gt;&lt;/strong&gt; to evaluate requests based on URL, e.g.: &lt;code&gt;/blog/exclusive-posts/*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In your &lt;code&gt;middleware.ts&lt;/code&gt;, use Clerk to validate user authentication.&lt;/strong&gt; Redirect to a paywall when the user is not logged in.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// middleware.ts (simplified)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineMiddleware&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;astro:middleware&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClerkClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@clerk/backend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Only gate the exclusive-posts pages.&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EXCLUSIVE_POSTS_PREFIX&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secretKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getClerkSecretKeyFromEnvironment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;publishableKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getClerkPublishableKeyFromEnvironment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clerkClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClerkClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;secretKey&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Get auth state&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;authState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;clerkClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticateRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;publishableKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;acceptsToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;session_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;paywallRedirectLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Get userId&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUserIdFromSessionClaims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;paywallRedirectLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// User is logged in, continue&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Signing in is only part of the story: for a real paywall you also need to &lt;strong&gt;check Clerk user metadata&lt;/strong&gt; (or equivalent claims) so an active subscription or valid one-time purchase grants access, and redirect everyone else, including logged-in users without entitlement, to your paywall.&lt;/p&gt;

&lt;p&gt;At this point you can test this setup manually, without integrating Stripe. Create users manually in the Clerk Dashboard, log in with them and try to access content on your protected URLs. You can even create separate development and production environments in Clerk.&lt;/p&gt;

&lt;p&gt;Once you are ready, you can move on to the next phase, which is Stripe integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stripe integration
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create &lt;a href="https://stripe.com/en-hu/payments/payment-links" rel="noopener noreferrer"&gt;Stripe Payment Links&lt;/a&gt;.&lt;/strong&gt; Payment Links give you pretty sweet customization options, like mandatory billing address fields and custom fields for newsletter subscriptions, for example. I've created a monthly and a yearly subscription, and one for one-time payments too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a &lt;a href="https://workers.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare Worker&lt;/a&gt;&lt;/strong&gt; that will get called by a Stripe webhook. Place this worker within your Astro repo, so you can deploy it together with the site. The task of this worker is to handle Stripe event notifications and react to them: create a new user in Clerk if payment has been processed and no user is found for the given email address, or update user metadata when subscription changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a &lt;a href="https://docs.stripe.com/api/webhook_endpoints" rel="noopener noreferrer"&gt;Stripe webhook&lt;/a&gt;&lt;/strong&gt; in the &lt;a href="https://dashboard.stripe.com/" rel="noopener noreferrer"&gt;Stripe Dashboard&lt;/a&gt;. Provide your Cloudflare Worker URL as the endpoint. Make sure to include the following events:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;checkout.session.completed
customer.subscription.created
customer.subscription.updated
customer.subscription.deleted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Webhook signing and secrets
&lt;/h3&gt;

&lt;p&gt;Stripe signs each webhook request with an HMAC of the raw body and a timestamp, and sends the result in the &lt;a href="https://docs.stripe.com/webhooks/signatures" rel="noopener noreferrer"&gt;&lt;code&gt;Stripe-Signature&lt;/code&gt;&lt;/a&gt; header. Your Worker should read the body as &lt;strong&gt;text&lt;/strong&gt; (not parsed JSON first), verify the signature with your endpoint’s &lt;strong&gt;signing secret&lt;/strong&gt;, and only then &lt;code&gt;JSON.parse&lt;/code&gt; the payload. If verification fails, respond with &lt;code&gt;400&lt;/code&gt; and do not update Clerk.&lt;/p&gt;

&lt;p&gt;When you add the endpoint in the Stripe Dashboard, Stripe shows a &lt;strong&gt;Signing secret&lt;/strong&gt; (it starts with &lt;code&gt;whsec_&lt;/code&gt;). Treat it like a password: store it only in Cloudflare, not in git.&lt;/p&gt;

&lt;p&gt;For a Worker in its own folder (for example &lt;code&gt;workers/stripe-webhook/&lt;/code&gt;), define the bindings your code expects (&lt;code&gt;STRIPE_WEBHOOK_SECRET&lt;/code&gt;, &lt;code&gt;CLERK_SECRET_KEY&lt;/code&gt;) and set the values with Wrangler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# from the worker directory; use your Worker name / env flags as in wrangler.toml&lt;/span&gt;
npx wrangler secret put STRIPE_WEBHOOK_SECRET &lt;span class="nt"&gt;--config&lt;/span&gt; wrangler.toml &lt;span class="nt"&gt;--env&lt;/span&gt; prod
npx wrangler secret put CLERK_SECRET_KEY &lt;span class="nt"&gt;--config&lt;/span&gt; wrangler.toml &lt;span class="nt"&gt;--env&lt;/span&gt; prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wrangler prompts you to paste each value; it stores them encrypted on Cloudflare’s side. Repeat with &lt;code&gt;--env dev&lt;/code&gt; for a development Worker and use a separate &lt;a href="https://docs.stripe.com/webhooks#test-webhook" rel="noopener noreferrer"&gt;Stripe webhook endpoint&lt;/a&gt; (or the &lt;a href="https://docs.stripe.com/stripe-cli" rel="noopener noreferrer"&gt;Stripe CLI&lt;/a&gt; forwarding URL) that points at that URL, with its own signing secret.&lt;/p&gt;

&lt;p&gt;In my own setup, I also use three metadata fields on Clerk users that store information about their subscription status.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hasOngoingSubscription: boolean
ongoingAccessUntil: Date
oneTimeAccessUntil: Date
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;hasOngoingSubscription&lt;/code&gt; becomes &lt;code&gt;true&lt;/code&gt; when they subscribe and switches to &lt;code&gt;false&lt;/code&gt; when they cancel. Upon cancellation the &lt;code&gt;ongoingAccessUntil&lt;/code&gt; field gets filled with a date. When someone performs a one-time purchase, their &lt;code&gt;oneTimeAccessUntil&lt;/code&gt; field gets filled with a date.&lt;/p&gt;

&lt;p&gt;As a bonus, you can create a static &lt;a href="https://gaborpinter.com/successful-payment" rel="noopener noreferrer"&gt;Thank You page&lt;/a&gt; in your Astro blog. Use &lt;a href="https://confettijs.org/" rel="noopener noreferrer"&gt;confetti.js&lt;/a&gt; for a ceremonial feel. Use the URL of this page as the redirect URL in your Stripe Payment Links, so your users land on a nice page after successful payments that gives them instructions about the next steps.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post has been originally published on my &lt;a href="https://gaborpinter.com/blog/posts/blog-paywall-with-astro-cloudflare-clerk-and-stripe/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>astro</category>
      <category>clerk</category>
      <category>stripe</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
