A Dockerized tech stack fingerprinting API built with FastAPI + httpx.
Give it a domain — it discovers all subdomains via Certificate Transparency logs, then fingerprints the tech stack of each live one concurrently.
# 1. Set your API key
export API_KEY=your-secret-key
# 2. Build & run
docker compose up --build
# 3. Analyze a domain and all its subdomains
curl -X POST http://localhost:8000/analyze \
-H "X-API-Key: your-secret-key" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com"}'Health check — no auth required.
Discover subdomains via crt.sh Certificate Transparency logs, then fingerprint the tech stack of every live subdomain (and the root domain) concurrently.
Headers: X-API-Key: <your-key>
Body:
{
"domain": "example.com",
"timeout": 10,
"max_subdomains": 50,
"concurrency": 10
}| Field | Default | Description |
|---|---|---|
domain |
required | Root domain to analyze (bare hostname, no scheme) |
timeout |
10 |
Per-request timeout in seconds (1–30) |
max_subdomains |
50 |
Cap on how many subdomains to probe (1–200) |
concurrency |
10 |
Max simultaneous requests (1–20) |
Response:
{
"domain": "example.com",
"subdomains_discovered": 18,
"targets_checked": 19,
"live": 12,
"elapsed_ms": 4823.1,
"results": [
{
"url": "https://example.com",
"status_code": 200,
"elapsed_ms": 312.4,
"technologies": {
"cdn": [{ "name": "Cloudflare", "category": "cdn", "confidence": 95, "version": null, "icon": "🌐" }],
"framework": [{ "name": "Next.js", "category": "framework", "confidence": 95, "version": null, "icon": "⚙️" }]
},
"summary": ["Cloudflare", "Next.js"]
},
{
"url": "https://shop.example.com",
"status_code": 200,
"elapsed_ms": 501.2,
"technologies": {
"platform": [{ "name": "Shopify", "category": "platform", "confidence": 95, "version": null, "icon": "🏪" }]
},
"summary": ["Shopify"]
}
],
"unreachable": [
{ "subdomain": "staging.example.com", "error": "Unreachable" }
]
}Each entry in results has the full tech stack breakdown grouped by category.
unreachable contains targets that failed both HTTPS and HTTP probes, with the failure reason.
Two sources run concurrently and their results are merged before probing:
- Certificate Transparency — crt.sh — queries the public crt.sh API for all SSL/TLS certificates ever issued to
*.domain, extracting every unique subdomain name fromname_valuefields. Wildcard entries (*.sub.domain) are collapsed to their bare hostname. - subfinder (ProjectDiscovery) — passive subdomain enumeration tool that queries dozens of public sources (DNS datasets, certificate logs, APIs) simultaneously. Bundled in the Docker image as a pre-built binary. Gracefully skipped if the binary is unavailable.
Then:
- Root domain is always prepended as the first target.
- Combined results are deduplicated, sorted, and capped at
max_subdomains. - Each target is probed: HTTPS first, falling back to HTTP before marking as unreachable.
- SSRF protection resolves each hostname and blocks requests to private/internal IP ranges before any connection is made.
| Category | Examples |
|---|---|
| Web server | Nginx, Apache, IIS, Gunicorn, Uvicorn, LiteSpeed |
| CDN | Cloudflare, AWS CloudFront, Fastly |
| Hosting | Vercel, AWS S3, AWS |
| Language | PHP, Java |
| Framework | Next.js, Nuxt.js, Express.js, Django, Laravel, Rails, ASP.NET |
| CMS | WordPress, Drupal, Joomla, Ghost |
| Platform | Shopify, Wix, Squarespace, Webflow, Framer |
| JS Library | React, Vue.js, Angular, Svelte, jQuery, Ember.js |
| CSS Framework | Bootstrap, Tailwind CSS |
| Analytics | Google Analytics, Segment, Hotjar |
| Support | Intercom, Crisp |
| Payment | Stripe |
| API | GraphQL |
| Monitoring | Sentry |
| Env Var | Default | Description |
|---|---|---|
API_KEY |
changeme |
Auth key for X-API-Key header — override in production |
RATE_LIMIT |
60/minute |
Unused by /analyze (kept for future raw-fetch routes) |
/analyzeis rate-limited to 10/minute per IP.
- API key auth on all routes except
/health - SSRF protection — resolves each discovered hostname and blocks private/loopback IPs before connecting
- Rate limiting per IP via slowapi
- Non-root container user
- Read-only filesystem
- Configurable timeout per request (max 30 s)
Visit http://localhost:8000/docs for the Swagger UI.