# How to Embed Holehe Functionality into Your Python Project: A Complete Integration Guide

> Embed Holehe into your Python project using httpx AsyncClient and asynchronous site modules for direct OSINT email verification. Integrate Holehe's powerful features today.

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

---

**You can embed Holehe into any Python project by importing its asynchronous site modules, passing an `httpx.AsyncClient` and an empty result list, then awaiting the check functions for direct OSINT email verification.**

Holehe is a lightweight, asynchronous OSINT library by megadose/holehe that probes over 120 online services to determine whether an email address is linked to existing accounts. Because the tool is built as a collection of pure asynchronous functions rather than a monolithic CLI, you can embed Holehe functionality into your Python project to build custom email investigation pipelines, automate reconnaissance workflows, or integrate account existence checks into larger security tools.

## Understanding Holehe’s Architecture

### Dynamic Module Loading System

The library uses a dynamic module loader to discover and import site-specific checkers at runtime. In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), the `import_submodules` function (lines 37-47) walks the `holehe.modules` package, automatically discovering every site-specific script without manual registration. This design allows the library to support new services simply by adding new files to the modules directory.

### The Standardized Site Interface

Each site module implements a consistent asynchronous interface defined as `async def <site>(email, client, out)`. As seen in [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) (lines 5-37), the function receives three parameters: the target email string, an `httpx.AsyncClient` instance for HTTP communication, and a shared list (`out`) that collects results. The function appends a dictionary with a fixed schema containing `name`, `domain`, `rateLimit`, `exists`, `emailrecovery`, `phoneNumber`, and `others`. This standardization means every module follows the same contract regardless of which service it probes.

## Step-by-Step Integration Guide

### Installation and Dependencies

First, install Holehe via PyPI to access the core library and all site modules:

```bash
pip install holehe

```

The library depends on `httpx` for asynchronous HTTP requests and `trio` for structured concurrency, though you can substitute `trio` with standard `asyncio` if preferred.

### Basic Single-Module Execution

To embed Holehe functionality into your Python project for checking a single service, import the specific module, create an `httpx.AsyncClient`, and await the check function:

```python
import trio
import httpx
from holehe.modules.social_media.twitter import twitter

async def check_single_email():
    email = "test@example.com"
    out = []  # shared list for results

    client = httpx.AsyncClient(timeout=10)
    
    await twitter(email, client, out)
    
    # Process results

    for result in out:
        if result["exists"]:
            print(f"[+] Account found on {result['domain']}")
    
    await client.aclose()

trio.run(check_single_email)

```

This pattern works for any module in the `holehe.modules` package, from social media platforms to developer tools.

### Orchestrating Multiple Checks

For batch processing, instantiate a single `httpx.AsyncClient` to share connection pools across multiple services, then run several modules against the same email:

```python
import trio
import httpx
from holehe.modules.social_media.snapchat import snapchat
from holehe.modules.social_media.twitter import twitter

async def check_multiple_services():
    email = "test@example.com"
    out = []
    client = httpx.AsyncClient(timeout=10)
    
    # Run multiple checks

    await snapchat(email, client, out)
    await twitter(email, client, out)
    
    # Filter results

    found_accounts = [r for r in out if r["exists"]]
    print(f"Found {len(found_accounts)} registered services")
    
    await client.aclose()

trio.run(check_multiple_services)

```

## Processing Results Programmatically

Each module populates the shared `out` list with dictionaries containing standardized keys. According to [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) (lines 6-52), the result aggregation system expects these fields:

- **name**: The service name (e.g., "Twitter")
- **domain**: The service domain (e.g., "twitter.com")
- **rateLimit**: Boolean indicating if the service throttled the request
- **exists**: Boolean indicating if the email is registered
- **emailrecovery**: Partial email recovery information if exposed
- **phoneNumber**: Phone number fragments if exposed
- **others**: Additional metadata

You can filter results based on the `exists` field to identify where the target email has active accounts, or check `rateLimit` to implement retry logic with exponential backoff.

## Advanced Usage Patterns

### Using the Built-in Launcher

For automated batch analysis, reuse Holehe's own orchestration logic through the `launch_module` wrapper in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) (lines 166-176). This function handles exception trapping and module execution:

```python
import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module

async def run_full_recon(email):
    client = httpx.AsyncClient()
    modules = import_submodules("holehe.modules")
    sites = get_functions(modules)  # all available site checkers

    out = []
    
    async with trio.open_nursery() as n:
        for site in sites:
            n.start_soon(launch_module, site, email, client, out)
    
    await client.aclose()
    return out

# Run complete OSINT check

results = trio.run(lambda: run_full_recon("target@example.com"))
exists_only = [r for r in results if r["exists"]]

```

### Handling Rate Limits and Errors

The result dictionary's `rateLimit` key indicates when a service has throttled requests. When embedding Holehe into production systems, implement IP rotation or request spacing when `rateLimit` returns `True`. The `others` field often contains HTTP status codes or error messages that help distinguish between connection failures, CAPTCHA triggers, and definitive "email not found" responses.

## Summary

- Holehe uses a **dynamic module loading system** (`import_submodules` in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)) to discover site checkers automatically.
- Every module follows the **standardized interface** `async def <site>(email, client, out)` and returns results to a shared list.
- You must provide an **`httpx.AsyncClient`** to each module for connection pooling and timeout management.
- Results follow a **fixed schema** with keys including `exists`, `rateLimit`, and `domain` for consistent data processing.
- Use **`launch_module`** from [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) to leverage built-in exception handling when running checks at scale.

## Frequently Asked Questions

### Can I use asyncio instead of Trio to run Holehe modules?

Yes. While the upstream CLI uses Trio for structured concurrency, the modules are pure `async def` functions compatible with any asyncio-compatible event loop. Simply replace `trio.run()` with `asyncio.run()` or use `await` within your existing async application.

### What data structure does each Holehe module return?

Each module appends a dictionary to the provided `out` list with seven fixed keys: `name`, `domain`, `rateLimit`, `exists`, `emailrecovery`, `phoneNumber`, and `others`. This schema is consistent across all 120+ services, allowing uniform result processing regardless of which site module you invoke.

### How do I run all available Holehe modules at once?

Import `import_submodules` and `get_functions` from [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) to dynamically load all site modules, then use `launch_module` with a Trio nursery (or asyncio tasks) to execute them concurrently. This approach mirrors the tool's own CLI behavior while giving you programmatic access to the aggregated results.

### Is it safe to reuse the same httpx.AsyncClient across multiple checks?

Yes. In fact, reusing the `httpx.AsyncClient` is recommended because it maintains connection pooling, keeps TCP connections alive, and respects shared timeout and header configurations across all Holehe modules. Instantiate one client at the start of your workflow and pass it to every module before closing it at the end.