Clerk Waitlist Implementation
This document describes the hybrid implementation of Clerk's official waitlist component integrated with our existing custom waitlist system.
Overview
We've implemented a hybrid approach that combines Clerk's polished waitlist UI components with our existing custom role-based system. This provides the best user experience while preserving all our existing functionality and user data.
Architecture
Hybrid System Design
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ New Users │ │ Existing Users │ │ OAuth Users │
│ │ │ │ │ │
│ Clerk Waitlist │ │ Custom Waitlist │ │ Direct Access │
│ ↓ │ │ ↓ │ │ ↓ │
│ Clerk Approval │ │ Admin Approval │ │ "user" role │
│ ↓ │ │ ↓ │ │ │
│"waitlist- │ │"waitlist- │ │ │
│ approved" role │ │ approved" role │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
↓
┌──────────────────┐
│ Onboarding │
│ ↓ │
│ "user" role │
└──────────────────┘User Journey Flows
New Users (Clerk Waitlist)
- Visit Homepage → See Clerk
<Waitlist />component - Submit Email → Joins Clerk's waitlist system
- Admin Approval → Admin approves via Clerk Dashboard
- Webhook Triggers →
user.updatedevent detected - Role Assignment → System grants
"waitlist-approved"role - Access Granted → User can sign in and complete onboarding
Existing Users (Custom System)
- Existing Flow → Continue using custom waitlist system
- Admin Approval → Via existing admin dashboard
- Role Assignment →
"waitlist-approved"role granted - Access Granted → User proceeds to onboarding
Implementation Details
1. ClerkProvider Configuration
// apps/dodev/components/app-providers.tsx
<ClerkProvider
publishableKey={process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY}
signInUrl="/sign-in"
signUpUrl="/sign-up"
waitlistUrl="/" // 👈 Points to homepage for waitlist
allowedRedirectOrigins={[...]}
>2. Waitlist Component Integration
Homepage Integration
// apps/dodev/components/hero-section.tsx
{!isAuthenticated && (
<ClerkWaitlistSection
title="Get Early Access"
description="Join our waitlist to be the first to experience our AI-powered development platform."
showDecorative={false}
/>
)}Dedicated Waitlist Page
- Route:
/waitlist - Features:
- Unauthenticated: Shows Clerk waitlist signup
- Waitlisted: Shows status with progress indicators
- Approved: Welcome message with dashboard access
3. Webhook Integration
The existing Clerk webhook (/api/webhooks/clerk/route.ts) has been enhanced to detect and handle Clerk waitlist approvals:
if (eventType === "user.updated") {
// Detect Clerk waitlist approval
const hasBasicAccess = evt.data.email_addresses?.length > 0
const hasNoCustomRoles = !currentRoles.includes("waitlist-approved") &&
!currentRoles.includes("user") &&
currentRoles.length <= 1
const wasApprovedFromClerkWaitlist = hasBasicAccess && hasNoCustomRoles &&
currentRoles.includes("waitlist")
if (wasApprovedFromClerkWaitlist) {
// Grant waitlist-approved role (matches existing flow)
const updatedRoles = [...currentRoles.filter(role => role !== "waitlist"), "waitlist-approved"]
await client.users.updateUser(id, {
publicMetadata: {
...public_metadata,
roles: updatedRoles,
waitlistApprovedAt: Date.now(),
approvedBy: "clerk-waitlist",
source: "clerk-waitlist",
},
})
}
}User Management
Clerk Dashboard Management
- Navigate to: Clerk Dashboard → Waitlist
- Approve Users: Click menu (⋯) → "Invite" to approve access
- Deny Users: Click menu (⋯) → "Deny" to reject access
Existing Admin Dashboard
- Custom waitlist users continue to be managed via existing admin interface
- All functionality preserved: Bulk approval, rejection reasons, analytics
Role System Integration
Role Hierarchy (Unchanged)
"waitlist" → "waitlist-approved" → "user" → "staff" → "admin" → "super_admin"Role Sources
"clerk-waitlist": Users approved via Clerk Dashboard"admin": Users approved via custom admin dashboard"organic": Default source for new signups
Configuration Requirements
1. Clerk Dashboard Setup
- ✅ Waitlist Mode Enabled: User Authentication → Restrictions → Waitlist
- ✅ Webhook Configured: Points to
/api/webhooks/clerk - ✅ Events Subscribed:
user.created,user.updated,user.deleted
2. Environment Variables
# Required for Clerk integration
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
CLERK_SECRET_KEY=sk_live_...
CLERK_WEBHOOK_SECRET=whsec_...
# Required for Convex sync
NEXT_PUBLIC_CONVEX_URL=https://...Pages and Components
New Components
ClerkWaitlistSection- Reusable waitlist component with Clerk integration/waitlistpage - Dedicated waitlist page with status handling
Updated Components
- Homepage - Integrated Clerk waitlist for unauthenticated users
- Hero Section - Shows waitlist instead of "Get Started" button
- ClerkProvider - Added
waitlistUrlconfiguration
Benefits of Hybrid Approach
✅ Advantages
- Zero Risk: Existing users and functionality unaffected
- Enhanced UX: New users get Clerk's polished waitlist interface
- Preserved Investment: All custom admin tools and analytics maintained
- Seamless Integration: Both systems feed into same role hierarchy
- Future Flexibility: Can gradually migrate existing users if desired
⚠️ Considerations
- Dual Management: Admins need to check both Clerk Dashboard and custom admin
- Training Required: Team needs to understand both approval flows
- Monitoring: Need to track both systems for waitlist analytics
Testing Checklist
New User Flow (Clerk Waitlist)
- Homepage shows Clerk waitlist component for unauthenticated users
- Email submission works via Clerk waitlist
- User appears in Clerk Dashboard waitlist
- Admin approval via Clerk Dashboard works
- Webhook grants
"waitlist-approved"role correctly - User can sign in after approval
- Onboarding flow works normally
Existing User Flow (Custom System)
- Existing admin dashboard continues to work
- Custom waitlist approval still grants
"waitlist-approved"role - All existing functionality preserved
- Analytics and reporting continue to work
Integration Points
- Role transitions work correctly for both systems
- Convex sync works for both approval methods
- User metadata includes correct source information
- No conflicts between the two systems
Migration Strategy for Existing Users
Option A: Status Quo (Recommended)
- Keep existing users in custom system
- Use Clerk waitlist only for new signups
- Maintain both systems indefinitely
Option B: Gradual Migration
- Create admin tool to migrate existing waitlist users to Clerk
- Notify users about the transition
- Migrate in batches with rollback capability
Option C: Full Migration
- Export all waitlist users from custom system
- Import into Clerk waitlist (if API available)
- Sunset custom waitlist system
Troubleshooting
Common Issues
Webhook Not Triggering
- Check webhook URL in Clerk Dashboard
- Verify
CLERK_WEBHOOK_SECRETenvironment variable - Check webhook endpoint is publicly accessible
Role Assignment Not Working
- Verify webhook logic for detecting Clerk approvals
- Check Convex sync is working correctly
- Ensure user has correct roles in Clerk publicMetadata
Waitlist Component Not Showing
- Verify
waitlistUrl="/"in ClerkProvider - Check Clerk waitlist mode is enabled in dashboard
- Ensure component is properly imported
Debugging Tools
- Clerk Dashboard: Check webhook delivery status
- Server Logs: Monitor webhook processing
- Admin Dashboard: Verify role assignments
- Browser DevTools: Check component rendering
Future Enhancements
Potential Improvements
- Unified Admin Interface: Single dashboard for both systems
- Advanced Analytics: Combined reporting across both waitlist systems
- Automated Migration Tool: Tool to move users between systems
- Email Templates: Custom email notifications for approvals
- Position Tracking: Integrate Clerk waitlist position with existing tracking
API Integrations
- Clerk Management API: Programmatic waitlist management
- Notification Services: Automated approval notifications
- Analytics Integration: Track conversion rates and user flows
Support and Documentation
Resources
Contact
- Technical Issues: Development team
- User Management: Admin dashboard
- Clerk-specific Issues: Clerk Dashboard → Support