# Where to Place Custom Modules in Holehe: Complete Directory Structure Guide

> Discover where to place custom modules in Holehe. Learn about the complete directory structure to easily add your own modules for enhanced functionality.

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

---

**Custom modules must be placed inside the `holehe/modules/` directory tree, either within existing category folders like `social_media/` or `shopping/`, or within new subdirectories you create, as Holehe automatically discovers all Python files under this package via the `import_submodules` function in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py).**

Holehe is an email reconnaissance tool developed by megadose that checks email usage across hundreds of platforms. When extending its capabilities with custom modules, understanding the precise directory structure and discovery mechanism ensures your integrations execute automatically without manual registration.

## How Holehe Discovers Custom Modules

Holehe uses dynamic package importing to load every module at runtime. In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) at lines 36-47, the `import_submodules("holehe.modules")` helper walks the `holehe.modules` package's `__path__` and imports each `.py` file it encounters. This means any Python file placed within the `holehe/modules/` hierarchy becomes available immediately upon the next execution—no edits to [`core.py`](https://github.com/megadose/holehe/blob/main/core.py) or registry files are necessary.

## The Correct Directory Structure for Custom Modules

All custom modules belong under the **`holehe/modules/`** directory. The repository organizes services into logical categories, and your additions should follow this convention:

```

holehe/
└─ modules/
   ├─ social_media/
   │   └─ your_service.py
   ├─ shopping/
   │   └─ your_shop.py
   ├─ sport/
   │   └─ your_sport.py
   ├─ custom/              # New category (requires __init__.py)

   │   ├─ __init__.py
   │   └─ foobar.py
   └─ __init__.py

```

**Existing categories** include `social_media`, `shopping`, `sport`, `music`, and others listed in the repository's README. Select the folder that best matches your service type. If none fit, create a new subpackage folder (e.g., `holehe/modules/custom/`) and include an empty [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) file so Python recognizes it as a package.

## Required Function Signature and Output Format

Every custom module must expose a single asynchronous function matching the filename. The function signature must be:

```python
async def module_name(email: str, client, out: list):

```

The function should append a dictionary to the `out` list containing exactly these keys:

- `name`: Service identifier string
- `domain`: Associated domain (e.g., `"example.com"`)
- `rateLimit`: Boolean indicating if rate limited
- `error`: Boolean indicating if an error occurred
- `exists`: Boolean indicating if account exists
- `emailrecovery`: String with masked recovery email or `None`
- `phoneNumber`: String with phone number or `None`
- `others`: Dictionary with additional metadata or `None`

## Step-by-Step Implementation Examples

### Adding a Module to an Existing Category

To add a new social media checker, create [`holehe/modules/social_media/myservice.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/myservice.py):

```python

# holehe/modules/social_media/myservice.py

import json

async def myservice(email: str, client, out: list):
    """
    Check if email exists on MyService.
    """
    # Replace with actual HTTP logic using client

    out.append({
        "name": "myservice",
        "domain": "myservice.com",
        "rateLimit": False,
        "error": False,
        "exists": False,
        "emailrecovery": None,
        "phoneNumber": None,
        "others": None,
    })

```

Holehe will automatically import `myservice` the next time you run the tool.

### Creating a New Category Folder

For services that do not fit existing categories, create a new subpackage:

```bash
mkdir -p holehe/modules/custom
touch holehe/modules/custom/__init__.py

```

Then add your module at [`holehe/modules/custom/foobar.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/custom/foobar.py):

```python

# holehe/modules/custom/foobar.py

async def foobar(email: str, client, out: list):
    out.append({
        "name": "foobar",
        "domain": "foobar.example",
        "rateLimit": False,
        "error": False,
        "exists": True,
        "emailrecovery": "re***@example.com",
        "phoneNumber": None,
        "others": {"info": "Custom metadata"},
    })

```

Because `import_submodules` recursively walks subdirectories, the new `custom` package and its `foobar` module will be discovered automatically.

## Summary

- Place custom modules inside `holehe/modules/` or its subdirectories (e.g., `holehe/modules/social_media/`).
- Use existing category folders when possible; create new folders with [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) for novel categories.
- Implement an `async def` function with the exact signature `(email, client, out)` and append the required dictionary format to `out`.
- No registration is required—the dynamic importer in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) (lines 36-47) discovers modules automatically.
- Reference existing modules like [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) for production-ready implementation templates.

## Frequently Asked Questions

### Do I need to register my custom module in a configuration file?

No. According to the megadose/holehe source code, the `import_submodules` function in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) automatically imports every Python file under `holehe/modules` at runtime. Simply placing your `.py` file in the correct directory is sufficient.

### Can I organize custom modules in nested subdirectories?

Yes. You can create subpackages (folders containing [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py)) within `holehe/modules/`, and Holehe will recursively discover modules inside them. This allows logical grouping such as [`holehe/modules/enterprise/servicenow.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/enterprise/servicenow.py).

### What happens if my custom module function raises an exception?

Holehe handles exceptions internally. However, your module should set the `error` key to `True` in the output dictionary when catching exceptions, and ideally log the failure details in the `others` field to maintain consistent reporting across all checks.

### Are there naming conventions for custom module files?

The filename should match the function name exactly (e.g., [`twitter.py`](https://github.com/megadose/holehe/blob/main/twitter.py) contains `async def twitter`). Use lowercase with underscores for readability. Avoid naming conflicts with existing modules in the `holehe/modules/` tree to prevent import collisions.