- Removed puma image from header navigation - Replaced with bold 'pounce' text wordmark - Uses Playfair Display font (font-display) - Responsive sizing: 1.5rem (mobile) to 1.75rem (desktop) - Clean, minimal, professional appearance - Removed unused Image import dependency
pounce — Domain Availability Monitoring
A professional full-stack application for monitoring domain name availability with TLD price tracking and intelligence.
Features
Core Functionality
- Domain Availability Monitoring — Track any domain and get notified when it becomes available
- Domain Portfolio Management — Track domains you own with purchase price, value, and ROI
- Domain Valuation Engine — 100% transparent algorithmic valuation with detailed breakdown
- Smart Pounce Auctions — Aggregated auctions from GoDaddy, Sedo, NameJet & more
- TLD Price Intelligence — Compare prices across 886+ TLDs from Porkbun API
- Automated Price Scraping — Daily cronjob scrapes real TLD prices from public APIs
- Price Change Alerts — Email notifications when TLD prices change >5%
- Expiration Tracking — Monitor domain expiration dates and plan ahead
- Real-time Checks — RDAP, WHOIS, and DNS-based availability verification
- Swiss Domain Support — Special RDAP integration for .ch/.li domains via nic.ch
- Historical Data — Track price trends and availability history over time (12 months)
- Email Notifications — Domain available alerts, price changes, weekly digests
Smart Pounce Auction Aggregator
- Multi-Platform Search — GoDaddy, Sedo, NameJet, SnapNames, DropCatch
- Ending Soon — Auctions ending in < 1 hour for sniping opportunities
- Hot Auctions — Most-bid domains across all platforms
- Smart Opportunities — AI-powered detection of undervalued domains
- Affiliate Integration — Click through to bid (no payment handling = Swiss GwG compliant)
- Filters — Search by keyword, TLD, platform, price range
Domain Valuation (Transparent)
- Clear Formula —
Value = Base × Length × TLD × Keyword × Brand - Factor Breakdown — Each multiplier explained (e.g., "4-letter domain ×5.0")
- Confidence Levels — High/Medium/Low based on score consistency
- Real TLD Costs — Registration cost context from database
- Value-to-Cost Ratio — Investment decision metric
- Disclaimer — Clear limitations of algorithmic valuation
User Experience
- Modern UI — Clean, minimalist dark-mode design with smooth animations
- Responsive — Fully optimized for desktop, tablet, and mobile
- Authentication — Secure JWT-based auth with subscription tiers
- Dashboard — Personal watchlist with status indicators and actions
Security Features (v1.1)
- Password Reset — Secure token-based password recovery via email
- Email Verification — Optional email confirmation for new accounts
- Rate Limiting — Protection against brute-force attacks (slowapi)
- Stripe Payments — Secure subscription payments with Stripe Checkout
- Stripe Customer Portal — Manage billing, view invoices, cancel subscriptions
- Contact Form — With email confirmation and spam protection
- Newsletter — Subscribe/unsubscribe with double opt-in
CI/CD Pipeline (v1.2)
- GitHub Actions — Automated CI/CD on push to main
- Frontend Lint — ESLint + TypeScript type checking
- Backend Lint — Ruff linter for Python
- Docker Build — Multi-stage build verification
- Security Scan — Trivy vulnerability scanner
- Automated Deploy — SSH deployment to production server
TLD Detail Page (Professional)
- Price Hero — Instant view of cheapest price with direct registration link
- Price Alert System — Subscribe to email notifications for price changes
- Interactive Price Chart — 1M/3M/1Y/ALL time periods with hover tooltips
- Domain Search — Check availability directly on the TLD page
- Registrar Comparison — Full table with Register/Renew/Transfer prices + external links
- Savings Calculator — Shows how much you save vs most expensive registrar
- Renewal Warning — ⚠️ indicator when renewal price is >1.5x registration price
- Related TLDs — Smart suggestions based on current TLD (e.g., .com → .net, .org, .io)
- Quick Stats — Average price, price range, 30-day change, registrar count
Tech Stack
Backend
| Technology | Purpose |
|---|---|
| Python 3.12+ | Runtime |
| FastAPI | Async web framework |
| SQLAlchemy 2.0 | Async ORM |
| SQLite/PostgreSQL | Database |
| APScheduler | Background job scheduling |
| python-whois | WHOIS domain lookups |
| whodap | RDAP domain lookups |
| httpx | Async HTTP client (for custom RDAP) |
| BeautifulSoup4 | Web scraping (backup) |
| Pydantic | Data validation |
| JWT (python-jose) | Authentication |
Frontend
| Technology | Purpose |
|---|---|
| Next.js 14 | React framework (App Router) |
| TypeScript | Type safety |
| Tailwind CSS | Styling |
| Zustand | State management |
| Lucide React | Icons (outlined style) |
| clsx | Conditional classes |
Project Structure
pounce/
├── backend/
│ ├── app/
│ │ ├── api/ # API endpoints
│ │ │ ├── auth.py # Authentication (register, login, me)
│ │ │ ├── check.py # Domain availability check
│ │ │ ├── domains.py # Domain watchlist CRUD
│ │ │ ├── subscription.py # User subscription management
│ │ │ ├── tld_prices.py # TLD pricing data
│ │ │ └── admin.py # Admin endpoints
│ │ ├── models/ # SQLAlchemy models
│ │ │ ├── user.py # User model
│ │ │ ├── domain.py # Domain watchlist model
│ │ │ ├── subscription.py # Subscription tiers
│ │ │ └── tld_price.py # TLD pricing model
│ │ ├── schemas/ # Pydantic schemas
│ │ ├── services/ # Business logic
│ │ │ ├── auth.py # Auth service (JWT, hashing)
│ │ │ ├── domain_checker.py # RDAP/WHOIS/DNS checks
│ │ │ ├── email_service.py # Email notifications (SMTP)
│ │ │ ├── price_tracker.py # Price change detection & alerts
│ │ │ └── tld_scraper/ # TLD price scraping
│ │ │ ├── __init__.py
│ │ │ ├── base.py # Base scraper class
│ │ │ ├── porkbun.py # Porkbun API scraper
│ │ │ ├── tld_list.py # TLD-List scraper (placeholder)
│ │ │ └── aggregator.py # Combines sources, saves to DB
│ │ ├── config.py # Environment settings
│ │ ├── database.py # Database connection
│ │ ├── main.py # FastAPI app entry
│ │ └── scheduler.py # Background jobs
│ ├── scripts/ # Utility scripts
│ │ ├── seed_tld_prices.py # Initial TLD data scrape
│ │ ├── export_tld_prices.py # Export DB to JSON
│ │ ├── import_tld_prices.py # Import JSON to DB
│ │ └── tld_prices_export.json # Price data backup
│ ├── requirements.txt
│ ├── Dockerfile
│ └── env.example
├── frontend/
│ ├── src/
│ │ ├── app/ # Next.js App Router pages
│ │ │ ├── page.tsx # Homepage with domain checker
│ │ │ ├── layout.tsx # Root layout
│ │ │ ├── dashboard/ # User dashboard
│ │ │ ├── login/ # Login page
│ │ │ ├── register/ # Registration page
│ │ │ ├── pricing/ # Pricing plans
│ │ │ └── tld-pricing/ # TLD price intelligence
│ │ │ ├── page.tsx # TLD overview
│ │ │ └── [tld]/ # TLD detail page
│ │ ├── components/ # React components
│ │ │ ├── Header.tsx # Navigation header
│ │ │ ├── Footer.tsx # Site footer
│ │ │ └── DomainChecker.tsx # Domain search component
│ │ └── lib/ # Utilities
│ │ ├── api.ts # API client
│ │ └── store.ts # Zustand store
│ ├── tailwind.config.ts # Tailwind configuration
│ ├── package.json
│ ├── Dockerfile
│ └── env.example
├── docker-compose.yml # Docker deployment
├── DEPLOYMENT.md # Deployment guide
└── README.md
Pages Overview
| Route | Description | Auth Required |
|---|---|---|
/ |
Homepage with domain checker, features, pricing preview | No |
/login |
User login | No |
/register |
User registration | No |
/forgot-password |
Request password reset | No |
/reset-password |
Reset password with token | No |
/verify-email |
Verify email with token | No |
/dashboard |
Personal domain watchlist | Yes |
/pricing |
Subscription plans with Stripe checkout | No |
/tld-pricing |
TLD price overview with trends | No* |
/tld-pricing/[tld] |
TLD detail with registrar comparison | Yes |
/auctions |
Smart Pounce auction aggregator | No* |
/contact |
Contact form | No |
/about |
About us | No |
/blog |
Blog & Newsletter signup | No |
/privacy |
Privacy policy | No |
/terms |
Terms of service | No |
/imprint |
Legal imprint | No |
*Unauthenticated users see limited data with shimmer effects
Quick Start
Prerequisites
- Python 3.12+
- Node.js 18+
- npm or yarn
1. Clone Repository
git clone https://git.6bit.ch/yvg/pounce.git
cd pounce
2. Backend Setup
cd backend
# Create virtual environment
python3 -m venv venv
source venv/bin/activate # Linux/macOS
# .\venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# Create environment file
cp env.example .env
# Generate secret key and add to .env
python -c "import secrets; print(f'SECRET_KEY={secrets.token_hex(32)}')"
Edit .env:
DATABASE_URL=sqlite+aiosqlite:///./domainwatch.db
SECRET_KEY=your-generated-secret-key
CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
Start backend:
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
3. Frontend Setup
cd frontend
# Install dependencies
npm install
# Create environment file
echo "NEXT_PUBLIC_API_URL=http://localhost:8000" > .env.local
# Start development server
npm run dev
4. Access Application
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
- API Docs: http://localhost:8000/docs
API Endpoints
Authentication
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/register |
Register new user (sends verification email) |
| POST | /api/v1/auth/login |
Login (returns JWT) |
| GET | /api/v1/auth/me |
Get current user |
| PUT | /api/v1/auth/me |
Update current user |
| POST | /api/v1/auth/forgot-password |
Request password reset |
| POST | /api/v1/auth/reset-password |
Reset password with token |
| POST | /api/v1/auth/verify-email |
Verify email with token |
| POST | /api/v1/auth/resend-verification |
Resend verification email |
Domain Check
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/check |
Check domain availability |
Domain Watchlist
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/domains |
List watched domains |
| POST | /api/v1/domains |
Add domain to watchlist |
| DELETE | /api/v1/domains/{id} |
Remove domain |
| POST | /api/v1/domains/{id}/refresh |
Refresh domain status |
| GET | /api/v1/domains/{id}/history |
Get check history |
TLD Prices
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/tld-prices/overview |
Get all TLDs overview |
| GET | /api/v1/tld-prices/trending |
Get trending TLDs |
| GET | /api/v1/tld-prices/{tld} |
Get TLD details |
| GET | /api/v1/tld-prices/{tld}/history |
Get price history |
| GET | /api/v1/tld-prices/{tld}/compare |
Compare registrar prices |
Price Data Consistency
All TLD price endpoints use a unified pricing strategy:
-
Static TLDs (18 popular): Rich multi-registrar data (5+ registrars per TLD)
- .com, .net, .org, .io, .ai, .dev, .app, .xyz, .tech, .online, .store, .me, .info, .biz, .ch, .de, .uk, .co
-
Database TLDs (869+): Scraped from Porkbun API (single registrar)
Price Calculation (consistent across all endpoints):
avg_price = sum(registrar_prices) / count(registrars)
min_price = min(registrar_prices)
max_price = max(registrar_prices)
This ensures identical prices on:
- Overview table (
/overview) - Detail page (
/{tld}) - Compare page (
/{tld}/compare) - Trending cards (
/trending)
Subscription & Payments
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/subscription |
Get current subscription |
| GET | /api/v1/subscription/tiers |
Get available tiers |
| GET | /api/v1/subscription/features |
Get current features |
| POST | /api/v1/subscription/checkout |
Create Stripe checkout session |
| POST | /api/v1/subscription/portal |
Create Stripe customer portal |
| POST | /api/v1/subscription/cancel |
Cancel subscription |
Price Alerts
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/price-alerts |
List user's price alerts |
| POST | /api/v1/price-alerts |
Create new price alert |
| GET | /api/v1/price-alerts/status/{tld} |
Check alert status for TLD |
| GET | /api/v1/price-alerts/{tld} |
Get alert for specific TLD |
| PUT | /api/v1/price-alerts/{tld} |
Update alert settings |
| DELETE | /api/v1/price-alerts/{tld} |
Delete alert |
| POST | /api/v1/price-alerts/{tld}/toggle |
Toggle alert on/off |
Contact & Newsletter
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/contact |
Submit contact form |
| POST | /api/v1/contact/newsletter/subscribe |
Subscribe to newsletter |
| POST | /api/v1/contact/newsletter/unsubscribe |
Unsubscribe from newsletter |
| GET | /api/v1/contact/newsletter/status |
Check subscription status |
Webhooks
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/webhooks/stripe |
Stripe webhook handler |
Smart Pounce (Auctions)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/auctions |
Search auctions across platforms |
| GET | /api/v1/auctions/ending-soon |
Auctions ending within X hours |
| GET | /api/v1/auctions/hot |
Most-bid auctions |
| GET | /api/v1/auctions/opportunities |
AI-powered opportunities (auth) |
| GET | /api/v1/auctions/stats |
Platform statistics |
Admin
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/admin/users |
List all users |
| POST | /api/v1/admin/upgrade-user |
Upgrade user subscription |
| POST | /api/v1/admin/scrape-tld-prices |
Manually trigger TLD price scrape |
| GET | /api/v1/admin/tld-prices/stats |
Get TLD price database stats |
Subscription Tiers
| Feature | Scout (Free) | Trader (€19/mo) | Tycoon (€49/mo) |
|---|---|---|---|
| Watchlist Domains | 5 | 50 | 500 |
| Portfolio Domains | — | 25 | Unlimited |
| Check Frequency | Daily | Hourly | 10 min |
| Notifications | SMS/Telegram | + Webhooks | |
| Domain Valuation | — | ✓ | ✓ |
| SEO Metrics | — | — | ✓ |
| Check History | — | 90 days | Unlimited |
| API Access | — | — | ✓ |
| Bulk Tools | — | — | ✓ |
Environment Variables
Backend (.env)
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
Database connection string | sqlite+aiosqlite:///./domainwatch.db |
SECRET_KEY |
JWT signing key (min 32 chars) | Required |
ALLOWED_ORIGINS |
Allowed origins (comma-separated) | http://localhost:3000 |
ACCESS_TOKEN_EXPIRE_MINUTES |
JWT token lifetime | 10080 (7 days) |
SITE_URL |
Frontend URL (for email links) | http://localhost:3000 |
REQUIRE_EMAIL_VERIFICATION |
Require email verification | false |
SCHEDULER_CHECK_INTERVAL_HOURS |
Domain check interval | 24 |
| SMTP Settings | ||
SMTP_HOST |
Email server host | Optional |
SMTP_PORT |
Email server port | 587 |
SMTP_USER |
Email username | Optional |
SMTP_PASSWORD |
Email password | Optional |
SMTP_FROM_EMAIL |
Sender email | noreply@pounce.ch |
CONTACT_EMAIL |
Contact form recipient | support@pounce.ch |
| Stripe Settings | ||
STRIPE_SECRET_KEY |
Stripe API secret key | Optional |
STRIPE_WEBHOOK_SECRET |
Stripe webhook secret | Optional |
STRIPE_PRICE_TRADER |
Trader plan Price ID | Optional |
STRIPE_PRICE_TYCOON |
Tycoon plan Price ID | Optional |
Frontend (.env.local)
| Variable | Description | Default |
|---|---|---|
NEXT_PUBLIC_API_URL |
Backend API URL | http://localhost:8000 |
Production Deployment
Docker (Recommended)
# Clone repository
git clone https://git.6bit.ch/yvg/pounce.git
cd pounce
# Set environment variables
export SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
# Build and start
docker-compose up -d --build
Manual Deployment
See DEPLOYMENT.md for detailed instructions including:
- Systemd service setup
- PM2 for Node.js
- Nginx reverse proxy configuration
- SSL/HTTPS with Let's Encrypt
- PostgreSQL database setup
Domain Checking Methods
pounce uses multiple methods to verify domain availability:
- Custom RDAP — For TLDs with own RDAP servers (e.g.,
.ch,.liviardap.nic.ch) - RDAP via whodap — Modern protocol with detailed data, supported by major registries
- WHOIS (Fallback) — Traditional protocol for domains without RDAP support
- DNS (Quick check) — Fast initial availability check via DNS queries
The system automatically falls back to the next method if one fails.
Supported TLDs with Custom RDAP
| TLD | RDAP Server | Notes |
|---|---|---|
.ch |
rdap.nic.ch |
Swiss domains - WHOIS blocked |
.li |
rdap.nic.ch |
Liechtenstein - same registry |
Standard RDAP TLDs
.com, .net, .org, .info, .biz, .io, .co, .ai, .app, .dev, .xyz, .me, and many more.
TLD Price Scraping
pounce automatically scrapes TLD prices from public sources for price intelligence and trend tracking.
Data Source
Primary: Porkbun Public API (no API key required!)
POST https://api.porkbun.com/api/json/v3/pricing/get
- ✅ 886+ TLDs with pricing
- ✅ Registration, Renewal, Transfer prices
- ✅ No authentication needed
- ✅ Updated daily via scheduler
Scheduler Jobs
| Job | Schedule | Description |
|---|---|---|
| Domain Check | Configurable (default: daily) | Checks all watched domains |
| TLD Price Scrape | Daily at 03:00 UTC | Scrapes current TLD prices |
| Price Change Alerts | Daily at 04:00 UTC | Sends email for price changes >5% |
Manual Scrape
Trigger a manual TLD price scrape:
curl -X POST http://localhost:8000/api/v1/admin/scrape-tld-prices
Response:
{
"message": "TLD price scrape completed",
"status": "success",
"tlds_scraped": 886,
"prices_saved": 886,
"sources_succeeded": 1
}
Database Stats
Get current TLD price data statistics:
curl http://localhost:8000/api/v1/admin/tld-prices/stats
Response:
{
"total_records": 886,
"unique_tlds": 886,
"unique_registrars": 1,
"latest_record": "2025-12-08T08:04:54",
"data_range_days": 0
}
Price Data Model
TLDPrice:
- tld: str # e.g., "com", "io", "ai"
- registrar: str # e.g., "porkbun"
- registration_price: float
- renewal_price: float
- transfer_price: float
- currency: str # "USD"
- recorded_at: datetime # For historical tracking
Future Data Sources
The scraper architecture supports multiple sources:
- Porkbun API ✅ (active)
- TLD-List.com (blocked - placeholder)
- Namecheap Affiliate (requires signup)
- Cloudflare (requires account)
Email Notifications
pounce supports automated email notifications for domain availability and price changes.
Setup
Configure SMTP settings in your .env:
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
Notification Types
| Type | Trigger | Description |
|---|---|---|
| Domain Available | Watched domain becomes available | Instant alert to domain owner |
| Price Change Alert | TLD price changes >5% | Daily batch after price scrape |
| Weekly Digest | Every Sunday | Summary of watched domains & price trends |
Email Templates
All emails feature:
- Dark mode branded design matching the app
- Clear call-to-action buttons
- Direct links to register domains
- Unsubscribe options
Test Email
# Via Python
cd backend && python3 -c "
import asyncio
from app.services.email_service import email_service
async def test():
result = await email_service.send_domain_available_alert(
'test@example.com',
'example.com',
'Test User'
)
print('Email sent:', result)
asyncio.run(test())
"
Design System
Colors
- Background: Dark (
#0a0a0a) - Foreground: Light (
#fafafa) - Accent: Teal (
#00d4aa) - Warning: Orange (
#f97316) - Success: Green (same as accent)
Typography
- Display: Playfair Display (serif)
- Body: Inter (sans-serif)
- Mono: JetBrains Mono (code)
Components
- All icons use outlined style (Lucide React)
- Minimalist, award-winning aesthetic
- Smooth animations and transitions
- Responsive design (mobile-first)
Development
Backend
cd backend
source venv/bin/activate
# Run with auto-reload
uvicorn app.main:app --reload
# API docs available at:
# http://localhost:8000/docs (Swagger)
# http://localhost:8000/redoc (ReDoc)
Frontend
cd frontend
# Development server
npm run dev
# Lint
npm run lint
# Build for production
npm run build
# Start production server
npm start
Troubleshooting
Backend won't start
- Check Python version:
python3 --version(needs 3.12+) - Ensure virtual environment is activated
- Check
.envfile exists and has validSECRET_KEY - Check for syntax errors in config files
Frontend can't connect to backend
- Ensure backend is running on port 8000
- Check
NEXT_PUBLIC_API_URLin.env.local - Verify CORS origins in backend
.env - Check browser console for CORS errors
Domain checks failing
- Some TLDs may have rate limits
- Certain ccTLDs require special handling (see below)
- Check backend logs for specific errors
Swiss/Liechtenstein domains (.ch, .li):
- WHOIS is blocked for automated requests
- pounce uses the official
rdap.nic.chAPI instead - This is automatic - no configuration needed
Other ccTLDs:
- Some country code TLDs don't support RDAP
- pounce falls back to DNS checking
- Results may be less detailed (no registrar info)
Database errors
- Delete
domainwatch.dbto reset (dev only) - Check database URL format in
.env - Ensure write permissions on database directory
License
MIT License
Support
For issues and feature requests, please open a GitHub issue or contact support@pounce.dev