Quick start → · Usage → · Collectors → · Live demo →
GeoIntel is an open-source OSINT workspace that consolidates 14 infrastructure intelligence modules behind a single interface. Enter an IP address, domain name, or URL and get back geolocation, DNS records, WHOIS registration, SSL certificate details, HTTP security headers, RDAP metadata, subdomain discoveries, email security posture, port scans, and more.
Three surfaces, one engine:
- Dashboard — React SPA with interactive map, per-module result views, and optional OpenCage enrichment
- CLI —
geointelcommand with subcommands, multiple output formats, and shell completion - JSON API — RESTful endpoints returning structured results for integration
⚠️ Authorization is non-negotiable. Port scanning, banner collection, connectivity checks, and DNS zone-transfer probes are active operations. Use this tool only on assets you own or have written permission to test.
- 🛰️ 14 intelligence modules — geolocation, DNS, WHOIS, SSL/TLS, HTTP headers, reverse DNS, RDAP, subdomains, email security, web intelligence, public file discovery, port scanning, connectivity checks, and zone-transfer auditing
- ⚡ Concurrent full scan — runs every module in parallel; one failure never discards the rest of the report
- 🌐 Interactive dashboard — Leaflet map, real-time results, OpenCage timezone/currency enrichment
- 🖥️ Feature-complete CLI —
geointel lookup/scan/fullscan/history/info/config/completion, multiple output formats (pretty, JSON, CSV, simple), OpenCage enrichment, shell completions, and config file - 🔗 RESTful JSON API — POST endpoints for single and full scans, designed for automation
- 🛡️ Safety-first — private/reserved addresses rejected for active modules; redirects revalidated; scans bounded to TCP 1–1024 plus select high-value ports
- 🔌 Zero API keys required — all passive collectors query public sources with no registration
flowchart TD
U[User] --> D{ }
D -- Dashboard --> R["<b>React SPA</b><br/><i>frontend/</i>"]
D -- CLI --> C["<b>geointel</b><br/><i>app/__main__.py</i>"]
D -- API --> F["<b>FastAPI server</b><br/><i>app/main.py</i>"]
R --> F
F --> S["<b>Scanner service</b><br/><i>app/services/scanner.py</i>"]
S --> M["<b>14 collector modules</b>"]
M --> P["<b>Public sources</b><br/>ip-api.com · crt.sh · rdap.org · DNS"]
M --> T["<b>Target host</b>"]
style U fill:#1a1a2e,stroke:#4a4a6a,color:#e0e0e0,stroke-width:2px
style D fill:#2d2d44,stroke:#555577,color:#cccccc,stroke-width:1px
style R fill:#1e3a5f,stroke:#3a6a9e,color:#e0e0e0,stroke-width:2px
style C fill:#1e4d3a,stroke:#3a8a6a,color:#e0e0e0,stroke-width:2px
style F fill:#1e3a5f,stroke:#3a6a9e,color:#e0e0e0,stroke-width:2px
style S fill:#4a2a1e,stroke:#7a4a3a,color:#e0e0e0,stroke-width:2px
style M fill:#3a1e2e,stroke:#6a3a4e,color:#e0e0e0,stroke-width:2px
style P fill:#3a3a2e,stroke:#6a6a4e,color:#e0e0e0,stroke-width:2px
style T fill:#4a2a1e,stroke:#7a4a3a,color:#e0e0e0,stroke-width:2px
The FastAPI backend dispatches each collector in its own thread. Active modules (port scan, connectivity, zone transfer) are gated behind _require_public_host — private and loopback addresses are rejected before any socket opens. Passive modules make outbound HTTP or DNS queries to public intelligence sources. The dashboard and CLI share the same scanner code path.
| ID | Module | Target | Type | Operation |
|---|---|---|---|---|
quick |
GeoIP | IP or domain | Passive | ISP, organisation, ASN, continent → city coordinates |
dns |
DNS Analysis | IP or domain | Passive | A, AAAA, MX, NS, TXT, SOA, CNAME, PTR records |
whois |
WHOIS | Domain | Passive | Registrar, dates, status, name servers, contacts |
ssl |
SSL/TLS | Public domain | Passive | Certificate subject, issuer, validity, SANs |
http |
HTTP Headers | Public domain | Passive | Server info, security headers, status code |
reverse |
Reverse DNS | IP or domain | Passive | PTR records and hostname resolution |
rdap |
RDAP | IP or domain | Passive | Structured registration data |
subdomains |
Subdomains | Domain | Passive | Certificate transparency (crt.sh) discoveries |
email |
Email Security | Domain | Passive | MX, SPF, and DMARC posture |
web |
Web Intelligence | Public domain | Passive | Metadata, technology signatures, emails, social links |
files |
Public Files | Public domain | Passive | robots.txt, sitemap.xml, security.txt |
ports |
Port & Service Scan | Public IP or domain | Active | TCP 1–1024 + high-value ports, service banners |
connectivity |
Connectivity | Public IP or domain | Active | Reachability and latency for SSH, SMTP, DNS, HTTP(S) |
zone_transfer |
Zone Transfer | Domain | Active | AXFR exposure check against authoritative name servers |
The full meta-module runs all 14 concurrently via the CLI (geointel fullscan --target <target>) or API (/api/full-scan).
# 1. Install Python dependencies
python -m pip install -r requirements.txt
# 2. Install the geointel CLI
pip install -e .
# 3. Build the frontend (optional, CLI-only users can skip)
cd frontend && npm install && npm run build && cd ..
# 4. Start the server
uvicorn app.main:app --reload→ http://127.0.0.1:8000
pip install -r requirements.txt
pip install -e .
geointel lookup --target example.com --type dnsOpen http://127.0.0.1:8000, enter a target, and select collectors from the module list. Results appear in real time with an interactive map for GeoIP lookups.
# Quick GeoIP lookup
geointel lookup --target 8.8.8.8
# Specific scan type
geointel scan --target example.com --type dns
# Multi-type scan (runs concurrently)
geointel scan --target example.com --type dns,whois,ssl
# Full recon (all 14 collectors)
geointel fullscan --target example.com
# JSON output
geointel fullscan --target example.com --json
# CSV export
geointel lookup --target 8.8.8.8 -t quick --csv
# Flat key-value output
geointel lookup --target example.com -t rdap --simple
# Scan history
geointel history
# Show version and available modules
geointel info
# OpenCage enrichment
geointel lookup --target 8.8.8.8 --opencage-key YOUR_KEY
# Skip logo for scripting
geointel lookup --target 8.8.8.8 --no-logo
# Persistent config (saves to ~/.geointel/config.json)
geointel config --set opencage_key=YOUR_KEY
# View current config
geointel config --show
# Generate shell completions
geointel completion bash > /etc/bash_completion.d/geointel# List modules
curl http://127.0.0.1:8000/api/scan-types
# Quick GeoIP lookup
curl -X POST http://127.0.0.1:8000/api/lookup \
-H 'Content-Type: application/json' \
-d '{"target":"8.8.8.8"}'
# Single module
curl -X POST http://127.0.0.1:8000/api/scan \
-H 'Content-Type: application/json' \
-d '{"target":"example.com","scan_type":"dns"}'
# Full scan (all 14 collectors)
curl -X POST http://127.0.0.1:8000/api/full-scan \
-H 'Content-Type: application/json' \
-d '{"target":"example.com"}'
# Geocoding enrichment (OpenCage)
curl -X POST http://127.0.0.1:8000/api/geocode \
-H 'Content-Type: application/json' \
-d '{"lat":39.03,"lon":-77.5,"api_key":"YOUR_KEY"}'Full scans return {"results":{…}, "errors":{…}} — one module failure never discards the rest. The geocode endpoint adds timezone, currency, and formatted address to GeoIP results.
| Method | Frontend | Backend | Active modules | Effort |
|---|---|---|---|---|
| Vercel (recommended) | Static (frontend/dist/) |
Python serverless | ❌ | One click |
| Local / VPS | FastAPI-served | uvicorn |
✅ | pip install + build |
Active modules (port scan, connectivity, zone transfer) use raw sockets and do not work in Vercel's serverless sandbox. Run them locally or on a VPS.
The repository includes vercel.json — importing it into Vercel automatically configures the build pipeline, route rewrites, and Python serverless function.
python -m pip install -r requirements.txt
cd frontend && npm install && npm run build && cd ..
uvicorn app.main:app --host 0.0.0.0 --port 8000→ http://localhost:8000
GeoIntel runs with zero configuration. Settings are resolved in this order: CLI flag → environment variable → config file.
| Method | Example | Precedence |
|---|---|---|
| CLI flag | --opencage-key YOUR_KEY |
1st |
| Environment | OPENCAGE_API_KEY=YOUR_KEY |
2nd |
| Config file | geointel config --set opencage_key=YOUR_KEY |
3rd |
The config file lives at ~/.geointel/config.json and is managed via geointel config:
geointel config --show # view current config
geointel config --set key=value # set a value
geointel config --unset key # remove a value
geointel config --reset # delete config fileThe OpenCage key is proxied through the backend (POST /api/geocode) and held in browser memory — never persisted on disk or sent directly from the browser.
| Layer | Choice |
|---|---|
| Backend framework | FastAPI |
| Frontend framework | React 19 + Vite 8 |
| Language | Python 3.12 + TypeScript 6 |
| Styling | Tailwind CSS 4 |
| Maps | Leaflet |
| CLI runtime | geointel (via pip install -e .) |
| Deployment | Vercel (Python + static) · uvicorn (local) |
| CI / CD | GitHub Actions · CodeQL · Dependabot |
- Python 3.10+ (3.12 recommended for Vercel)
- Node.js 20+ and npm (for frontend builds)
- Zero external API keys
- Requires
pip install -e .to make thegeointelCLI command available
# Backend smoke tests (no framework required)
python -c "
from test_scanner import *
test_normalize_target()
test_page_parser()
test_full_scan_keeps_partial_results()
test_private_web_targets_are_rejected()
test_port_probe_formats_json_result()
"
# Frontend checks
cd frontend
npm run lint # ESLint
npm test # TypeScript type-check + Vite production buildCI automatically runs both suites on every push and pull request to main.
| Symptom | Cause | Fix |
|---|---|---|
| Dashboard shows blank page or 404 | Frontend not built | cd frontend && npm install && npm run build |
| Collector returns error | Target unsuitable or upstream source unreachable | Use a domain for WHOIS/subdomains/email; verify network access to external APIs |
| Port 8000 in use | Another process on that port | uvicorn app.main:app --port 8080 |
| Active modules fail on Vercel | Serverless sandbox restricts raw sockets | Run locally or on a VPS for port scanning and connectivity checks |
| API returns 500 | Python dependency not installed | python -m pip install -r requirements.txt |
- ✅ Authorization required — only scan systems you own or have permission to test
- ✅ Private-address rejection — loopback, RFC 1918, and reserved addresses are blocked for active modules
- ✅ Redirect revalidation — HTTP redirects are verified before following
- ✅ Bounded scanning — port scan covers TCP 1–1024 plus select high-value ports with short timeouts
- ❌ No exploitation — does not brute-force, fuzz, or bypass access controls
- ❌ No data persistence — results returned in the response only, never stored server-side
GitHub · Issue tracker · Security · Live demo

