How to Integrate Holehe into Your Own Python Application: A Complete Guide
You can integrate Holehe into your Python application by importing the orchestration functions from holehe.core, dynamically loading service modules with import_submodules and get_functions, and executing email checks concurrently using trio with a shared httpx.AsyncClient.
Holehe is an open-source OSINT tool by megadose that checks whether an email address exists across hundreds of online services. While the command-line interface is useful for standalone investigations, embedding Holehe directly into your Python codebase allows you to automate reconnaissance workflows, build web interfaces, or integrate results into larger data pipelines. This guide demonstrates how to integrate Holehe into your own Python application using its public API.
Core Architecture and Module Discovery
Three functions in holehe/core.py form the integration foundation:
import_submodules("holehe.modules"): Dynamically discovers every service module under theholehe/modulespackage without hard-coding service names.get_functions(modules, args): Extracts async check functions from the loaded modules, optionally filtering by CLI-style arguments.launch_module: Executes individual service checks with built-in rate-limit detection and user-agent rotation fromholehe/localuseragent.py.
The library uses trio for structured concurrency, spawning each service check as a separate task within an open_nursery() context. Each check receives the target email, an httpx.AsyncClient instance, and a shared results list populated with standardized dictionaries.
Basic Integration Pattern
This minimal example demonstrates the essential workflow to check a single email address programmatically:
import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module
async def check_email(email: str, timeout: int = 10):
# 1. Dynamically load all service modules
modules = import_submodules("holehe.modules")
services = get_functions(modules)
# 2. Create shared HTTP client with configured timeout
client = httpx.AsyncClient(timeout=timeout)
results = []
# 3. Execute all checks concurrently via trio
async with trio.open_nursery() as nursery:
for svc in services:
nursery.start_soon(launch_module, svc, email, client, results)
await client.aclose()
return results
# Run the check
if __name__ == "__main__":
found = trio.run(lambda: check_email("example@example.com"))
for entry in found:
print(entry)
This approach automatically picks up any new modules added to holehe/modules without code changes, leveraging Holehe's dynamic discovery system.
Advanced Integration Examples
Creating a Reusable Scanner Class
For applications requiring multiple scans, wrap the logic in a class that initializes modules once to avoid repeated import overhead:
import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module
class HoleheScanner:
def __init__(self, timeout: int = 10):
self.timeout = timeout
# Initialize once during instantiation
self.modules = import_submodules("holehe.modules")
self.services = get_functions(self.modules)
async def _run(self, email: str):
async with httpx.AsyncClient(timeout=self.timeout) as client:
out = []
async with trio.open_nursery() as nursery:
for svc in self.services:
nursery.start_soon(launch_module, svc, email, client, out)
return out
def scan(self, email: str):
"""Synchronous entry point for trio-based execution."""
return trio.run(lambda: self._run(email))
# Usage
scanner = HoleheScanner()
results = scanner.scan("user@example.com")
Integrating with FastAPI
Expose Holehe functionality via a REST API endpoint while maintaining the async execution model:
from fastapi import FastAPI, HTTPException
import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module
app = FastAPI()
# Load modules at startup
modules = import_submodules("holehe.modules")
services = get_functions(modules)
async def run_checks(email: str):
async with httpx.AsyncClient() as client:
out = []
async with trio.open_nursery() as nursery:
for svc in services:
nursery.start_soon(launch_module, svc, email, client, out)
return out
@app.get("/holehe/{email}")
async def holehe_check(email: str):
results = await run_checks(email)
if not results:
raise HTTPException(status_code=404, detail="No data returned")
return {"email": email, "checks": results}
Exporting Results to CSV
Process results programmatically without invoking the CLI formatter:
import csv
import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module
async def export_to_csv(email: str, path: str = "holehe_results.csv"):
modules = import_submodules("holehe.modules")
services = get_functions(modules)
async with httpx.AsyncClient() as client:
out = []
async with trio.open_nursery() as nursery:
for svc in services:
nursery.start_soon(launch_module, svc, email, client, out)
# Write standardized results to CSV
with open(path, "w", newline="", encoding="utf8") as f:
writer = csv.DictWriter(f, fieldnames=out[0].keys())
writer.writeheader()
writer.writerows(out)
return path
# Execute export
trio.run(lambda: export_to_csv("test@example.com"))
Customizing Execution Behavior
Timeout Configuration: Pass custom timeout values when initializing httpx.AsyncClient to accommodate slow services or restrictive network conditions.
Password Recovery Toggle: The CLI's --no-password-recovery flag maps to the nopasswordrecovery attribute in get_functions(). Mimic this by passing an argparse.Namespace:
import argparse
args = argparse.Namespace(nopasswordrecovery=True)
services = get_functions(modules, args)
Service Filtering: Since get_functions returns a list of callable objects, filter services before execution based on module names:
all_services = get_functions(modules)
social_services = [s for s in all_services if "social" in s.__module__]
Key Source Files for Integration
Understanding these files helps when debugging or extending functionality:
holehe/core.py: Containsimport_submodules,get_functions, andlaunch_moduleorchestration logic.holehe/modules/: Directory containing service-specific check implementations (e.g.,facebook.py,twitter.py).holehe/localuseragent.py: Supplies the user-agent rotation pool used automatically by the HTTP client.
Summary
- Import
import_submodules,get_functions, andlaunch_modulefromholehe.coreto access the public API without CLI overhead. - Use
import_submodules("holehe.modules")for dynamic discovery of available services at runtime. - Execute checks concurrently using
trio.open_nursery()with a sharedhttpx.AsyncClientto maximize throughput. - Results accumulate in a shared list containing standardized dictionaries with keys including
name,domain,exists, andemailrecovery. - Customize behavior by filtering service lists, adjusting HTTP timeouts, or passing
argparse.Namespaceobjects toget_functions(). - The architecture supports both
trioandasyncioevent loops since service functions rely only onhttpx.AsyncClient.
Frequently Asked Questions
Can I use Holehe with asyncio instead of trio?
Yes. While the reference implementation in holehe/core.py uses trio.run() and trio.open_nursery(), the underlying service functions only require httpx.AsyncClient. You can replace the trio nursery with asyncio.gather() or asyncio.create_task() loops while keeping the same import_submodules and get_functions workflow to integrate Holehe into asyncio-based applications.
How do I disable password recovery checks when integrating Holehe?
Pass an argparse.Namespace object with nopasswordrecovery=True to get_functions(). This mimics the CLI's --no-password-recovery flag and filters out services that specifically check for account recovery options, returning only existence checks.
What format does the results list use?
Each entry in the results list is a dictionary containing standard keys: name (service name), domain (service domain), exists (boolean indicating account existence), emailrecovery (recovery email if found), and other service-specific metadata. This matches the JSON structure output by the CLI, allowing you to reuse existing parsing logic.
Do I need to handle rate limiting when integrating Holehe?
No. The launch_module function in holehe/core.py already implements rate-limit detection and user-agent rotation using holehe/localuseragent.py. The HTTP client is shared across services, but each service module handles its own rate-limit response detection and backoff logic automatically.
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 →