A modern, real-time CTF (Capture The Flag) scoreboard application built with Next.js that provides an enhanced viewing experience for CTFd competitions. This dashboard offers live updates, animated celebrations, comprehensive analytics, and a polished interface for both participants and spectators.
π Static Deployment Ready: This application can be deployed as a static site to GitHub Pages, Netlify, Vercel, or any static hosting platform. It connects directly to your CTFd instance via API, running entirely in the browser.
β οΈ Important: When deploying this application, you must configure CORS in your CTFd instance to allow requests from your deployment domain. See the Deployment section for details.
- Live Rankings: Real-time scoreboard updates with configurable refresh intervals (5-300 seconds)
- Comprehensive User Stats: View scores, solve counts, first bloods, and last solve timestamps
- Pagination Support: Navigate through large participant lists efficiently
- Top 10 Quick View: Instant access to leading competitors
- Challenge Grid: Visual overview of all available challenges with solve counts
- Category Organization: Challenges grouped by categories for easy navigation
- Difficulty Indicators: Visual representation of challenge values and solve rates
- Challenge Details: Expandable cards with descriptions and solver information
- Animated Notifications: Stunning animations when challenges are solved for the first time
- Sound Effects: Audio feedback for first blood achievements
- User Recognition: Highlight first blood achievers with special badges
- Auto-dismiss: Smart timing for celebration displays
- Competition Statistics: Total users, active participants, challenge metrics
- Performance Metrics: Average scores, top performers, submission counts
- Visual Charts: Interactive graphs showing competition progress
- Time Tracking: Live countdown timers and competition duration
- Real-Time Updates: Stream of the latest correct submissions
- User Activity: Track who's solving what in real-time
- Submission History: Comprehensive log of all solve attempts
- Filtering Options: Filter by submission type and user
- Dark/Light Themes: Automatic theme switching based on system preference
- Responsive Design: Optimized for desktop, tablet, and mobile viewing
- Smooth Animations: Polished transitions and micro-interactions
- Accessible Interface: WCAG compliant design with proper ARIA labels
- Easy Setup: Simple dialog for CTFd instance configuration
- API Integration: Secure connection to CTFd API with token authentication
- Flexible Refresh Rates: Configurable polling intervals to balance performance
- URL Validation: Smart handling of CTFd instance URLs
- Node.js 18+
- A running CTFd instance with API access
- CTFd API token with appropriate permissions
-
Clone the repository
git clone <repository-url> cd ctf-scoreboard
-
Install dependencies
npm install # or yarn install # or pnpm install
-
Start the development server
npm run dev # or yarn dev # or pnpm dev
-
Open the application Navigate to http://localhost:3000 in your browser
On first launch, click the settings icon (βοΈ) in the top-right corner to configure your CTFd connection:
- CTFd API URL: Your CTFd instance URL (e.g.,
https://ctf.ncr-external.iaas.iik.ntnu.no) - API Token: Generate from your CTFd admin panel (see below)
- Refresh Interval: How often to poll for updates (5-300 seconds)
- Top Teams Count: Number of teams to display (10-100)
If you're getting 401 Unauthorized errors, you need to configure an API token:
- Log into your CTFd instance as an admin
- Navigate to Admin Panel β Settings β Security
- Scroll to the API section
- Generate a new token or copy an existing one
- Paste the token into the configuration dialog in this application
The application will show a warning banner when authentication is required with instructions on how to fix it.
Note: Some CTFd instances may allow public access to scoreboard data. If your instance requires authentication, you must configure an API token.
- Next.js 15: React framework with App Router
- TypeScript: Type-safe development
- TailwindCSS: Utility-first styling
- Framer Motion: Smooth animations and transitions
- Lucide React: Modern icon library
- TanStack Query: Server state management and caching
- CTFd REST API: Direct integration with CTFd backend
- Rate Limiting: Intelligent request throttling with exponential backoff
- Error Handling: Robust error recovery and user feedback
- Caching: Optimized data fetching with intelligent cache invalidation
- Server-Side Rendering: Fast initial page loads
- Code Splitting: Optimized bundle sizes
- Image Optimization: Automatic image compression and WebP conversion
- Font Optimization: Self-hosted Geist font family
The application is fully responsive and optimized for:
- Desktop: Full-featured dashboard experience
- Tablet: Optimized layouts for medium screens
- Mobile: Touch-friendly interface with swipe gestures
βββ app/ # Next.js App Router pages
βββ components/ # Reusable UI components
β βββ ui/ # Base UI components (shadcn/ui)
β βββ page/ # Page-specific components
βββ hooks/ # Custom React hooks
β βββ api/ # API integration hooks
βββ lib/ # Utility functions and API clients
βββ types/ # TypeScript type definitions
βββ contexts/ # React context providers
βββ public/ # Static assets and sounds
npm run dev: Start development server with Turbopacknpm run build: Build for productionnpm run start: Start production servernpm run lint: Run ESLint
The application includes a Next.js API route (/api/ctfd) that proxies requests to your CTFd instance:
- Scoreboards:
/scoreboardand/scoreboard/top/10 - Challenges:
/challengesand/challenges/{id} - Submissions:
/submissionswith filtering options - Configuration:
/configsfor CTF metadata - Challenge Solves:
/challenges/{id}/solvesfor first blood detection
The application includes audio feedback for enhanced user experience:
- First Blood: Celebration sound for first solves
- Success: General achievement notifications
- Error: Alert sounds for error states
Audio files are included in /public/sounds/ and can be customized.
This scoreboard can be deployed to GitHub Pages as a static site. The application will run entirely in the browser and connect directly to your CTFd instance via its API.
Prerequisites:
- Your CTFd instance must have CORS enabled to allow requests from your GitHub Pages domain
- Generate a CTFd API token with appropriate permissions
Setup Instructions:
-
Configure GitHub Repository Settings:
- Go to your repository Settings β Pages
- Under "Build and deployment", select "GitHub Actions" as the source
-
Deploy:
- Push your changes to the
mainbranch - The GitHub Actions workflow will automatically build and deploy your site
- Your scoreboard will be available at
https://<username>.github.io/<repository-name>/
- Push your changes to the
-
Optional: Custom Domain
- Add a
CNAMEfile in thepublicdirectory with your domain - Configure your DNS settings to point to GitHub Pages
- Update the
basePathinnext.config.tsif deploying to a subpath
- Add a
-
Configure CTFd CORS:
- Add your GitHub Pages URL to CTFd's allowed origins
- This is typically done in CTFd's configuration or reverse proxy settings
Note: The first time you access the deployed site, you'll need to configure it with your CTFd API URL and token using the settings dialog.
npm run build
# The static files will be in the 'out' directory
# Serve them with any static file server- Vercel: Deploy with zero config (will use static export)
- Netlify: Drag and drop the
outfolder or connect your repository - Cloudflare Pages: Connect your repository for automatic deployments
- Any Static Host: Upload the contents of the
outdirectory
- Ensure your CTFd instance is accessible from your deployment environment
- Configure CORS settings in CTFd to allow requests from your deployment domain
- Set appropriate rate limits to avoid overwhelming your CTFd instance
- The application stores configuration (API URL, token) in the browser's localStorage
β οΈ Security Warning:
Data stored in localStorage (including your API token) can be accessed by any script running on the same origin.
Do not use this application on shared or public computers unless you clear localStorage after use.
To clear, open your browser's developer tools and run:localStorage.clear();
If you see HTTP 401 errors in your browser console:
GET https://your-ctfd-instance.com/api/v1/scoreboard [HTTP/2 401]
GET https://your-ctfd-instance.com/api/v1/challenges [HTTP/2 401]
Solution:
- Your CTFd instance requires authentication
- Click the Settings icon (βοΈ) in the top-right corner
- Enter your CTFd API URL and API Token
- Get your API token from: Admin Panel β Settings β Security in your CTFd instance
The application will display a helpful warning banner when authentication is required.
If you see CORS errors in your console:
Access to fetch at 'https://your-ctfd-instance.com' from origin 'http://localhost:3000' has been blocked by CORS policy
Solution:
- Configure your CTFd instance to allow requests from your application's origin
- Add your domain to CTFd's CORS allowlist
- This is typically done in CTFd's
config.pyor via reverse proxy (nginx, etc.)
If you see HTTP 429 (Too Many Requests) errors:
Solution:
- Open Settings (βοΈ) and increase the Refresh Interval
- Reduce the Top Teams Count (higher values = more API calls)
- The application has built-in retry logic with exponential backoff
If the scoreboard isn't refreshing:
Solution:
- Check your Refresh Interval in settings
- Verify your CTFd instance is accessible
- Check browser console for errors
- Try manually refreshing the page
If your settings don't persist after refresh:
Solution:
- Check that localStorage is enabled in your browser
- Clear your browser cache and try again
- Ensure you're not in incognito/private mode (some browsers restrict localStorage)
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
This project is open source and available under the MIT License.
Built with β€οΈ for the CTF community