# Understanding the Holehe Architecture: A Deep Dive into the Modular OSINT Toolkit

> Explore the Holehe architecture, a layered, asynchronous Python design. Discover how its modular OSINT toolkit executes hundreds of email checks concurrently using trio and asyncio.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: architecture
- Published: 2026-08-21

---

**Holehe utilizes a layered, asynchronous architecture built on Python's `trio` and `asyncio` that separates CLI handling, core orchestration, and modular service checking, enabling hundreds of email verification modules to execute concurrently through a shared `httpx.AsyncClient`.**

Holehe is a Python-based OSINT (Open Source Intelligence) toolkit developed by megadose that checks whether an email address is registered across hundreds of online platforms without alerting the target. The holehe architecture follows a modular, plugin-based design that makes it trivial to add new service checks while maintaining high performance through shared asynchronous HTTP clients.

## Five-Layer Architectural Stack

The codebase organizes functionality into distinct layers, each with specific responsibilities and well-defined interfaces.

### CLI and Entry Point

The command-line interface resides in [`holehe/__main__.py`](https://github.com/megadose/holehe/blob/main/holehe/__main__.py), which parses arguments and delegates to the core engine. The [`setup.py`](https://github.com/megadose/holehe/blob/main/setup.py) file registers this as the console entry point (`holehe = holehe.__main__:main`), allowing users to invoke the tool directly after installation.

```bash
holehe test@example.com

```

This layer handles argument parsing, output formatting flags (such as `--json`), and initializes the async event loop before calling `holehe.core.run`.

### Core Orchestrator

The [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) file contains the central execution engine. Its primary function, `run()`, dynamically discovers all available service modules by walking the `holehe/modules` package tree. It imports every submodule that implements the public API signature: `async def <service_name>(email, client, out)`.

The core instantiates a single shared `httpx.AsyncClient` configured with rotating user agents from [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py). It then spawning each service module as a separate concurrent task using `trio` (with `asyncio` support), aggregating results into a standardized output format.

### Service Modules

Individual service implementations live in `holehe/modules/` organized by category (e.g., `social_media/`, `porn/`, `shopping/`). Each file exports exactly one coroutine named after the service. For example, [`holehe/modules/social_media/snapchat.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/snapchat.py) contains the `snapchat()` coroutine, while [`holehe/modules/porn/xvideos.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/porn/xvideos.py) contains the `xvideos()` coroutine.

Every module follows a strict contract:

- **Parameters**: `email` (str), `client` (httpx.AsyncClient), `out` (list)
- **Output**: Appends a dictionary to the `out` list containing:
  - `name`: Service identifier
  - `exists`: Boolean indicating account presence
  - `emailrecovery`: Recovery email if exposed
  - `phoneNumber`: Phone number if exposed  
  - `rateLimit`: Boolean indicating throttling
  - `others`: Additional metadata dictionary

### Utilities Layer

Helper functions for operational concerns reside in [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py). This module generates rotating user-agent strings to prevent fingerprinting during concurrent requests. The architecture allows modules to focus purely on service-specific logic while shared concerns like HTTP headers and rate-limit handling remain in the core or utility layers.

### Packaging Configuration

The [`setup.py`](https://github.com/megadose/holehe/blob/main/setup.py) file declares dependencies (`httpx`, `trio`, `bs4`, etc.) and establishes the package structure. It defines the `holehe` command as an entry point mapping to `holehe.__main__:main`, ensuring proper module path resolution when the tool is installed via pip.

## The Async Execution Pipeline

The holehe architecture implements a specific workflow for concurrent email checking that maximizes throughput while respecting service constraints.

### Dynamic Module Discovery

When `core.run()` executes, it programmatically inspects the `holehe.modules` namespace package. It imports every Python file found in subdirectories automatically, checking for the presence of a callable matching the required async signature. This eliminates manual registration—adding a new service requires only dropping a file into the appropriate `holehe/modules/` subdirectory.

### Shared Client Concurrency

Rather than instantiating separate HTTP clients per service, the core creates one `httpx.AsyncClient` instance and passes it to all coroutines. This connection pooling reduces overhead and ensures consistent timeout and retry policies across all checks. The client configuration includes randomized user agents sourced from [`localuseragent.py`](https://github.com/megadose/holehe/blob/main/localuseragent.py) to mitigate blocking.

### Standardized Result Aggregation

Each module executes independently and appends its result dictionary to the shared `out` list passed by reference. The core awaits all tasks using `trio` nurseries (or `asyncio.gather`), then processes the aggregated list. This approach prevents race conditions while allowing services with varying response times to complete without blocking faster checks.

### Rate Limit Awareness

Modules detect throttling (HTTP 429, CAPTCHA challenges, or timing anomalies) and set `rateLimit=True` in their output. While the current implementation primarily reports these states, the architecture supports future extensions for automatic retry logic with exponential backoff or proxy rotation between attempts.

## Practical Implementation Examples

### Running from Command Line

The simplest interaction uses the packaged CLI:

```bash
holehe test@example.com --json

```

The `--json` flag outputs structured data rather than the default colored table format.

### Embedding Individual Modules

You can import and run specific modules directly for targeted checks:

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

async def check_snapchat():
    email = "target@example.com"
    results = []
    client = httpx.AsyncClient()
    
    await snapchat(email, client, results)
    print(results)
    # Output: [{'name': 'snapchat', 'exists': True, 'emailrecovery': None, ...}]

    
    await client.aclose()

trio.run(check_snapchat)

```

### Using the High-Level Core API

For comprehensive checks across all registered services:

```python
import trio
from holehe.core import run

async def full_scan():
    email = "target@example.com"
    results = await run(email)
    
    for service in results:
        if service.get('exists'):
            print(f"Account found on {service['name']}")

trio.run(full_scan)

```

This invokes the full holehe architecture, including module discovery and parallel execution.

## Summary

- **Layered Design**: The architecture separates CLI parsing ([`holehe/__main__.py`](https://github.com/megadose/holehe/blob/main/holehe/__main__.py)), core orchestration ([`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)), service implementations (`holehe/modules/`), and utilities ([`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py)).
- **Plugin Architecture**: New services require only a single Python file implementing the `async def service(email, client, out)` signature—no registration or configuration files needed.
- **Shared Resources**: A single `httpx.AsyncClient` serves all concurrent modules, reducing connection overhead while maintaining isolation through async task boundaries.
- **Standardized Contracts**: Every module returns a dictionary with `name`, `exists`, `rateLimit`, `emailrecovery`, `phoneNumber`, and `others` fields, ensuring consistent output regardless of service complexity.
- **Async-First**: Built on `trio` and `asyncio`, the codebase achieves true parallelism suitable for I/O-bound OSINT operations across hundreds of endpoints.

## Frequently Asked Questions

### What async library does holehe use for concurrency?

Holehe primarily uses **Trio** for structured concurrency, though it maintains compatibility with `asyncio`. The [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) file implements task spawning through Trio nurseries, allowing modules to run in parallel while providing clean cancellation semantics and error propagation across hundreds of concurrent HTTP requests.

### How do I add a new service module to holehe?

Create a Python file in the appropriate `holehe/modules/` subdirectory (e.g., [`holehe/modules/shopping/newstore.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/shopping/newstore.py)) and implement an async function matching the service name. The function must accept three parameters: `email` (string), `client` (httpx.AsyncClient), and `out` (list). Append a dictionary with the required keys (`name`, `exists`, `rateLimit`, etc.) to `out`. The core automatically discovers and executes the module on the next run.

### What information does each holehe module return?

Every module returns a standardized dictionary containing: `name` (the service identifier), `exists` (boolean indicating if the email is registered), `emailrecovery` (any leaked recovery email), `phoneNumber` (any leaked phone digits), `rateLimit` (boolean indicating if the service throttled the request), and `others` (a dictionary for additional service-specific metadata such as profile URLs or account creation dates).

### Why does holehe use a shared HTTP client across all modules?

The architecture shares a single `httpx.AsyncClient` instance across all service modules to enable connection pooling, reduce memory overhead, and ensure consistent request handling (timeouts, headers, redirects). This design, implemented in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), allows hundreds of concurrent checks to run efficiently without establishing separate TCP connections for each service, significantly improving performance during large-scale OSINT operations.