Photon: Incredibly fast crawler designed for OSINT.
π§ Overview

Photon is a fast OSINT-focused web crawler written in Python by s0md3v. Point it at a domain and, in a single crawl, it harvests a remarkable amount of intel: in-scope and out-of-scope URLs, parameterized (fuzzable) URLs, emails, social accounts, AWS buckets, files (PDF/XML/β¦), JavaScript files, secret keys, subdomains, and DNS data.
Unlike a pure link crawler, Photon is built to extract intelligence while it walks the site. It organizes findings into neat text files on disk (internal.txt, fuzzable.txt, keys.txt, β¦), can export to JSON/CSV, and even clones sites locally. For a tester, that means one command produces both an attack-surface map and a ready-to-fuzz parameter list.
| π OffSec Tip
Photonβs superpower is that it sorts what it finds. Instead of one giant URL dump, you get fuzzable.txt (params), scripts.txt (JS), keys.txt (secrets), and intel.txt (emails/social) β already split for you.
Repo: github.com/s0md3v/Photon
π¦ Installation
Photon is a Python 3 script. The canonical install is a git clone:
1 | |
Docker:
1 | |
| π OffSec Tip
Run it from inside the cloned folder as python photon.py. Depending on your setup you may need python3 photon.py.
π Basic Usage
The only required flag is -u (the target URL):
1 | |
Photon crawls the target and drops a folder named after the domain (e.g. example.com/) containing all the result files.
π© All CLI Flags
π·οΈ Core crawl
| Flag | Default | Description |
|---|---|---|
-u, --url |
Root URL to crawl (required) | |
-l, --level |
2 |
Levels (depth) to crawl |
-t, --threads |
2 |
Number of threads |
-d, --delay |
0 |
Delay between requests (seconds) |
--timeout |
5 |
HTTP request timeout (seconds) |
π Authentication & requests
| Flag | Description |
|---|---|
-c, --cookie |
Cookie header for authenticated sections |
--user-agent |
Custom user-agent(s), comma-separated |
--headers |
Supply custom HTTP headers |
π± Scope & seeds
| Flag | Description |
|---|---|
-s, --seeds |
Additional seed URLs, comma-separated |
--exclude |
Exclude URLs matching this regex |
--wayback |
Use archive.org URLs (from the current year) as seeds |
--only-urls |
Only extract URLs β skip intel & JS extraction |
βοΈ Data extraction
| Flag | Description |
|---|---|
-r, --regex |
Extract strings matching a custom regex during the crawl |
--keys |
Extract secret keys (high-entropy strings, API keys, hashes) |
--dns |
Enumerate subdomains & DNS data (with a visualization) |
--clone |
Clone the crawled pages locally for offline use |
π€ Output
| Flag | Default | Description |
|---|---|---|
-o, --output |
domain name | Output directory |
-e, --export |
Export formatted results (json or csv) |
|
--stdout |
Print one variable to stdout (see list below) | |
-v, --verbose |
Verbose output β print pages/keys/files as found |
π§° Misc
| Flag | Description |
|---|---|
--ninja |
Ninja mode β route some requests through third-party services |
--update |
Check for and install updates |
π Every Flag Explained (the ones that matter)
π -l, --level β crawl depth
Depth 2 (default) crawls the homepage and its seeds, then the results of those. Bump it for deeper coverage; each level multiplies the work.
1 | |
β‘ -t, --threads + -d, --delay β speed vs. stealth
More threads = faster, but noisier and more likely to trip rate limits. Add a delay to slow down.
1 | |
π --keys β the money flag
Turns on secret/high-entropy extraction, writing hits to keys.txt. Cheap to add, frequently pays off.
1 | |
π§© -r, --regex β grab anything you want
Extract custom patterns while crawling β internal IDs, phone numbers, API paths, whatever:
1 | |
π°οΈ --wayback β free historical seeds
Seeds the crawl with archive.org URLs for the current year, so you also touch old/forgotten paths:
1 | |
π« --exclude β stay in scope
Regex out logout links, media, or out-of-scope sections:
1 | |
π --dns β subdomains + graph
Enumerates subdomains and DNS data, saving subdomains.txt and a DNS visualization:
1 | |
π --only-urls β fast link map
Skip all intel/JS extraction when you just want the URL surface quickly:
1 | |
ποΈ Output Files Explained
Photon writes a folder (named after the domain, or your -o) containing:
| File | Contents |
|---|---|
internal.txt |
In-scope URLs (same domain) |
external.txt |
Out-of-scope / third-party URLs |
fuzzable.txt |
URLs that contain parameters β your fuzzing target list |
endpoints.txt |
Endpoints discovered in JavaScript |
scripts.txt |
JavaScript file URLs |
intel.txt |
Emails, social media handles, other OSINT |
robots.txt |
Paths pulled from the siteβs robots.txt |
custom.txt |
Matches from your --regex pattern |
keys.txt |
Secret keys (only with --keys) |
subdomains.txt |
Subdomains (only with --dns) |
failed.txt |
URLs that failed to fetch |
| π OffSec Tipfuzzable.txt is the file you want most often β itβs a pre-filtered list of parameterized URLs, ready to hand to ffuf, qsreplace, or your injection tooling.
π§ͺ Practical Examples
Authenticated crawl:
1 | |
Add extra starting points:
1 | |
Custom user-agents:
1 | |
Deeper, threaded crawl with a timeout tweak:
1 | |
π§ Advanced Examples
π°οΈ Full intel sweep
Depth 3, keys on, wayback seeds, DNS enumeration, verbose:
1 | |
π₯ Export for tooling
Dump results as JSON so you can jq them:
1 | |
𧬠Clone for offline analysis
Save every crawled page locally (useful for source review without re-hitting the target):
1 | |
β‘οΈ Pipe a single result set out live
--stdout prints exactly one variable to stdout so you can chain it. Supported values:files, intel, robots, custom, failed, internal, scripts, external, fuzzable, endpoints, keys.
1 | |
π― Real Pentest Workflow
From a single domain to a fuzzed, JS-mined attack surface:
1 | |
| π OffSec Tip
Photon and jsluice pair beautifully: Photon finds the JS files (scripts.txt), jsluice dissects them (endpoints, secrets, params). Run them back to back.
π€ Automation Examples
Reusable function:
1 | |
Loop over a scope file:
1 | |
π§Ύ JSON / Output Explanation
Photonβs default output is a set of plain-text files (see the table above) β not JSON. Thatβs deliberate: each file is already a clean, deduplicated, single-purpose wordlist you can pipe directly (cat fuzzable.txt | ...).
When you do want structured data, add --export json (or --export csv) and Photon writes a formatted export you can parse with jq. Use --stdout <variable> when you want a single category streamed live into another tool without touching disk.
π§ jq Filtering Examples
After --export json:
1 | |
| π OffSec Tip
Export key names depend on the Photon version. Run jq 'keys' on the export first to see exactly whatβs available before scripting.
π‘ Combine with httpx
Photon finds URLs; httpx tells you which ones live and what they return:
1 | |
π°οΈ Combine with gau
Feed Photonβs crawl straight into historical URL mining for extra coverage (Photon also has --wayback built in, but gau casts a wider net):
1 | |
π Combine with subjs
Widen JavaScript discovery beyond what Photonβs crawl reached:
1 | |
π§ Combine with jsluice (the natural pair)
Let Photon collect scripts, let jsluice extract from them:
1 | |
π₯ Combine with ffuf
fuzzable.txt is basically a ready-made target list:
1 | |
β‘ One-liners
1 | |
β οΈ Common Mistakes
- Forgetting
--keys. Secret extraction is off by default. If you skip it,keys.txtnever gets written. - Cranking
-ttoo high. Photon defaults to 2 threads for a reason β pushing to 50 on a fragile target gets you blocked or drops results intofailed.txt. - Expecting JSON by default. Base output is
.txtfiles. Add--export jsonif you need structured data. - Ignoring
fuzzable.txt. People re-derive a parameter list with other tools when Photon already handed them one. - No
--excludeon big sites. Without scope control the crawler wanders into logout links and infinite calendars. - Wrong Python. Photon is Python 3; running it under a stale Python 2 environment will error out.
π‘ Pro Tips & Performance
- Start shallow, then go deep. Run
-l 2 --only-urlsfirst for a quick map, then a full-l 3 --keys --dnspass on the interesting hosts. --waybackfor free coverage. It costs almost nothing and often surfaces retired endpoints the live site no longer links to.- Tune threads to the target.
-t 10on a robust CDN-backed site; keep it low (-t 2 -d 1) on something fragile or WAFβd. - Use
--stdoutto avoid disk churn in pipelines β stream one category straight into the next tool. - Chain into jsluice every time.
scripts.txtβ jsluice is the highest-value follow-up Photon enables. - Keep the output folder per target with
-oso parallel scans donβt clobber each otherβs files.
π Conclusion
Photon is the OSINT crawler that does your sorting for you. One command turns a domain into a labeled set of files β in-scope URLs, fuzzable parameters, JavaScript, secrets, subdomains, and intel β each already deduplicated and ready to pipe. That structure is what makes it such a good first recon step: everything downstream (httpx for liveness, ffuf for fuzzing fuzzable.txt, jsluice for dissecting scripts.txt) has a clean input waiting for it.
Remember the flags that matter β --keys for secrets, --wayback for historical reach, --dns for subdomains, -l/-t/-d to balance depth against stealth β and let the output files drive the rest of your workflow. Pair it with jsluice and youβve got a JavaScript-to-endpoints pipeline thatβs hard to beat.
| π OffSec Tip
The fastest way to level up your recon: run Photon first, then feed its scripts.txt to jsluice and its fuzzable.txt to ffuf. Three tools, one clean chain.