Static recon of JS-heavy / geo-blocked single-page apps: extract pricing, plan IDs, API endpoints and embedded copy from the JavaScript bundles a site already serves to every visitor — no browser, no code execution, no auth bypass.
When a site is geo-blocked ("Not available in your region") or is a pure JS SPA that renders nothing without a browser, the interesting data usually still lives in its publicly served JS bundles. This tool automates what you would otherwise do by hand in DevTools' Sources tab: find the bundles, download them, grep for the good stuff, and produce a structured report.
| Category | Example hits |
|---|---|
| Plans / products | carpool_2p, carpool_4p, reclaude_1m, dedicated_12m |
| Prices | ¥1,100, $30.00/M, amount_cents: 110000, 输出: ¥1/M token |
| API endpoints | /api/admin/billing/catalog, /api/v1/plans |
| Models | gpt-5.6-terra, cc-gpt-5.6-sol, grok-4.5 |
| Keyword context | snippets around quota, invite, refund, carpool, ... |
No third-party dependencies — Python 3.8+ standard library only.
# Scan a site and print the human-readable summary
python3 recon.py https://example.com/pricing
# Save the full JSON report
python3 recon.py https://example.com/pricing --out report.json
# JSON to stdout (pipe to jq)
python3 recon.py https://example.com --out -Example output (summary mode):
$ python3 recon.py https://recode.cat/ --out report.json
target : https://recode.cat/
final url : https://www.recode.cat/
js bundles : 1
- https://recode.cat/assets/index-CpKEWhXC.js (3411131)
== plans (53) ==
org_id x54
subscription_expires_at x47
subscription_type x26
org_name x22
carpool_not_active x16
subscription_source x11
... (also catches plan IDs like carpool_2p, carpool_4p,
reclaude_1m / 3m / 6m / 12m deeper in the list)
== api_endpoints (192) ==
"/api/app/me" x7
"/api/admin/users" x5
"/api/auth/login" x3
...
== keyword hits (13 keywords) ==
[carpool]
...拼车 / 独享方案,自动续杯换号...
positional:
url target page URL
options:
--out PATH write JSON report (use '-' for stdout)
--no-summary skip the human-readable summary
--timeout SEC per-request timeout (default 25)
{
"target": "https://example.com/",
"final_url": "https://www.example.com/",
"js_bundles": [{"url": "...", "bytes": 3449892}],
"scan": {
"plans": [{"value": "carpool_2p", "count": 3}, ...],
"prices": [{"value": "¥1,100", "count": 1}, ...],
"api_endpoints": [{"value": "/api/v1/catalog", "count": 2}, ...],
"models": [{"value": "gpt-5.6-terra", "count": 6}, ...]
},
"keyword_snippets": {
"quota": ["...carpool 5-hour quota via the /api/v1 endpoints...", ...]
}
}- Fetch the HTML shell with a desktop User-Agent. Geo-blocks are usually implemented as a client-side check — the HTML and bundles are still served to anyone. If the page redirects, the final URL is recorded.
- Enumerate bundles by scanning
<script src>/<link href>for.jsassets. - Download each bundle — the exact same bytes any visitor's browser gets. The tool never executes them.
- Scan with the pattern groups in
recon.py(DEFAULT_PATTERNS) plus seed-keyword snippet capture (DEFAULT_KEYWORDS), and emit a JSON report.
- Only reads what is publicly served to anonymous visitors.
- Never bypasses login walls, auth, rate limits, or access controls — a login-gated API path is merely recorded as a string.
- Never executes third-party code; nothing runs on the target.
- Use only on sites you are permitted to analyze, in line with their ToS and your local law. This is a research/automation convenience, not a weapon.
MIT — see LICENSE.