# How to Add a Custom Module to Holehe: Complete Developer Guide

> Learn how to add a custom module to Holehe. Follow our developer guide to create a Python module, implement its methods, and integrate it seamlessly into Holehe.

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

---

**To add a custom module to Holehe, create a Python file implementing a class with a `NAME` attribute and a `run(self, email)` method that returns a status dictionary, place it in the appropriate `holehe/modules/` subdirectory, and register it by importing the class in that sub-package's [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py).**

Holehe is an open-source email reconnaissance framework that checks whether an address is registered across hundreds of online services. Adding a custom module to Holehe allows you to extend its coverage to new platforms by conforming to its standardized plugin architecture, which the core engine in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) uses to automatically discover and execute service checks.

## Understanding the Holehe Module Architecture

### Module Location and Structure

All service modules reside within the `holehe/modules/` directory, organized into sub-packages by service category. The repository includes folders such as `social_media/`, `shopping/`, and `crm/`, each containing individual Python files representing specific platforms. When you add a custom module to Holehe, you must place the file in the appropriate category folder or create a new sub-package if the service defines a new vertical.

### The Standard Interface

Every module must implement a consistent interface so that [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) can execute it generically. The required contract includes:

- A **class-level `NAME` attribute** (string) that identifies the service in output reports
- A **`run(self, email)` method** that accepts an email string and returns a dictionary containing:
  - `"status"`: Boolean indicating whether the account exists (True) or not (False)
  - `"message"`: Human-readable string describing the result or error

### Automatic Discovery Mechanism

The framework uses [`holehe/modules/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/__init__.py) to walk through sub-packages and import all module classes into an internal registry. When a user runs `holehe -l <email>`, the core engine iterates this registry and invokes each module's `run()` method asynchronously, aggregating results into the final report.

## Step-by-Step Guide to Adding a Custom Module

1. **Select the category** – Choose the appropriate sub-package under `holehe/modules/` (e.g., `social_media/`). Create a new folder with an [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) if the category does not exist.

2. **Create the module file** – Add a new Python file within the chosen directory, such as [`holehe/modules/social_media/myservice.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/myservice.py).

3. **Implement the interface** – Define a class with the `NAME` attribute and `run(self, email)` method returning the required dictionary format.

4. **Register the class** – Edit the [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) in the same directory to import your class: `from .myservice import MyService`.

5. **Verify integration** – Run `holehe -l test@example.com` and confirm your module appears in the output and executes correctly.

## Custom Module Implementation Example

The following example follows the same pattern as the built-in Facebook module. Save this as [`holehe/modules/social_media/custom_platform.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/custom_platform.py):

```python
import requests
from holehe.modules.base import BaseModule  # Optional inheritance for shared utilities

class CustomPlatform(BaseModule):
    """
    Check email registration status on CustomPlatform.
    """
    NAME = "CustomPlatform"

    def run(self, email: str) -> dict:
        """
        Query CustomPlatform API to verify if email is registered.

        Parameters
        ----------
        email : str
            The email address to verify.

        Returns
        -------
        dict
            Dictionary with keys:
            - status (bool): True if account exists, False otherwise
            - message (str): Description of result or error
        """
        try:
            response = requests.get(
                f"https://api.customplatform.com/v1/users/check?email={email}",
                timeout=10,
                headers={"User-Agent": "Holehe/1.0"}
            )
            
            if response.status_code == 200:
                data = response.json()
                exists = data.get("user_exists", False)
                return {
                    "status": exists,
                    "message": "Account found" if exists else "No account"
                }
            elif response.status_code == 404:
                return {"status": False, "message": "Account not found"}
            else:
                return {
                    "status": False,
                    "message": f"Unexpected HTTP {response.status_code}"
                }
        except requests.RequestException as exc:
            return {"status": False, "message": f"Network error: {str(exc)}"}

```

## Registering Your Module

After creating the file, you must expose the class to the discovery mechanism. Modify [`holehe/modules/social_media/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/__init__.py) to include your import:

```python

# holehe/modules/social_media/__init__.py

from .facebook import Facebook
from .instagram import Instagram
from .custom_platform import CustomPlatform  # Add this line

```

The top-level [`holehe/modules/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/__init__.py) automatically imports all sub-packages, so no additional changes are required at the root level if you placed your module within an existing category.

## Testing Your Implementation

Execute Holehe with a verbose flag to verify your module loads and runs:

```bash
holehe -l test@example.com

```

Look for your `NAME` value in the output table. If the module fails to appear:

- Confirm the file resides in `holehe/modules/<category>/`
- Verify the class name matches the import statement in [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py)
- Ensure `run()` returns the exact dictionary structure with `status` and `message` keys
- Check that `NAME` is defined as a class attribute, not an instance attribute

## Summary

- **Location**: Place custom modules in `holehe/modules/` subdirectories (e.g., `social_media/`, `shopping/`)
- **Interface**: Implement a class with `NAME` attribute and `run(self, email)` returning `{"status": bool, "message": str}`
- **Registration**: Import the class in the sub-package's [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) to enable automatic discovery
- **Core Integration**: [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) builds the execution registry from [`holehe/modules/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/__init__.py) and invokes each module's `run()` method during scans
- **Error Handling**: Modules should catch exceptions and return `status: False` with descriptive messages rather than raising errors

## Frequently Asked Questions

### Where should I place my custom module in the Holehe repository?

Place your Python file in the appropriate category folder under `holehe/modules/`, such as `holehe/modules/social_media/` for social platforms. If the service category does not exist, create a new directory with an empty [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) file to make it a proper Python package, then place your module inside.

### What methods and attributes are required in a Holehe custom module class?

Your class must define a `NAME` class attribute (a string identifier used in reports) and a `run(self, email)` method that accepts an email string parameter and returns a dictionary containing `"status"` (a boolean indicating account existence) and `"message"` (a human-readable result string). These specific names and types are required for the core engine in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) to process your results correctly.

### How does Holehe discover modules automatically without manual registry updates?

The [`holehe/modules/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/__init__.py) script walks through all sub-packages during initialization. Each sub-package's [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) (such as [`holehe/modules/social_media/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/__init__.py)) imports its module classes explicitly. When you add an import statement there, the top-level loader registers the class, making it available to the execution loop in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) without modifying the core code itself.

### Can I distribute a Holehe module as a standalone package without modifying the core repository?

Currently, Holehe requires modules to be integrated directly into the `holehe/modules/` directory structure and registered via the sub-package [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) files. The framework does not support external plugin directories or entry-point-based discovery; to add a custom module to Holehe, you must place files within the source tree and ensure they are imported by the existing package initialization system.