IC Paywall is a decentralized application (dApp) built on the Internet Computer Protocol (ICP) blockchain. It allows users to create customizable paywalls for their web projects, charging visitors in ICP tokens for access. Payments can be split across multiple destinations (principals or account IDs), with options to convert ICP to cycles for canister top-ups. The app generates embeddable script tags for easy integration into websites or dApps, enforcing access controls via Internet Identity authentication and ICP ledger transactions.
Key features:
- Paywall Creation: Set ICP price, session duration, custom prompts, and payment splits.
- Payment Handling: Uses the ICP ledger for secure, on-chain transfers.
- Cycle Conversion: Automatically convert payments to cycles via the Cycles Minting Canister (CMC).
- Integration: Client-side script for frontend enforcement; backend checks for integrity.
- User Wallets: Each user gets a derived subaccount for deposits and payments.
The app is deployed on ICP mainnet:
- Frontend (Paywall Builder): https://4kz7m-7iaaa-aaaab-adm5a-cai.icp0.io/
- Backend Canister ID: 4d2uq-jaaaa-aaaab-adm4q-cai
- Prerequisites
- Tracking Disclosure
- Installation and Setup
- Deployment
- Using the Paywall Builder
- Integrating the Paywall Script
- Integrating with Vibe Coding
- Strengthening Projects for Integrity
- Editing and Deleting Paywalls
- How It Works
- Common Issues and Troubleshooting
- Contributing
- License
To run or deploy IC Paywall, ensure your system meets these requirements:
- DFX SDK: Version 0.29.2 or later. Install from the DFINITY SDK documentation.
- Node.js and npm: Version 16+ and 7+ respectively. Download from nodejs.org.
- Git: For cloning the repository.
- ICP Wallet: For testing payments (e.g., NNS dApp or Plug Wallet).
- Internet Identity: Required for authentication in the app and paywalls.
This codebase includes basic usage tracking to help identify deployments of the open-source project. The frontend sends a minimal beacon (watermark ID + domain) from initAnalytics in the paywall builder and initSessionTracker in the embeddable script. The backend logs a watermark string when paywalls are created or payments are verified. Remove these helpers if you do not want tracking enabled in your deployment.
-
Clone the Repository:
git clone https://github.com/dickhery/paywall.git cd paywall -
Install Dependencies:
npm installThis installs all Node.js packages for the frontend and prepares the project.
-
Generate Declarations (Optional, but recommended for development):
dfx generateThis generates TypeScript declarations for the Motoko backend.
-
Set Up Environment Variables (Optional):
- The project uses a
.envfile for canister IDs and network settings. A sample is provided; customize as needed for local vs. mainnet.
- The project uses a
-
Start the local ICP replica:
dfx start --clean --background -
Deploy the canisters:
dfx deploy --network local- This deploys the backend (
paywall_backend), frontend (paywall_frontend), and Internet Identity (for local testing).
- This deploys the backend (
-
Access the local frontend at
http://localhost:4943/?canisterId=<frontend-canister-id>(find IDs in.dfx/local/canister_ids.json).
-
Ensure you have cycles in your wallet for deployment.
-
Deploy to ICP mainnet:
dfx deploy --network ic- This uses the configuration in
dfx.jsonand.env. - Note: Mainnet deployment costs cycles; monitor via the ICP dashboard.
- This uses the configuration in
-
After deployment, update your frontend URL and canister IDs in any integrations.
For production, always verify canister IDs and use certified assets for security.
The Paywall Builder is the user interface for creating and managing paywalls. Access it at https://4kz7m-7iaaa-aaaab-adm5a-cai.icp0.io/.
-
Sign In: Use Internet Identity to authenticate. This links your principal to paywall ownership.
-
Configure Paywall:
- Price (ICP): Set the amount users pay (e.g., 0.1 ICP). Minimum ensures coverage of the 1% fee (or 0.001 ICP min).
- Destination Splits: Define up to 3 destinations for payments after fees.
- Separate Destinations: Payments can be split by percentage (must sum to 100%). Each destination receives its share.
- Types:
- Principal: Send to an ICP principal (e.g., wallet or canister). Enable "Convert to Cycles" to top up canister cycles via CMC.
- Account ID: Send to a 64-hex ledger account ID (legacy format; no cycle conversion).
- Example: 70% to your wallet principal, 30% to a canister for cycles.
- Associated URL: The URL where this paywall will be deployed (e.g., https://example.com).
- Session Duration: Set access time post-payment (days/hours/minutes/seconds).
- Custom Prompts (Optional): Login and payment messages for user experience.
-
Create and Generate Script:
- Submit to create the paywall.
- Copy the generated
<script>tag for integration.
- My Paywalls: Lists your created paywalls with configs, usage counts (refreshable), and embed scripts.
- Usage Count: Tracks payments; refresh to update from backend.
- Vibe Coding Prompt: For each paywall, a pre-generated prompt is provided that can be copied to integrate the paywall into vibe-coded apps (e.g., using AI-assisted coding tools). This prompt includes integration instructions, troubleshooting tips, and paywall details for seamless one-pass integration.
Embed the generated script in your web project to enforce the paywall.
- Add to the
<head>of your HTML:<script type="module" data-paywall data-backend-id="4d2uq-jaaaa-aaaab-adm4q-cai" src="https://4kz7m-7iaaa-aaaab-adm5a-cai.icp0.io/paywall.js?paywallId=pw-0"></script> - Attributes:
data-paywall: Marks the script.data-backend-id: Backend canister ID (fixed for this app).
- Query Param:
?paywallId=<your-id>links to your config.
- On load, it checks access via backend query.
- If no access: Shows overlay prompting login/payment.
- Users deposit ICP to their derived subaccount, then pay.
- On success: Hides overlay, grants access for session duration.
- CORS Headers: If the script fails to load or communicate:
- Ensure your server allows cross-origin requests from
*.icp0.io. - Set headers:
Access-Control-Allow-Origin: *(or specific ICP domains),Access-Control-Allow-Methods: GET, OPTIONS,Access-Control-Allow-Headers: *. - For static sites (e.g., GitHub Pages), use a proxy or host on ICP.
- Ensure your server allows cross-origin requests from
- Script Blocked: Browser extensions (ad blockers) may interfere; test in incognito.
- Local Testing: Use
dfx deploy --network localand update script src to local URL (e.g.,http://<frontend-id>.localhost:4943/paywall.js?paywallId=<id>). - Payment Failures: Ensure sufficient balance including fees. Check console for errors.
IC Paywall supports integration with AI-assisted coding tools like vibe coding apps. For each paywall in "My Paywalls", a customizable vibe coding prompt is generated. This prompt provides a complete guide to integrate the paywall in one pass, including:
- The exact embed script tag.
- CORS configuration instructions.
- Frontend and backend enforcement tips (e.g., using
window.paywallHandshakeandhasAccesschecks). - Troubleshooting for common issues like page reloads, origin mismatches, and access propagation.
- Paywall details like price, prompts, and session duration.
Copy the prompt and paste it into your vibe coding tool to automatically generate or update your app with paywall enforcement. This is ideal for vibe-coded apps, ensuring seamless monetization without manual coding.
For maximum security, combine client-side script with backend enforcement:
-
Frontend Handshake:
- Before rendering sensitive UI:
window.paywallHandshake(() => { /* logout or hide */ }); - Blocks until access confirmed; returns
trueif granted.
- Before rendering sensitive UI:
-
Backend Checks (Motoko/Rust):
- In canister methods: Query
paywall_backend.hasAccess(caller, paywallId). - Example (Motoko):
if (not (await paywall_backend.hasAccess(caller, "pw-0"))) { Debug.trap("Access denied"); }; - Prevents bypassing client-side checks.
- In canister methods: Query
-
Periodic Checks:
- Re-validate every 60s: Use
setIntervalwithpaywallHandshake. - Invalidate session if fails.
- Re-validate every 60s: Use
-
Audit Logs: Use target canister for hooks (future expansion).
- Edit: In "My Paywalls", click "Edit" to update config. Changes apply immediately.
- Delete: In "My Paywalls", click "Delete" to remove the paywall.
- Warning: Deleting a paywall is permanent and cannot be undone. This action will:
- Lose all associated user accounts and funds in subaccounts. Users with balances will lose access/funds—export data first if needed.
- Break any websites or apps that have integrated this paywall, potentially causing errors or unexpected behavior for users.
- Require manual removal of the paywall script from all integrated projects to avoid runtime issues.
- Disrupt ongoing sessions and payments; notify users and integrators in advance if possible.
- Proceed with caution, especially if the paywall is in active use.
- Warning: Deleting a paywall is permanent and cannot be undone. This action will:
- Backend (Motoko): Manages configs, derives subaccounts, handles payments via ICP ledger/CMC.
- Frontend (React): UI for creation/management.
- Script (paywall.js): Client-side enforcement with overlays and periodic checks.
- Payments: 1% fee (min 0.001 ICP) to fixed account; remainder split/converted.
- Security: Uses salted derivations for privacy; Internet Identity for auth.
View source: GitHub Repo.
- Deployment Errors: Ensure DFX version matches (0.29.2). Check cycles balance.
- Auth Failures: Clear browser cache; ensure II URL is correct.
- Payment Issues: Verify ledger ID; check console for transfer errors.
- Script Not Loading: Confirm canister IDs; test with
dfx canister call. - Debugging: Use browser console; enable Motoko debug prints.
For help, open a GitHub issue.
Contributions welcome! Fork the repo, create a branch, and submit a PR. Follow code style in existing files.
See LICENSE
