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

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:

  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 lines 210–215:

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


# 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


# 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

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 37–47 import_submodules() — dynamic module discovery
holehe/core.py 50–63 get_functions() — callable extraction
holehe/core.py 66–78 launch_module() — async task wrapper
holehe/core.py 194–196 Timeout argument parsing
holehe/core.py 210–215 Elapsed time calculation and output
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 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 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.

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 →