Holehe CLI vs Programmatic API: Key Differences for OSINT Email Checks

The Holehe CLI provides a ready-to-run terminal interface with formatted output and CSV export, while the programmatic API returns raw Python data structures for custom integration.

Holehe is an open-source email OSINT tool by megadose that checks for account registrations across hundreds of websites. When deciding how to run Holehe, you'll choose between its command-line interface for quick investigations or its Python API for embedded workflows. Both approaches ultimately execute the same async core logic in holehe.core, but they differ significantly in input handling, output formatting, and control flow.

Entry Points and Execution Flow

CLI: Console Script to Trio Runner

The CLI installs as a console script named holehe, defined in setup.py as holehe=holehe.core:main. When invoked, this calls holehe.core.main(), which immediately executes trio.run(maincore).

In holehe/core.py lines 32-34, the main() function serves as the synchronous entry point that bridges to the async world.


# From holehe/core.py

def main():
    trio.run(maincore)

The maincore() function handles argument parsing via argparse starting at line 179, then orchestrates module execution through a Trio nursery.

API: Direct Async Function Imports

The programmatic API skips the console script entirely. You import async functions directly from holehe.core and manage execution yourself.

from holehe.core import import_submodules, get_functions, launch_module
import httpx

async def custom_check(email):
    modules = import_submodules("holehe.modules")
    
    class Args: 
        csvoutput = False
        nopasswordrecovery = False
    
    websites = get_functions(modules, Args())
    
    async with httpx.AsyncClient(timeout=10) as client:
        out = []
        for website in websites:
            await launch_module(website, email, client, out)
        return out

This approach gives you fine-grained control over which modules run, concurrency strategies, and result handling.

Argument Handling: Parsed Flags vs Direct Parameters

The CLI uses argparse with flags defined in maincore() at lines 179-196. Key options include:

  • --only-used — Show only sites where the email is registered
  • --no-color — Disable terminal colors
  • --csv — Export results to a timestamped CSV file
  • --timeout — Set request timeout in seconds

The API bypasses argparse completely. You construct parameter objects directly, as shown in the Args class above. This eliminates string parsing overhead and enables dynamic configuration at runtime.

Output Formats: Terminal Tables vs Raw Data Structures

CLI Output Characteristics

The CLI produces multiple side effects after the async run completes:

  • Formatted table: Color-coded results printed via print_result
  • Progress bar: Visual feedback through TrioProgress instrument
  • CSV export: Optional file creation via export_csv
  • Terminal clearing: Screen management for clean display

These features are implemented in holehe/core.py lines 27-31.

API Output Characteristics

The programmatic API returns a plain Python list of dictionaries containing raw findings. Each dictionary includes standard fields like name, domain, method, rateLimit, exists, emailrecovery, phoneNumber, and others.


# Example returned structure

[
    {
        "name": "twitter",
        "domain": "twitter.com",
        "method": "register",
        "rateLimit": False,
        "exists": True,
        "emailrecovery": None,
        "phoneNumber": "+1-xxx-xxx-xxxx",
        "others": None
    }
]

No formatting, no files, no terminal manipulation — just structured data for your application to process.

Concurrency and Control Flow

CLI: Full Module Sweep with Fixed Orchestration

The CLI discovers all modules and launches them together inside a Trio nursery. From holehe/core.py lines 18-22:

async with trio.open_nursery() as nursery:
    for website in websites:
        nursery.start_soon(launch_module, website, email, client, out)

This approach maximizes throughput but offers no granularity. Every discovered module runs, and the CLI blocks until completion.

API: Selective Execution and Custom Strategies

With the API, you control exactly which modules execute and how:


# Run only specific modules

target_modules = ["github", "twitter", "instagram"]
filtered = [w for w in websites if w.__name__.split(".")[-1] in target_modules]

# Custom concurrency: sequential with delays

import asyncio
for website in filtered:
    await launch_module(website, email, client, out)
    await asyncio.sleep(1)  # Rate limiting

