Private football prediction pools for friends, families, and teams.
Rank group tables, predict knockout scores or winners, track leaderboards, and keep the pool private with invite codes.
Tippa is a tournament prediction pool app built with Next.js, Supabase, and Vercel. A group admin creates a private pool, picks the prediction format, shares an invite code, and members submit predictions before each phase locks.
The default game is intentionally simple:
- Group stage: rank each group table.
- Knockout stage: pick winners in the bracket, or predict knockout scores, after group play is done.
- Leaderboard: group-stage points + knockout points = total score.
Groups can also choose easier or harder formats:
- Rank final group tables.
- Pick group-stage match winners.
- Predict exact group-stage scores.
- Pick knockout winners in a full bracket or predict knockout scores.
- Optionally include the third-place match.
- Use scoring presets or custom point values.
The current tournament adapter targets the 2026 World Cup data from the openfootball JSON repository. Tournament data can be synced by cron, script, or manually from the group admin page.
- Google, Apple, and email magic-link login through Supabase Auth
- Private groups with invite codes
- Configurable prediction modes per group
- Group-stage lock at first tournament kickoff
- Admin-opened knockout prediction phase
- Full knockout winner bracket or knockout score prediction mode
- Configurable scoring presets plus advanced custom scoring
- Leaderboard breakdown for group-stage and knockout points
- Configurable prize modes: none, sponsored, buy-in, or hybrid
- Group-specific manual result overrides
- Admin-only manual tournament sync and score recalculation
- Daily Vercel Cron sync support
- Offline/PWA shell basics
- Next.js App Router
- React
- Supabase Auth and Postgres
- Tailwind CSS
- Vercel Cron Jobs
- Vitest for scoring tests
Install dependencies:
npm installCreate a local environment file:
cp .env.example .env.developmentFill in:
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
SUPABASE_SECRET_KEY=
CRON_SECRET=Run the app:
npm run devOpen:
http://localhost:3000The dev script uses Webpack because this project hit a Turbopack proxy issue during local development.
- Create a Supabase project.
- Run the SQL in
supabase/schema.sql. - Enable the auth providers you want under Supabase Auth.
- Add local and production callback URLs in Supabase Auth URL Configuration:
http://localhost:3000/auth/callback
https://your-domain.com/auth/callbackFor Google and Apple OAuth, the provider callback URL registered in Google/Apple should be the Supabase callback:
https://YOUR_SUPABASE_PROJECT_REF.supabase.co/auth/v1/callbackThe prediction system uses mode-specific tables:
group_prediction_settingsgroup_table_predictionsmatch_predictionsknockout_prediction_entries
If you are upgrading from an older Tippa version, reset/recreate the Supabase database with the current supabase/schema.sql. Existing prediction data is not migration-compatible.
NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY are safe to expose to the browser. Supabase Row Level Security policies protect user data.
Keep these secret:
SUPABASE_SECRET_KEYCRON_SECRET- OAuth client secrets
- Apple
.p8private keys
Do not commit .env.development, .env.production, or .env*.local.
Manual sync:
- Log in as a group admin.
- Open the group admin page.
- Click Sync now.
- Click Recalculate scores if you changed overrides or scoring.
Script sync:
npm run sync:tournamentSync one tournament:
npm run sync:tournament -- world-cup-2026Cron sync:
vercel.json defines a daily sync route:
/api/cron/sync-tournamentsVercel Hobby cron is limited to once per day. For more frequent automated syncs, use Vercel Pro or an external scheduler that can call the cron route with:
Authorization: Bearer <CRON_SECRET>- Admin creates a group and chooses the group-stage prediction mode.
- Members submit group-stage predictions.
- Group-stage predictions lock at the first group-stage kickoff.
- Admin syncs tournament data after group play when knockout fixtures are known.
- Admin opens knockout predictions.
- Members pick knockout winners or scores before the first knockout kickoff.
- Scores are recalculated after match results are synced or overridden.
Deploy to Vercel as a Next.js project.
Set production environment variables in Vercel:
NEXT_PUBLIC_SITE_URL=https://your-domain.com
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
SUPABASE_SECRET_KEY=
CRON_SECRET=Use:
npm run buildas the build command.
npm run dev # start local dev server with Webpack
npm run dev:turbo # start local dev server with Turbopack
npm run build # production build
npm run start # start production server
npm run lint # run ESLint
npm run test # run Vitest tests
npm run sync:tournament # sync tournament dataMIT. See LICENSE.