Waitlist plugin for Better Auth
Made by haxurn
npm install better-waitlistpnpm add better-waitlistyarn add better-waitlistAdd the plugin to your Better Auth configuration:
import { betterAuth } from 'better-auth';
import { waitlist } from 'better-waitlist';
export const auth = betterAuth({
plugins: [waitlist()],
});Run the migration to add the waitlist table to your database:
npx @better-auth/cli migrateOr generate the schema for your ORM:
npx @better-auth/cli generateAdd the client plugin:
import { createAuthClient } from 'better-auth/client';
import { waitlistClient } from 'better-waitlist';
export const authClient = createAuthClient({
plugins: [waitlistClient()],
});import { waitlist } from 'better-waitlist';
export const auth = betterAuth({
plugins: [
waitlist({
// Authentication
requireAdmin: true, // require session for admin endpoints (default: true)
// Entry Management
maxEntries: 0, // maximum entries allowed (0 = unlimited, default: 0)
enabled: true, // allow new waitlist joins (default: true)
// Public Features
allowStatusCheck: true, // allow public status checks (default: true)
showPosition: false, // show position in status response (default: false)
// Invitations
markInvitedOnApprove: false, // mark as invited when approving (default: false)
// Position Management
recalculatePositionOnApprove: false, // recalculate positions when entries are approved/rejected (default: false)
// Callbacks
onJoin: async (entry) => {
// Called when user joins waitlist
console.log('New entry:', entry.email);
},
onApprove: async (entry) => {
// Called when entry is approved
console.log('Approved:', entry.email);
},
onReject: async (entry) => {
// Called when entry is rejected
console.log('Rejected:', entry.email);
},
onComplete: async (entry) => {
// Called when entry is completed (user signs up)
console.log('Completed:', entry.email);
},
}),
],
});// Anonymous user
await authClient.waitlist.join({ email: 'user@example.com' });
// Logged-in user
await authClient.waitlist.join({
email: 'user@example.com',
userId: 'user-123',
});const { data, error } = await authClient.waitlist.getStatus({
email: 'user@example.com',
});
if (data) {
console.log(data.status); // "pending" | "approved" | "rejected"
}const { data, error } = await authClient.waitlist.getPosition({
email: 'user@example.com',
});
if (data) {
console.log(data.position); // real-time position among pending entries
}const { data, error } = await authClient.waitlist.list({
status: 'pending', // optional filter
limit: 20,
offset: 0,
});
if (data) {
console.log(data.entries);
console.log(data.total);
}const { data, error } = await authClient.waitlist.stats();
if (data) {
console.log(data.total);
console.log(data.pending);
console.log(data.approved);
console.log(data.rejected);
}const { data, error } = await authClient.waitlist.approve({
email: 'user@example.com',
});
// With mark as invited
const { data: data2 } = await authClient.waitlist.approve({
email: 'user@example.com',
sendInvite: true, // override plugin setting for this call
});const { data, error } = await authClient.waitlist.reject({
email: 'user@example.com',
});Send an invite to an approved user:
const { data, error } = await authClient.waitlist.promote({
email: 'user@example.com',
});Send invites to all approved users:
const { data, error } = await authClient.waitlist.promoteAll({
status: 'approved', // default: 'approved'
});
if (data) {
console.log(data.promoted); // count of promoted entries
}Mark an entry as complete (e.g., after user signs up):
const { data, error } = await authClient.waitlist.complete({
email: 'user@example.com',
});
if (data) {
console.log(data.entry); // the completed entry data
}The plugin adds a waitlist table with the following fields:
| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier |
email |
string | User's email (unique) |
status |
string | pending | approved | rejected |
position |
number | Position in queue |
userId |
string? | Optional relation to user |
invitedAt |
date? | Timestamp when invite was sent |
createdAt |
date | Timestamp when joined |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /waitlist/join |
None | Join waitlist |
| GET | /waitlist/status |
None | Check status |
| GET | /waitlist/position |
None | Get position |
| GET | /waitlist/list |
Session | List entries |
| GET | /waitlist/stats |
Session | Get waitlist statistics |
| POST | /waitlist/approve |
Session | Approve entry |
| POST | /waitlist/reject |
Session | Reject entry |
| POST | /waitlist/promote |
Session | Send invite to user |
| POST | /waitlist/promote-all |
Session | Send invites to all |
| POST | /waitlist/complete |
Session | Complete entry |
The plugin provides full TypeScript support. Types are automatically inferred when using the client:
// Full type inference
const result = await authClient.waitlist.join({
email: 'test@example.com',
});
// result.data is typed as WaitlistEntry
// result.error is typed as { message: string }Contributions are welcome! Please see our CONTRIBUTING.md for details.
Please read our CODE_OF_CONDUCT.md before participating in our community.