# Can Holehe Be Used Programmatically in Python? 3 Methods to Integrate OSINT Checks

> Integrate Holehe programmatically in Python using three methods. Learn how to perform OSINT checks with this pure-Python library for seamless automation and enhanced security.

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

---

**Yes, Holehe can be used programmatically in Python** as a pure-Python library with full async support, no subprocess or external binaries required.

Holehe is an open-source **email OSINT tool** by megadose that checks whether an email address is registered on hundreds of websites. While commonly used as a CLI tool, its modular architecture makes it ideal for Python automation, custom pipelines, and integration into larger security workflows.

## Why Use Holehe Programmatically?

Running Holehe from Python code unlocks several advantages over CLI usage:

- **Custom filtering** – Process only specific site categories or result types
- **Result transformation** – Convert output to JSON, database records, or alerts
- **Workflow integration** – Embed checks into SIEM pipelines, web apps, or scheduled jobs
- **Concurrent control** – Fine-tune async execution with Trio primitives

The codebase is structured around a simple contract: every site check is an `async` function with signature `(email, client, out)` in `holehe/modules/`.

## Method 1: Check a Single Site Directly

For targeted investigations, import and call individual modules. This is the most lightweight approach.

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

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

trio.run(check_snapchat)

```

Each module in `holehe/modules/` follows this pattern. The `out` list receives standardized result dictionaries containing:

| Key | Meaning |
|-----|---------|
| `name` | Site identifier (e.g., `"snapchat"`) |
| `exists` | Boolean indicating registration found |
| `emailrecovery` | Partial recovery email if exposed |
| `rateLimit` | Whether the check hit rate limiting |

## Method 2: Run Full Multi-Site Scans

To replicate the complete Holehe behavior programmatically, use the core orchestration utilities from [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py).

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

async def full_holehe_scan(email):
    # Dynamically load all site check modules

    modules = import_submodules("holehe.modules")
    websites = get_functions(modules)  # Extract callable check functions

    
    results = []
    
    async with httpx.AsyncClient() as client:
        # Run all checks concurrently with Trio nursery

        async with trio.open_nursery() as nursery:
            for check_func in websites:
                nursery.start_soon(launch_module, check_func, email, client, results)
    
    return results

# Execute scan

output = trio.run(full_holehe_scan, "target@example.com")

for site_result in output:
    print(f"{site_result['name']}: {site_result.get('exists', 'unknown')}")

```

The `launch_module` wrapper in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) handles exceptions and ensures partial failures don't crash the entire scan.

## Method 3: Invoke the High-Level CLI Wrapper

For quick scripts that need standard CLI behavior without shelling out, call `main()` directly.

```python
from holehe.core import main

if __name__ == "__main__":
    # Behaves identically to: holehe target@example.com

    main()

```

**Important:** `main()` parses `sys.argv`, so you must set arguments before calling:

```python
import sys
from holehe.core import main

sys.argv = ["holehe", "target@example.com", "--only-used"]
main()

```

This approach respects all CLI flags including `--only-used`, `--no-clear`, and timeout settings.

## Key Implementation Files Reference

Understanding these source files helps with custom integrations:

- **[`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)** – Contains `main()`, `maincore()`, `import_submodules()`, `get_functions()`, and `launch_module()`. The async orchestration hub.
- **[`holehe/modules/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/__init__.py)** – Package structure enabling dynamic module discovery.
- **[`holehe/modules/social_media/snapchat.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/snapchat.py)** – Template for individual site checks; shows request construction and response parsing.
- **[`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py)** – Provides `getUserAgent()` for rotating headers.

## Async Architecture: Trio and httpx

Holehe is built on **Trio** for structured concurrency and **httpx** for HTTP. This matters for programmatic use:

- **Never mix asyncio and Trio** – Use `trio.run()` or `trio`'s guest mode exclusively
- **Share the client** – Pass one `httpx.AsyncClient` to all checks for connection pooling
- **Nursery-based cancellation** – Failed checks cancel cleanly without resource leaks

For sync-only codebases, run Trio in a thread:

```python
import trio

def sync_wrapper(email):
    return trio.run(full_holehe_scan, email)

result = sync_wrapper("target@example.com")

```

## Summary

- **Holehe is fully importable** as a Python library in `megadose/holehe`
- **Three integration patterns**: single module, full orchestration, or CLI wrapper
- **Core functions** in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) handle module loading and concurrent execution
- **Result format** is standardized across all 100+ site checks
- **No subprocess required** – pure Python with Trio/httpx async stack

## Frequently Asked Questions

### Can I use Holehe with standard asyncio instead of Trio?

No. Holehe is built exclusively on Trio for structured concurrency. While Trio can run as a guest inside asyncio using `trio.lowlevel.start_guest_run`, the library itself requires Trio primitives. Mixing asyncio coroutines directly will cause runtime errors.

### How do I filter results to only show confirmed accounts?

Check the `exists` key in result dictionaries. When using the programmatic API, filter the output list:

```python
confirmed = [r for r in results if r.get("exists") is True]

```

The `--only-used` CLI flag performs this filtering automatically when using `main()`.

### Is rate limiting handled automatically?

Partially. Individual modules detect rate limits and set `rateLimit: True` in results, but retry logic is minimal. For production use, implement exponential backoff between calls or proxy rotation via `httpx.AsyncClient` configuration.

### Can I add custom site checks without modifying the source?

Yes. Create a module matching the `(email, client, out)` signature and add it to `holehe/modules/your_category/`. The `import_submodules` function in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) dynamically discovers all modules at runtime, so custom checks integrate automatically.