# How to Integrate Holehe into Your Own Python Application: A Complete Guide

> Integrate Holehe into your Python app. Learn to import core functions, load services, and run concurrent email checks using trio and httpx. Get the complete guide.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: how-to-guide
- Published: 2026-08-26

---

**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`](https://github.com/megadose/holehe/blob/main/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`](https://github.com/megadose/holehe/blob/main/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:

```python
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:

```python
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:

```python
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:

```python
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`:

```python
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:

```python
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`](https://github.com/megadose/holehe/blob/main/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`](https://github.com/megadose/holehe/blob/main/facebook.py), [`twitter.py`](https://github.com/megadose/holehe/blob/main/twitter.py)).
- **[`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/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`](https://github.com/megadose/holehe/blob/main/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`](https://github.com/megadose/holehe/blob/main/holehe/core.py) already implements rate-limit detection and user-agent rotation using [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/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.