Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Pay-per-Visit Content

Enable micropayment-based content access. Users pay cents per article instead of monthly subscriptions.

Problem statement

Traditional content monetization forces creators into difficult trade-offs:

  • Subscriptions force users to pay for content they don't consume. Most readers abandon paywalls rather than commit to a monthly subscription for a single article, leaving the content provider with a missed connection with a potential user.
  • Ads damage user experience, raise privacy concerns, and are increasingly under strain with the rise of web crawlers.
  • Freemium models leave money on the table from engaged users willing to pay for premium content.

Radius solves this with pay-per-visit micropayments—users pay exactly for what they read, watch, or download. No subscriptions. No trackers. Instant access.

How it works

The user journey is frictionless:

  1. User lands on premium content and sees a paywall
  2. Clicks "Unlock" and chooses a micropayment amount (0.05 USD, 0.10 USD, 0.25 USD, etc.)
  3. Confirms payment in their wallet (MetaMask, Rainbow, etc.)
  4. Content unlocks instantly after payment confirmation—no waiting, no email verification
  5. Payment settles instantly to your account in stablecoins

Behind the scenes, Radius handles the heavy lifting: gas fees are paid in stablecoins via Turnstile, transactions settle in seconds, and there's no intermediary taking a cut.

Implementation example

Here's a complete React component that implements a content paywall with Radius micropayments:

Step 1: Paywall component

import { useState } from 'react';
import { parseEther } from 'viem';
import { useAccount, useWriteContract, useWaitForTransactionReceipt } from 'wagmi';
 
interface ContentPaywallProps {
  contentId: string;
  title: string;
  amount: string; // e.g., "0.10" (USD)
  children: React.ReactNode;
}
 
export function ContentPaywall({
  contentId,
  title,
  amount,
  children,
}: ContentPaywallProps) {
  const { address, isConnected } = useAccount();
  const [isUnlocked, setIsUnlocked] = useState(false);
  const [isPaying, setIsPaying] = useState(false);
  const { data: hash, writeContract, isPending } = useWriteContract();
  const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({
    hash,
  });
 
  const handleUnlock = async () => {
    if (!address) return;
 
    setIsPaying(true);
 
    try {
      // Send payment to content owner address
      const contentOwner = '0x742d35Cc6634C0532925a3b844Bc9e7595f7E9F1';
 
      writeContract({
        to: contentOwner,
        account: address,
        value: parseEther(amount),
      });
    } catch (error) {
      console.error('Payment failed:', error);
      setIsPaying(false);
    }
  };
 
  // Once payment is confirmed, unlock content
  if (isSuccess && !isUnlocked) {
    setIsUnlocked(true);
    setIsPaying(false);
  }
 
  if (!isConnected) {
    return (
      <div className="paywall">
        <h2>{title}</h2>
        <p>Connect your wallet to unlock this content.</p>
        <button onClick={() => {}}>Connect Wallet</button>
      </div>
    );
  }
 
  if (isUnlocked) {
    return <div className="content">{children}</div>;
  }
 
  return (
    <div className="paywall">
      <h2>{title}</h2>
      <p>
        This premium content costs <strong>{amount} USD</strong> to unlock.
      </p>
      <p>
        One-time payment. No subscription. Instant access.
      </p>
 
      <button
        onClick={handleUnlock}
        disabled={isPaying || isConfirming}
        className="unlock-button"
      >
        {isPaying || isConfirming ? 'Processing...' : `Unlock for ${amount} USD`}
      </button>
 
      {isPending && <p className="status">Awaiting wallet confirmation...</p>}
      {isConfirming && <p className="status">Confirming payment...</p>}
      {hash && (
        <p className="transaction-hash">
          Transaction: {hash.slice(0, 10)}...{hash.slice(-8)}
        </p>
      )}
    </div>
  );
}

Step 2: Using the paywall

export default function ArticlePage() {
  return (
    <ContentPaywall
      contentId="article-123"
      title="The Future of Micropayments"
      amount="0.10"
    >
      <article>
        <p>
          Micropayments enable creators to monetize directly. Instead of
          relying on ads or subscriptions, users pay exactly what content is
          worth to them...
        </p>
        {/* Rest of article content */}
      </article>
    </ContentPaywall>
  );
}

Complete code examples

Server-side payment verification

Verify payments on your backend to prevent abuse:

// pages/api/verify-payment.ts
import { createPublicClient, http } from 'viem';
import { radiusTestnet } from '@radiustechsystems/sdk';
 
const publicClient = createPublicClient({
  chain: radiusTestnet,
  transport: http(),
});
 
export default async function handler(req, res) {
  const { transactionHash, contentId, userAddress } = req.body;
 
  try {
    // Fetch transaction receipt
    const receipt = await publicClient.getTransactionReceipt({
      hash: transactionHash,
    });
 
    // Verify transaction success
    if (receipt.status !== 'success') {
      return res.status(400).json({ error: 'Payment failed' });
    }
 
    // Verify amount and recipient
    const tx = await publicClient.getTransaction({ hash: transactionHash });
    const expectedAmount = parseEther('0.10');
 
    if (tx.value !== expectedAmount) {
      return res.status(400).json({ error: 'Incorrect payment amount' });
    }
 
    // Record successful payment in your database
    await db.payments.create({
      contentId,
      userAddress,
      transactionHash,
      amount: tx.value.toString(),
      timestamp: new Date(),
    });
 
    return res.status(200).json({ verified: true, access: true });
  } catch (error) {
    console.error('Verification error:', error);
    return res.status(500).json({ error: 'Verification failed' });
  }
}

Multiple price tiers

Offer different content at different prices:

const contentTiers = {
  article: '0.05', // 0.05 USD per article
  video: '0.25', // 0.25 USD per video
  research: '1.00', // 1.00 USD per research paper
  masterclass: '5.00', // 5.00 USD per masterclass
};
 
export function ContentLibrary() {
  return (
    <div>
      {[
        { id: '1', title: 'Breaking News', type: 'article' },
        { id: '2', title: 'Tutorial: Radius SDK', type: 'video' },
        { id: '3', title: 'Stablecoin Economics', type: 'research' },
      ].map((item) => (
        <ContentPaywall
          key={item.id}
          contentId={item.id}
          title={item.title}
          amount={contentTiers[item.type]}
        >
          <p>Content for {item.title}</p>
        </ContentPaywall>
      ))}
    </div>
  );
}

Benefits of Radius micropayments

For users

  • Lower barrier than subscriptions — Pay 0.10 USD for one article instead of 15 USDC/month
  • No tracking required — Stablecoins provide value; ads and trackers don't
  • Global access — Pay with Radius in any country; instant settlement
  • Instant access — Content unlocks immediately after payment confirmation

For creators

  • Higher effective revenue — Every engaged reader becomes a paying user
  • No chargeback risk — Stablecoin transactions are final; no refund disputes
  • Direct payment — Money goes directly to you; no subscription platform taking 30%
  • Flexible pricing — Set different prices for articles, videos, research—whatever works for your audience

For both

  • No intermediaries — Direct creator-to-reader transactions
  • Instant settlement — Money available immediately, not locked up for 30 days
  • Low transaction cost — Radius handles gas via Turnstile; you pay almost nothing per transaction
  • Works globally — Stablecoins work in any country; currency conversion handled on-chain

With Radius, a creator earning 0.10 USD per article only needs 100 readers per day to generate 1000 USD/month. That's achievable for most niche content creators.

Use cases

Micropayments work for any content creators want compensation for:

  • News & Journalism — Articles, investigations, breaking news
  • Video Content — Tutorials, documentaries, educational videos
  • Research & Data — Academic papers, market research, whitepapers
  • Premium Tutorials — In-depth guides, programming courses, design resources
  • Podcasts — Individual episode access or full-library unlock
  • Photography & Art — High-resolution downloads, exclusive collections
  • Gaming Content — Cosmetics, level packs, exclusive streams
  • Expert Advice — Consultations, AMA sessions, email support tiers

Getting started

1. Install dependencies

pnpm add @radiustechsystems/sdk wagmi viem @tanstack/react-query

2. Configure Wagmi

import { WagmiProvider, createConfig, http } from 'wagmi';
import { radiusTestnet } from '@radiustechsystems/sdk';
import { injected } from 'wagmi/connectors';
 
const config = createConfig({
  chains: [radiusTestnet],
  connectors: [injected()],
  transports: {
    [radiusTestnet.id]: http(),
  },
});
 
export function App({ children }) {
  return <WagmiProvider config={config}>{children}</WagmiProvider>;
}

3. Wrap your app

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
 
const queryClient = new QueryClient();
 
export default function RootApp() {
  return (
    <QueryClientProvider client={queryClient}>
      <App>
        <YourContent />
      </App>
    </QueryClientProvider>
  );
}

4. Deploy and test

Test with Radius Testnet before going live:

# Get free test tokens from the faucet
# https://testnet.radiustech.xyz/testnet/faucet
 
# Deploy your dapp and test payments
# Once verified, switch to mainnet

Best practices

  1. Show the price upfront — Users hate surprises. Display the cost before they click "unlock"
  2. Make wallet connection obvious — If not connected, guide users to connect before payment
  3. Handle network errors gracefully — Show retry buttons if payment fails
  4. Store payment receipts — Keep transaction hashes for support and analytics
  5. Offer value for the price — 0.10 USD articles should be substantial; avoid paywalling single paragraphs
  6. Test on testnet first — Always verify payment flow before production
  7. Monitor gas costs — Radius fees are low, but still track transaction costs

Scaling considerations

  • Batch settlements — Collect multiple payments, settle once daily to save costs
  • Tiered content — Use content length/quality to justify different price points
  • Bundle offers — Sell article packs ("10 articles for 0.50 USD") to increase AOV
  • Incentivize loyalty — Offer discounts to frequent readers or newsletter subscribers
  • Track conversion — Monitor which price points convert best for different content types

What's next


Ready to monetize? Build your first paywall, test on testnet, and start earning from every engaged reader.