Holehe Module Output Structure: The Complete Developer Guide
Each Holehe module must append a standardized 9-field dictionary to the shared out list, containing metadata and account discovery results that the core engine consumes for formatted console output and CSV export.
Writing effective OSINT modules for the megadose/holehe repository requires understanding exactly how the framework expects results to be structured. The holehe/core.py file processes these outputs to generate color-coded terminal reports, making strict adherence to the schema essential for interoperability.
Required Output Schema for Holehe Modules
Every module function receives three parameters: email, client, and out. The out parameter is a list that collects result dictionaries from all executed modules. According to the source code in holehe/core.py, each dictionary must contain exactly these keys:
| Key | Type | Purpose |
|---|---|---|
name |
str |
Module identifier (typically the function name) |
domain |
str |
Target service's primary domain |
method |
str |
HTTP strategy used: "login", "register", or similar |
frequent_rate_limit |
bool |
Service reputation flag for aggressive throttling |
rateLimit |
bool |
Whether this specific request hit rate limiting |
exists |
bool or None |
Account existence: True=found, False=not found, None=uncertain |
emailrecovery |
str or None |
Recovered email from password-reset flows |
phoneNumber |
str or None |
Recovered phone number from account recovery |
others |
dict or None |
Arbitrary additional metadata the module wishes to expose |
The core processing logic expects this schema at lines 6–49 of holehe/core.py, where it iterates over out to determine which symbol to display: [+] for confirmed accounts, [-] for confirmed absences, [x] for rate limits, and [!] for ambiguous results.
Minimal Module Skeleton
This template demonstrates the required structure with placeholder values:
# holehe/modules/custom/example.py
from holehe.core import *
from holehe.localuseragent import *
async def example(email, client, out):
name = "example"
domain = "example.com"
method = "login"
frequent_rate_limit = False
# Perform async HTTP requests with `client`
# Determine results based on response analysis
out.append({
"name": name,
"domain": domain,
"method": method,
"frequent_rate_limit": frequent_rate_limit,
"rateLimit": False,
"exists": True, # Set based on response
"emailrecovery": None,
"phoneNumber": None,
"others": None,
})
Production Implementation: GitHub Module
The github module in holehe/modules/programing/github.py illustrates the schema in action:
async def github(email, client, out):
name = "github"
domain = "github.com"
method = "register"
frequent_rate_limit = False
freq = await client.get("https://github.com/join")
token = re.findall(
r'<auto-check src="/signup_check/username[\s\S]*?value="([\S]+)"'
r'[\s\S]*<auto-check src="/signup_check/email[\s\S]*?value="([\S]+)"',
freq.text,
)
data = {"value": email, "authenticity_token": token[0]}
req = await client.post("https://github.com/signup_check/email", data=data)
if req.status_code == 422:
exists = True
elif req.status_code == 200:
exists = False
else:
exists = None
out.append({
"name": name,
"domain": domain,
"method": method,
"frequent_rate_limit": frequent_rate_limit,
"rateLimit": False,
"exists": exists,
"emailrecovery": None,
"phoneNumber": None,
"others": None,
})
This module uses the register endpoint as an existence oracle: HTTP 422 indicates the email is already registered, while 200 means it's available for new account creation.
Using the others Field for Extended Data
The others key accepts any dictionary, enabling modules to surface additional account metadata beyond the core schema. While many modules set others: None, the field supports flexible extension:
others = {
"fullName": "Jane Smith",
"accountCreated": "2019-03-15",
"profileUrl": "https://example.com/user/janesmith"
}
When populated, this data appears in JSON exports and can be processed by downstream tooling that consumes Holehe's structured output.
Core Engine Processing
The holehe/core.py file implements the consumer side of this contract. Key processing behaviors include:
- Symbol selection: Based on
existsandrateLimitvalues - Color coding: Green for found, red for not found, yellow for rate limits, white for uncertain
- CSV serialization: Flattening the
othersdictionary when present - Rate limit aggregation: Tracking
frequent_rate_limitfor user warnings
Modules that deviate from the schema will cause KeyError exceptions during result formatting, terminating the scan prematurely.
Summary
- Nine required keys form the standardized Holehe module output structure
- Append to
out—never return values directly from module functions - Use
exists=Nonewhen response ambiguity prevents definitive determination - Leverage
othersfor extended metadata without breaking core compatibility - Reference
holehe/core.pyfor validation of your module's output handling
Frequently Asked Questions
What happens if I omit a required key from the output dictionary?
The core engine will raise a KeyError when attempting to format results, causing the entire scan to crash. Always include all nine keys, using None or False as appropriate for empty values.
Can I add custom keys beyond the nine specified fields?
No—the core processing logic expects exactly this schema. Use the others dictionary to encapsulate any additional data your module discovers.
How do I indicate that a service is blocking requests?
Set rateLimit=True when the response indicates CAPTCHA challenges, IP blocking, or explicit rate limiting. Set frequent_rate_limit=True in the module metadata if the service is known for aggressive throttling behavior.
Where are real-world module examples located?
Study the implementations in holehe/modules/programing/github.py and holehe/modules/productivity/evernote.py for production patterns. The holehe/modules/__init__.py file handles dynamic module discovery for the framework.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →