Skip to content

About

A complete waitlist for Better Auth: a live queue, status links, referrals, invites and invite-only sign-up

Topics

Resources

Contributing

Stars

11 stars

Watchers

0 watching

Forks

Repository files navigation

better-auth-waitlist

npm license

A complete waitlist for your Better Auth app. People join, follow their place in line, bring friends with their referral link, and get an invite when you let them in.

  • A real queue: every entry has a live position, and you can boost people up the line.
  • Status links, emailed on join, showing the person's place in line and their share link.
  • Referrals with share links, self-referral detection and a success callback for your rewards.
  • Invites: approve people one by one or "next 50", or invite someone directly. Each invite is a single-use code bound to one email, with an expiry.
  • Manager tools to list, search, approve, reject, requeue, boost and delete entries, gated by the admin plugin's roles or your own check.
  • Invite-only sign-up while the waitlist is on, across every sign-up method (email and password, OAuth, One Tap, magic link, email OTP, anonymous). Existing users keep signing in as usual.
  • No email enumeration: join, refusals and timing look the same whether an email is new, pending, rejected or already a user.
  • Typed, tiny client (about 2 kB gzipped). No server code, zod or better-call reaches the browser.
  • Adapter-agnostic, ESM only, Better Auth ^1.7.0.

Coming from 3.x? v4 is a rewrite: read Upgrading from v3.

Install

pnpm add better-auth-waitlist
# or: npm install better-auth-waitlist / yarn add better-auth-waitlist / bun add better-auth-waitlist

better-auth and @better-auth/core (^1.7.0) are peer dependencies.

Quick start

1. Add the plugin to your server

// auth.ts
import { betterAuth } from "better-auth"
import { admin } from "better-auth/plugins"
import { waitlist } from "better-auth-waitlist"

export const auth = betterAuth({
  // ...database, emailAndPassword, socialProviders
  plugins: [
    admin(), // admins are waitlist managers by default
    waitlist({
      statusLink: { buildUrl: (token) => `https://example.com/waitlist?token=${token}` },
      sendStatusLink: async ({ email, url }) => {
        await sendEmail(email, "You're on the waitlist", `Check your place in line: ${url}`)
      },
      invite: { buildUrl: (code) => `https://example.com/register?code=${code}` },
      sendInvite: async ({ email, url }) => {
        await sendEmail(email, "You're invited", `Create your account: ${url}`)
      },
    }),
  ],
  // Send emails after the response, so timing doesn't reveal who is on the list.
  advanced: { backgroundTasks: { handler: (promise) => waitUntil(promise) } },
})

2. Update your database

The plugin adds a waitlistEntry model. Generate or apply it with the Better Auth CLI, as for any plugin.

3. Add the client plugin

// auth-client.ts
import { createAuthClient } from "better-auth/client"
import { waitlistClient } from "better-auth-waitlist/client"

export const authClient = createAuthClient({ plugins: [waitlistClient()] })

4. Wire up the flow

The plugin has no UI. Your app calls the client from three places:

  1. Join: authClient.waitlist.join({ email }) adds the email and sends the status link.
  2. Status link: confirm and status with the link's token show the person's place in line and their share link.
  3. Invite link: invite.accept({ code }) checks the code; then any Better Auth sign-up method creates the account for the invited email.

Approve people with authClient.waitlist.admin.approve(...) from your admin UI, or auth.api.approveWaitlistEntries(...) from server code. Sign-up is now invite-only.

See Building the pages for complete examples.

Documentation

Contributing

See CONTRIBUTING.md.

License

MIT

About

A complete waitlist for Better Auth: a live queue, status links, referrals, invites and invite-only sign-up

Topics

Resources

Contributing

Stars

11 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages