Holehe JSON Output Format: Standardized Schema and Field Reference
Holehe returns email-check results as a list of flat Python dictionaries that serialize directly to JSON, with each entry containing standardized fields like exists, rateLimit, emailrecovery, and others.
Holehe is an open-source OSINT tool by @megadose that checks whether an email address is registered across hundreds of websites. Understanding the Holehe JSON output format is essential for building automated workflows, because the tool's programmatic value lies in this consistent, machine-readable schema. The format is defined implicitly in holehe/core.py and implemented by every module in holehe/modules/.
Core Structure: A List of Uniform Dictionaries
Holehe aggregates results into a single Python list variable named out. Each element is a dictionary representing one site check. Because the structure uses only built-in types—strings, booleans, None, and nested dicts—it requires no custom encoders.
from holehe.core import launch_module
# Inside the execution loop, each module appends to `out`:
out = [] # Collects all results
await launch_module(site, email, client, out)
# `out` is now JSON-serializable
The list structure enables parallel processing and simple downstream parsing with standard JSON libraries.
Standard Fields in Every Holehe JSON Entry
Every dictionary follows the same schema, whether produced by twitter.py, blablacar.py, or any other module. Fields are populated according to the site's response and the module's capabilities.
| Field | Type | Purpose |
|---|---|---|
name |
str |
Internal module identifier (e.g., "blablacar"). |
domain |
str |
Public domain queried (e.g., "blablacar.com"). |
method |
str | absent |
HTTP method used: "register", "login", etc. |
frequent_rate_limit |
bool | absent |
Whether the service commonly returns rate limits. |
rateLimit |
bool |
True if the request was blocked temporarily. |
error |
bool |
True if the module raised an unexpected exception. |
exists |
bool |
True if the email is registered on this service. |
emailrecovery |
str | None |
Password-recovery hint (masked email) if exposed. |
phoneNumber |
str | None |
Recovered phone number if exposed. |
others |
dict | None |
Additional metadata (name, dates, raw responses). |
The name and domain fields are guaranteed. Optional fields appear only when modules explicitly set them.
How Fields Are Populated: Source Code Analysis
Automatic Fields from Core Logic
In holehe/core.py, the launch_module function provides fallback handling when a module crashes. This fallback constructs a minimal valid entry:
# holehe/core.py lines 71-73 (simplified)
name = str(module).split('<function ')[1].split(' ')[0]
data[name] = {"exists": False, ...} # domain derived similarly
out.append({"name": name, "domain": data[name], ...})
The fallback also sets error: True when an exception occurs, ensuring the output remains schema-compliant even during failures.
Module-Generated Fields
Individual modules populate the remaining fields based on HTTP responses. Consider blablacar.py:
# holehe/modules/transport/blablacar.py lines 5-9
def blablacar(email, client, out):
# Module metadata
method = "register"
frequent_rate_limit = True
# ... request logic ...
On success (lines 68-74), it returns:
{
"exists": True, # Email found on service
"rateLimit": False, # No throttling occurred
"emailrecovery": None, # No recovery hint extracted
"phoneNumber": None,
"others": None
}
The others field captures unstructured data. For example, if a module extracts a user's full name or account creation date, it places these in others rather than polluting the top-level schema.
Working with Holehe JSON Output
Command-Line JSON Export
Holehe's table output is human-readable but not machine-friendly. Capture raw JSON using Python's eval-to-JSON pattern:
# Basic CLI usage (colored table)
holehe test@example.com
# Extract valid JSON
holehe test@example.com --no-color --no-clear | \
python -c "import sys, json; print(json.dumps(eval(sys.stdin.read())))"
Library Usage for Programmatic Access
For production automation, import Holehe directly:
import json
import asyncio
import httpx
from holehe.core import import_submodules, get_functions, launch_module
async def check_email(email: str) -> str:
"""Return Holehe results as a JSON string."""
modules = import_submodules("holehe.modules")
sites = get_functions(modules)
out = []
async with httpx.AsyncClient() as client:
for site in sites:
await launch_module(site, email, client, out)
return json.dumps(out, indent=2)
# Execute
result = asyncio.run(check_email("target@example.com"))
print(result)
Sample output:
[
{
"name": "blablacar",
"domain": "blablacar.com",
"method": "register",
"frequent_rate_limit": true,
"rateLimit": false,
"error": false,
"exists": true,
"emailrecovery": null,
"phoneNumber": null,
"others": null
}
]
Field-by-Field Reference for Automation
exists vs. rateLimit vs. error
These three booleans encode distinct failure modes:
exists: True— Confirmed registration. The email has an account.rateLimit: True— Cannot determine; the service blocked the request. Retry later.error: True— Module crashed. The result is unreliable; check logs.
A result with exists: False and rateLimit: True is inconclusive, not negative.
emailrecovery and phoneNumber Pattern Matching
When services expose password-recovery hints, modules attempt extraction:
# Typical extraction pattern in modules
"emailrecovery": response.text.split('maskedEmail":"')[1].split('"')[0],
These fields often contain partially redacted values like t***@example.com. Parse defensively—services change their masking formats without warning.
Extending with others
The others field preserves forward compatibility. When Holehe adds new extractors, they place data here rather than breaking existing parsers. Structure varies by module:
"others": {
"full_name": "John Doe",
"created_at": "2019-03-15",
"raw_error": "Invalid captcha" # Even errors may appear here
}
Key Files Defining the Output Format
| Path | Responsibility |
|---|---|
holehe/core.py |
Orchestration, fallback entry construction, error handling. Contains launch_module and the schema fallback. |
holehe/modules/**/*.py |
Site-specific logic. Every module must return a dictionary matching the core schema. |
holehe/instruments.py |
Progress instrumentation (does not affect output format). |
Summary
- Holehe produces a list of flat dictionaries that serialize directly to JSON without custom encoders.
- Ten standardized fields cover identification (
name,domain), status (exists,rateLimit,error), and extracted intelligence (emailrecovery,phoneNumber,others). - The core fallback in
launch_moduleensures schema compliance even when modules crash. othersprovides an extension point for unstructured data without breaking backward compatibility.- For automation, import
launch_moduledirectly rather than parsing CLI output.
Frequently Asked Questions
How do I know if an email is definitely not registered?
You cannot be certain when rateLimit: True. Only exists: False with rateLimit: False indicates absence. Rate-limited responses require retry.
Why is emailrecovery often null?
Most services mask recovery hints or require additional authentication steps. Modules populate this field only when the unauthenticated response exposes recoverable data.
Can I add custom fields to the output?
Yes, through the others dictionary in your own module. Do not add top-level fields—this breaks compatibility with standard Holehe parsers.
What version of Holehe uses this exact schema?
The schema described reflects the current master branch as implemented in megadose/holehe. Specific field availability (method, frequent_rate_limit) depends on whether individual modules choose to populate them.
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 →