# How to Integrate Holehe as a Python Library in Custom OSINT Tools

> Integrate Holehe as a Python library into your OSINT tools. Leverage Trio and httpx to run async service checks for enhanced data gathering.

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

---

**You can integrate holehe as a Python library by importing `import_submodules`, `get_functions`, and `launch_module` from `holehe.core`, then running the async service checks with Trio and httpx.**

Holehe is a fast, asynchronous email-to-service correlation tool maintained by megadose. While it ships with a command-line interface, its core engine exposes a public API that lets you embed email reconnaissance directly into custom OSINT pipelines. This guide shows exactly how to integrate holehe as a Python library using the same primitives the CLI relies on.

---

## Core Architecture of Holehe's Public API

The library's design separates discovery, execution, and result handling into distinct layers in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py).

| Component | Role | Key Source File |
|-----------|------|---------------|
| **`holehe.core`** | Central engine providing `import_submodules`, `get_functions`, `launch_module`, and `maincore`. | [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) |
| **`holehe.modules`** | Package containing one file per service (social media, e-commerce, etc.). Each exports a single async function with signature `(email, client, out)`. | [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) (example) |
| **`holehe.instruments.TrioProgress`** | Optional Trio instrument for progress bar display during async execution. | [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) |
| **`holehe.localuseragent.ua`** | Random User-Agent generator used per request to reduce fingerprinting. | [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py) |

The execution flow works as follows:

1. **`import_submodules("holehe.modules")`** walks the package tree using `pkgutil.walk_packages` and dynamically loads every service module.

2. **`get_functions()`** inspects each loaded module and extracts the public async function—the last callable object defined in the file.

3. **`launch_module`** schedules each service inside a Trio nursery, passing a shared `httpx.AsyncClient` and a shared `out` list where results are appended.

4. **Result normalization** ensures every module returns a dict with consistent keys: `name`, `domain`, `rateLimit`, `error`, `exists`, `emailrecovery`, `phoneNumber`, `others`.

Because `maincore` is CLI-oriented, you bypass it entirely and call the lower-level helpers directly for programmatic use.

---

## Step-by-Step Integration Guide

Follow these steps to embed holehe into your own Python-based OSINT tooling.

### Step 1: Install the Library

```bash
pip install holehe

```

Or add to your [`requirements.txt`](https://github.com/megadose/holehe/blob/main/requirements.txt):

```

holehe>=1.60

```

### Step 2: Import Core Helpers

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

```

These three functions are the only imports you need for full functionality.

### Step 3: Create a Shared HTTPX Client

```python
import httpx

client = httpx.AsyncClient(timeout=10)  # matches CLI default

```

Reusing a single client across all service checks saves connection overhead and respects HTTP/2 multiplexing where available.

### Step 4: Load and Filter Modules

```python
all_modules = import_submodules("holehe.modules")

# Optional: filter to specific service categories

wanted = {
    k: v for k, v in all_modules.items()
    if any(s in k for s in ("twitter", "instagram", "snapchat"))
}

functions = get_functions(wanted)  # or pass `all_modules` for everything

```

The `get_functions()` helper returns a list of async callables ready for execution.

### Step 5: Run Checks Concurrently with Trio

```python
import trio

async def run_checks(email):
    out = []
    async with client:
        async with trio.open_nursery() as nursery:
            for fn in functions:
                nursery.start_soon(launch_module, fn, email, client, out)
    return out

```

Trio is holehe's native async runtime. The nursery pattern ensures all services run in parallel and cleans up properly on cancellation or error.

### Step 6: Process Results Programmatically

```python
def analyze_results(results):
    for r in results:
        if r["exists"]:
            print(f"[+] {r['domain']}: account found")
        elif r["rateLimit"]:
            print(f"[x] {r['domain']}: rate limited")
        elif r["error"]:
            print(f"[!] {r['domain']}: {r['error']}")
        else:
            print(f"[-] {r['domain']}: no account")

# Run it

results = trio.run(run_checks, "target@example.com")
analyze_results(results)

```

Each result dict follows the same schema used by the CLI, so you can feed data directly into databases, SIEMs, or graph-based OSINT platforms like Maltego.

### Step 7: Optional CSV Export

```python
from holehe.core import export_csv
import argparse

# Create minimal namespace matching CLI expectations

args = argparse.Namespace(csvoutput=True, filename="results.csv")
export_csv(results, args, email="target@example.com")

```

The `export_csv` helper reuses the CLI's formatting logic without requiring subprocess calls.

---

## Complete Minimal Example

This self-contained script mirrors CLI behavior while exposing raw results for custom handling:

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


async def holehe_check(email: str):
    # Load all available service modules

    modules = import_submodules("holehe.modules")
    funcs = get_functions(modules)

    # Execute all checks concurrently

    async with httpx.AsyncClient(timeout=10) as client:
        out = []
        async with trio.open_nursery() as nursery:
            for fn in funcs:
                nursery.start_soon(launch_module, fn, email, client, out)

    # Return sorted by service name for consistent output

    return sorted(out, key=lambda x: x["name"])


if __name__ == "__main__":
    email = "victim@example.com"
    results = trio.run(holehe_check, email)

    for r in results:
        status = "[+]" if r["exists"] else "[-]"
        recovery = f" (recovery: {r['emailrecovery']})" if r.get("emailrecovery") else ""
        print(f"{status} {r['domain']}{recovery}")

```

Replace the print block with your own logic: Elasticsearch indexing, Neo4j graph insertion, or webhook triggers to other OSINT tools.

---

## Key Source Files Reference

| File | Purpose |
|------|---------|
| [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) | Main orchestration with `import_submodules`, `get_functions`, `launch_module`, `export_csv`, and result formatting |
| `holehe/modules/**/*.py` | Individual service implementations—one async function per target site |
| [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) | `TrioProgress` class for optional CLI progress bars |
| [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py) | `ua()` function for randomized User-Agent strings |

All paths are relative to the repository root at `megadose/holehe`.

---

## Advanced Integration Patterns

### Selective Service Loading for Performance

```python
from pathlib import Path

def load_category(category: str):
    """Load only modules from a specific subdirectory."""
    base = Path(__file__).parent / "holehe" / "modules" / category
    modules = {}
    for mod in base.glob("*.py"):
        if mod.stem == "__init__":
            continue
        # Build dotted path and import

        dotted = f"holehe.modules.{category}.{mod.stem}"
        modules[dotted] = __import__(dotted, fromlist=[None])
    return modules

```

This avoids importing 100+ modules when you only need social media checks.

### Custom Result Handlers with Structured Logging

```python
import json
import structlog

logger = structlog.get_logger()

async def logged_check(email: str):
    results = await holehe_check(email)
    for r in results:
        logger.info(
            "holehe_check_complete",
            email=email,
            domain=r["domain"],
            exists=r["exists"],
            rate_limited=r["rateLimit"],
            error=r["error"],
        )
    return results

```

Structured logging enables downstream SIEM correlation and audit trails.

### Integration with Async Web Frameworks

```python
from fastapi import FastAPI
import trio
from trio_asyncio import trio_as_aio

app = FastAPI()

@app.get("/check/{email}")
async def api_check(email: str):
    # Bridge Trio to asyncio for FastAPI compatibility

    results = await trio_as_aio(trio.run, holehe_check, email)
    return {"email": email, "services": results}

```

Use `trio-asyncio` or similar bridges when mixing holehe with asyncio-based tools.

---

## Summary

- **Install once:** `pip install holehe` gives you the full public API.

- **Import three functions:** `import_submodules`, `get_functions`, and `launch_module` from `holehe.core` are the complete integration surface.

- **Use Trio:** The library is built on Trio; use `trio.open_nursery()` for concurrent execution.

- **Share one client:** Pass a single `httpx.AsyncClient` to all `launch_module` calls for connection efficiency.

- **Consume standard dicts:** Results use a fixed schema with `exists`, `rateLimit`, `error`, `emailrecovery`, and `phoneNumber` keys.

- **Avoid subprocess:** Direct API calls are faster, cleaner, and give you full control over error handling and result routing.

---

## Frequently Asked Questions

### Can I use holehe with asyncio instead of Trio?

Holehe's core in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) uses Trio-specific APIs like `trio.open_nursery()`. To use it with asyncio, bridge with `trio-asyncio` or run holehe in a separate thread and communicate via queues. Direct asyncio compatibility would require modifying `launch_module` and the nursery patterns.

### How do I add my own custom service checks?

Create a Python file in `holehe/modules/` or a custom package, define an async function with signature `async def myservice(email, client, out)`, and append a result dict to `out`. The `get_functions()` helper will auto-discover it if you pass your package name to `import_submodules()`.

### What rate limiting protections exist?

Each module handles its own rate-limit detection and sets `rateLimit: True` in results when triggered. The shared `httpx.AsyncClient` does not enforce global delays—implement your own throttling (e.g., `trio.sleep()` between batches) if scanning multiple emails against the same service.

### Is the User-Agent rotation automatic?

Yes. Every request in the standard modules pulls from `holehe.localuseragent.ua()`, which returns a randomized desktop browser User-Agent string. No additional configuration is required for basic OPSEC.