Error Handling Behavior

Both interfaces use the same launch_module function, which catches exceptions internally. In holehe/core.py lines 168-176, errors are recorded in the output list rather than raised:

try:
    await module(email, client, out)
except Exception as e:
    name = str(module).split('<function ')[1].split(' ')[0]
    out.append({"name": name, "error": str(e)})

The CLI continues execution and prints a summary showing any failures. The API returns these error entries in the list, allowing your code to detect them via the "error" key and respond appropriately — retry, log, or raise as needed.

When to Use Each Interface

Scenario Recommended Approach
One-off email investigation CLI — fastest path to visual results
Automated security scanning API — integrate with existing Python tooling
Custom output formatting API — raw data for your own reports
CI/CD pipeline integration API — programmatic error handling and exit codes
Large-scale batch processing API — control rate limiting and resource usage
Quick verification with CSV export CLI with --csv flag

Working Code Examples

Complete CLI Usage


# Basic check with formatted output

holehe target@example.com

# Export to CSV, show only confirmed accounts

holehe target@example.com --only-used --csv --timeout 15

# No color for pipe processing

holehe target@example.com --no-color | grep "True"

Complete API Integration

import asyncio
import httpx
from holehe.core import import_submodules, get_functions, launch_module

async def holehe_api_check(email, timeout=10, modules=None):
    """
    Programmatic Holehe check with optional module filtering.
    Returns structured results for integration.
    """
    # Load module discovery

    module_root = import_submodules("holehe.modules")
    
    # Minimal args namespace

    class Config:
        csvoutput = False
        nopasswordrecovery = False
    
    # Get target functions

    all_websites = get_functions(module_root, Config())
    
    # Apply module filter if specified

    if modules:
        targets = [w for w in all_websites 
                  if any(m in w.__name__ for m in modules)]
    else:
        targets = all_websites
    
    # Execute with controlled client

    results = []
    async with httpx.AsyncClient(timeout=timeout) as client:
        for site in targets:
            await launch_module(site, email, client, results)
    
    # Separate successes and errors

    successes = [r for r in results if "error" not in r]
    failures = [r for r in results if "error" in r]
    
    return {"found": successes, "errors": failures, "total": len(results)}

# Usage

output = asyncio.run(holehe_api_check(
    "target@example.com",
    modules=["github", "gitlab", "twitter"]
))

Key Source Files

File Purpose
holehe/core.py Main orchestration: main(), maincore(), launch_module(), argument parsing, and result formatting
holehe/instruments.py TrioProgress class for CLI progress bars
holehe/modules/__init__.py Module discovery and loading utilities
setup.py Console script entry point definition

Summary

  • The CLI wraps Holehe's core in a user-friendly layer with argparse, colored terminal output, progress indicators, and CSV export — ideal for standalone investigations.
  • The API exposes launch_module, import_submodules, and get_functions directly, returning raw Python lists for custom processing and integration.
  • Both interfaces execute identical verification logic in holehe.modules; the difference is presentation and control.
  • Choose the CLI for immediate visual results, the API for embedded automation and custom workflows.

Frequently Asked Questions

Can I use the CLI and API together in the same project?

Yes. Import holehe.core functions for programmatic use while still invoking the holehe command for manual checks. They share no global state and can coexist safely.

Does the API support CSV export like the CLI?

Not automatically. The API returns raw data; you implement CSV export using Python's csv module or pandas. The CLI's export_csv function in holehe/core.py demonstrates the expected format if you want to match it.

Is there a performance difference between CLI and API?

No meaningful difference in core execution speed. Both use the same Trio-based async engine and httpx.AsyncClient. The CLI adds minimal overhead for progress rendering and terminal output.

How do I filter specific modules when using the API?

Filter the list returned by get_functions() before calling launch_module(). Match against function.__name__ or maintain an allowlist of target modules, as shown in the complete API example above.

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 →