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 the holehe/modules package 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 from holehe/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: Contains import_submodules, get_functions, and launch_module orchestration 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, and launch_module from holehe.core to 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 shared httpx.AsyncClient to maximize throughput.
  • Results accumulate in a shared list containing standardized dictionaries with keys including name, domain, exists, and emailrecovery.
  • Customize behavior by filtering service lists, adjusting HTTP timeouts, or passing argparse.Namespace objects to get_functions().
  • The architecture supports both trio and asyncio event loops since service functions rely only on httpx.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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →