WhoisScope is an open-source WHOIS lookup platform built with Laravel and Vue.js.
Use it as a REST API, a full-stack web app, or both — with caching, rate limiting, bulk queries, and a multilingual UI.
Quick Start · Features · API · Configuration · Architecture · License
WhoisScope lets you look up domain registration data through a clean web interface or a versioned JSON API. It parses raw WHOIS responses, detects whether a domain is registered, available, or unknown, and returns structured fields such as registrar, creation date, expiry date, and status codes.
The project follows Domain-Driven Design (DDD) so business rules stay independent from Laravel, the WHOIS library, and the Vue frontend.
| Mode | Best for |
|---|---|
| Web UI | Manual lookups, bulk CSV export, exploring results |
| REST API | Integrations, scripts, backend services |
| API + UI | Self-hosted product with built-in documentation at /docs |
| Feature | Description |
|---|---|
| 🔍 Single lookup | Query one domain with summary or full response format |
| 📦 Bulk lookup | Up to 50 domains per request, parallel processing, per-domain status |
| ⚡ Smart cache | Results cached by default (1 hour); repeat queries are near-instant |
| 🛡️ Rate limiting | Per-IP limits on single and bulk endpoints |
| 🌍 Multilingual UI | 7 languages in the web interface |
| 📄 CSV export | Download bulk results from the web UI |
| 🎯 Registration status | registered, available, unknown, or error per domain |
| 📚 Built-in API docs | Interactive reference at /docs |
| 🔓 MIT licensed | Free for personal and commercial use |
| Tool | Version |
|---|---|
| PHP | 8.3 or higher |
| Composer | 2.x |
| Node.js | 20+ (for frontend build) |
| SQLite | Included (default) or MySQL/PostgreSQL |
git clone https://github.com/your-org/whois-api.git
cd whois-api
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate
npm install
npm run buildOption A — Full stack (recommended for first run)
# Terminal 1
php artisan serve
# Terminal 2
npm run dev| Page | URL |
|---|---|
| Home (lookup UI) | / |
| API documentation | /docs |
Option B — API only
php artisan serveThe API works without building the frontend. Endpoints are available under /api/v1/whois/*.
Option C — One command (dev)
composer devRuns the PHP server, queue worker, logs, and Vite dev server together.
The UI includes two tabs:
- Domain Whois — single domain lookup with summary/full format
- Bulk Whois — paste up to 50 domains (one per line or comma-separated), view accordion results, export CSV
Supported interface languages:
| Code | Language |
|---|---|
en |
English (default) |
tr |
Türkçe |
es |
Español |
fr |
Français |
pt |
Português |
zh |
中文 |
ar |
العربية |
Base URL: http://localhost:8000/api/v1/whois
| Method | Endpoint | Rate limit | Description |
|---|---|---|---|
GET |
/whois/{domain} |
60/min per IP | Single domain lookup |
POST |
/whois/bulk |
10/min per IP | Bulk domain lookup |
| Parameter | Location | Values | Default |
|---|---|---|---|
format |
query or JSON body | summary, full |
summary |
domains |
JSON body (bulk only) | array of strings, max 50 | — |
summary — essential fields:
domain, registration_status, registrar, created_at, expires_at, states
full — all parsed fields plus raw WHOIS text:
whois_server, owner, updated_at, name_servers, dnssec, raw, …
curl -s "http://localhost:8000/api/v1/whois/google.com?format=summary" | jq{
"data": {
"domain": "google.com",
"registration_status": "registered",
"registrar": "MarkMonitor Inc.",
"created_at": "1997-09-15T04:00:00+00:00",
"expires_at": "2028-09-14T04:00:00+00:00",
"states": ["client delete prohibited", "client transfer prohibited"]
}
}curl -s -X POST "http://localhost:8000/api/v1/whois/bulk" \
-H "Content-Type: application/json" \
-d '{
"domains": ["google.com", "this-domain-is-free-xyz123.com"],
"format": "summary"
}' | jq{
"format": "summary",
"results": [
{
"domain": "google.com",
"status": "registered",
"data": { "domain": "google.com", "registration_status": "registered", "...": "..." }
},
{
"domain": "this-domain-is-free-xyz123.com",
"status": "available",
"data": { "domain": "this-domain-is-free-xyz123.com", "registration_status": "available", "...": "..." }
}
]
}| Status | Meaning |
|---|---|
registered |
Domain has active WHOIS registration data |
available |
Domain appears unregistered / available |
unknown |
WHOIS response could not be classified confidently |
error |
Lookup failed (invalid domain, timeout, server error) |
Errors return JSON with message and code:
| HTTP | Code | Typical cause |
|---|---|---|
422 |
invalid_domain |
Malformed domain name |
429 |
too_many_requests |
Rate limit exceeded |
502 |
lookup_failed |
WHOIS server unreachable or TLD unsupported |
500 |
server_error |
Unexpected server error |
All WHOIS-related settings live in .env and config/whois.php.
# Timeouts (seconds)
WHOIS_TIMEOUT=8
WHOIS_CONNECT_TIMEOUT=3
# Bulk
WHOIS_BULK_LIMIT=50
WHOIS_BULK_CONCURRENCY=5
WHOIS_BULK_MAX_EXECUTION=300
# Cache
WHOIS_CACHE_ENABLED=true
WHOIS_CACHE_TTL=3600
# Rate limits (requests per minute, per IP)
WHOIS_RATE_LIMIT=60
WHOIS_BULK_RATE_LIMIT=10
# Laravel cache driver — use redis in production for best performance
CACHE_STORE=database| Variable | Default | Description |
|---|---|---|
WHOIS_TIMEOUT |
8 |
Max seconds to read WHOIS server response |
WHOIS_CONNECT_TIMEOUT |
3 |
Max seconds to open TCP connection (port 43) |
WHOIS_BULK_CONCURRENCY |
5 |
Parallel lookups during bulk requests |
WHOIS_BULK_LIMIT |
50 |
Max domains per bulk request |
WHOIS_CACHE_TTL |
3600 |
Cache lifetime in seconds (1 hour) |
WHOIS_RATE_LIMIT |
60 |
Single lookup requests per minute per IP |
WHOIS_BULK_RATE_LIMIT |
10 |
Bulk requests per minute per IP |
Tip: For production, set
CACHE_STORE=redisand keepWHOIS_CACHE_ENABLED=true. Cached lookups typically respond in ~1 ms.
Custom WHOIS servers for specific TLDs can be added in config/whois.php under custom_servers.
WhoisScope uses a layered DDD structure:
flowchart TB
subgraph Presentation
UI[Vue 3 Web UI]
API[Laravel API Controllers]
end
subgraph Application
UC1[LookupWhoisUseCase]
UC2[BulkLookupWhoisUseCase]
end
subgraph Domain
ENT[WhoisRecord]
VO[Value Objects]
REPO_IF[WhoisRepositoryInterface]
end
subgraph Infrastructure
CACHE[CachedWhoisRepository]
PHP[PhpWhoisRepository]
LIB[io-developer/php-whois]
end
UI --> API
API --> UC1 & UC2
UC1 & UC2 --> REPO_IF
REPO_IF --> CACHE
CACHE --> PHP
PHP --> LIB
PHP --> ENT
app/
├── Domain/Whois/ # Entities, value objects, domain services, exceptions
├── Application/Whois/ # Use cases, DTOs, application services
├── Infrastructure/Whois/ # php-whois adapter, cache decorator, socket loader
├── Http/ # Controllers, form requests, API resources
└── Providers/ # DI bindings, rate limiters
resources/js/ # Vue 3 SPA (router, i18n, components)
routes/
├── api.php # /api/v1/whois/*
└── web.php # SPA catch-all
sequenceDiagram
participant Client
participant API as WhoisController
participant UC as LookupWhoisUseCase
participant Cache as CachedWhoisRepository
participant WHOIS as PhpWhoisRepository
participant Server as WHOIS Server :43
Client->>API: GET /api/v1/whois/example.com
API->>UC: execute(domain)
UC->>Cache: lookup(domain)
alt cache hit
Cache-->>UC: WhoisRecord
else cache miss
Cache->>WHOIS: lookup(domain)
WHOIS->>Server: TCP WHOIS query
Server-->>WHOIS: raw text
WHOIS-->>Cache: WhoisRecord
Cache-->>UC: WhoisRecord
end
UC-->>API: WhoisRecord
API-->>Client: JSON response
php artisan testThe test suite covers API responses, caching, rate limiting, and registration status detection.
| Layer | Technology |
|---|---|
| Backend | Laravel 13, PHP 8.3+ |
| WHOIS library | io-developer/php-whois |
| Frontend | Vue 3, Vue Router, Tailwind CSS 4, Vite 8 |
| Cache | Laravel Cache (database, file, or Redis) |
| Database | SQLite by default |
Contributions are welcome. Please open an issue or pull request. By contributing, you agree that your code will be released under the MIT License.
WhoisScope is open source software licensed under the MIT License.
You may use, copy, modify, merge, publish, distribute, sublicense, and sell copies of the software — for personal or commercial projects — as long as the license notice is included.