# How Long Does It Take to Run All Holehe Modules on One Email? A Performance Deep Dive

> Discover how long it takes to run all holehe modules on one email. Get a performance deep dive into holehe module execution times on a standard connection.

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

---

**Running all ~120 Holehe modules against a single email address typically completes in 5–12 seconds on a standard broadband connection, with the exact duration printed at the end of each scan.**

Holehe is an open-source OSINT tool that checks whether an email address is registered across more than 120 online services. According to the megadose/holehe source code, the tool's performance characteristics are determined by its concurrent async architecture and network-bound request pattern rather than CPU processing.

## How Holehe Measures and Executes a Full Scan

### The Module Loading Pipeline

Before any network requests fire, Holehe performs three setup steps defined in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py):

1. **Dynamic submodule import** — `import_submodules()` (lines 37–47) recursively imports every Python file under `holehe/modules/`, discovering approximately 120 service-specific checkers.

2. **Function extraction** — `get_functions()` (lines 50–63) filters these imports to collect only async callables matching the signature `async def service_name(email, client, out)`.

3. **Concurrent task spawning** — `launch_module()` (lines 66–78) wraps each callable as a Trio task, enabling parallel execution across all services.

This architecture means all ~120 modules start simultaneously rather than running sequentially.

### Timing Implementation

The elapsed time calculation is straightforward and visible in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) lines 210–215:

```python
start_time = time.time()

# ... trio nursery runs all modules ...

elapsed = time.time() - start_time
print(f"{len(modules)} websites checked in {elapsed:.2f} seconds")

```

The timer starts before module execution and stops after every task completes or times out. No per-module timing is captured—only total wall-clock duration.

## What Determines Total Runtime

Holehe's performance is **network-bound, not CPU-bound**. Each module performs a single HTTP request (typically to a "forgot password" or account recovery endpoint). The dominant factors are:

- **Per-request latency** — Most services respond in 200ms–800ms, though global CDNs and server locations vary this widely.

- **Default timeout** — Set to 10 seconds via `parser.add_argument("-T","--timeout", default=10, type=float)` (lines 194–196). Slow or unresponsive services consume up to this limit.

- **Concurrent connection limits** — Holehe uses `httpx.AsyncClient` with Trio; practical TCP limits and remote server rate-limiting cap true parallelism.

- **Rate-limit detection** — When a service returns HTTP 429 or similar, Holehe skips further processing for that module (`rateLimit=True` in response dict), which can reduce total time.

## Practical Runtime Ranges

| Scenario | Expected Duration |
|----------|-----------------|
| Fast, stable connection; most services responsive | **5–7 seconds** |
| Typical residential broadband with moderate latency | **8–12 seconds** |
| High-latency or congested network | **12–20 seconds** |
| Multiple timeouts at 10s default | **Up to ~30 seconds** (rare, as most fail faster) |

The worst-case theoretical runtime would be `~120 × timeout` if every service hung, but in practice connection timeouts and TCP failures resolve in 3–5 seconds rather than the full 10-second window.

## Running Holehe and Observing Performance

### Command-Line Usage

```bash

# Default execution with timing output

holehe user@example.com

# Example output:

# [+] twitter.com

# [-] facebook.com

# ...

# 120 websites checked in 9.34 seconds

```

### Adjusting Performance via Timeout

```bash

# Faster failure for unresponsive services

holehe -T 5 user@example.com

# More patience for slow international endpoints

holehe -T 15 user@example.com

```

### Programmatic Usage with Timing

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

async def timed_scan(email: str, timeout: float = 10.0):
    start = time.time()
    
    # Load all modules

    modules = import_submodules("holehe.modules")
    functions = get_functions(modules)
    
    # Execute concurrently

    client = httpx.AsyncClient(timeout=timeout)
    nursery_results = []
    
    async with trio.open_nursery() as nursery:
        for func in functions:
            nursery.start_soon(
                launch_module, func, email, client, nursery_results
            )
    
    await client.aclose()
    elapsed = time.time() - start
    
    print(f"Scanned {len(functions)} services in {elapsed:.2f}s")
    return nursery_results, elapsed

# Run

results, duration = trio.run(timed_scan, "user@example.com")

```

## Key Implementation Files

| File | Lines | Purpose |
|------|-------|---------|
| [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) | 37–47 | `import_submodules()` — dynamic module discovery |
| [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) | 50–63 | `get_functions()` — callable extraction |
| [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) | 66–78 | `launch_module()` — async task wrapper |
| [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) | 194–196 | Timeout argument parsing |
| [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) | 210–215 | Elapsed time calculation and output |
| [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) | Full file | Trio progress bar for live feedback |

## Summary

- **Holehe runs all ~120 modules concurrently using Trio**, not sequentially.

- **Total runtime is measured in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) lines 210–215** as wall-clock time from start to completion of all async tasks.

- **Expect 5–12 seconds for typical broadband**; the 10-second default timeout bounds worst-case per-module delays.

- **Network latency dominates**; CPU usage remains minimal throughout execution.

- **Adjust with `-T` / `--timeout`** to trade failure speed for resilience on slow connections.

## Frequently Asked Questions

### Why doesn't Holehe show per-module timing?

The codebase only implements total elapsed measurement. Individual module duration would require instrumenting each `launch_module()` call separately—possible to patch locally, but not present in the upstream source.

### Can I speed up Holehe by reducing the timeout?

Yes. Using `-T 3` or `-T 5` forces faster failures on unresponsive services, though you may miss results from legitimately slow international endpoints. The default 10 seconds balances completeness against wait time.

### Does Holehe cache results between runs?

No. Every execution performs fresh HTTP requests. No disk or memory caching exists in [`core.py`](https://github.com/megadose/holehe/blob/main/core.py) or module implementations. Repeated scans of the same email incur full network cost each time.

### What happens if my connection drops during a scan?

Active Trio tasks raise `httpx.ConnectError` or `trio.BrokenResourceError`, which modules catch and report as `error: True` in result dicts. The remaining concurrent tasks continue; total runtime reflects completed plus failed requests.