How to Add a Custom Module for a New Website to the Holehe Framework

To add a custom module for a new website to Holehe, create an async Python function with the signature async def <site>(email, client, out) inside the holehe/modules/ package hierarchy; the framework's dynamic import system automatically discovers and runs it at startup.

Holehe uses a dynamic import system to discover and execute every site-specific check at runtime. When Holehe launches, import_submodules("holehe.modules") traverses the package tree in holehe/core.py, imports every submodule, and extracts public functions via get_functions. This architecture makes extending Holehe straightforward—no central registry or configuration file updates are required.

Understanding the Module Structure

Holehe organizes website checks by category. The holehe/modules/ directory contains subdirectories like social_media, forum, software, and others. Each category holds Python files implementing checks for specific sites.

The core mechanism lives in holehe/core.py. The import_submodules function walks the entire package hierarchy, making any new module file immediately available without explicit registration.

Required Function Signature

Every Holehe module must define a single public async function with this exact signature:

async def <site>(email, client, out):

The parameters are:

  • email — The target email address being investigated
  • client — An httpx.AsyncClient instance provided by the core for making HTTP requests
  • out — A list to which you append result dictionaries

Result Dictionary Format

Your function must populate out with a dictionary following the established schema. In holehe/core.py, the get_functions utility extracts these functions, and the orchestration code processes the standardized output.

The required result structure:

out.append({
    "name": name,                   # Internal identifier (same as function name)

    "domain": domain,               # Human-readable domain (e.g., "example.com")

    "method": method,               # Usually "register"

    "frequent_rate_limit": False,
    "rateLimit": False,             # Set True when rate-limit response detected

    "exists": exists,               # True if email is registered on the site

    "emailrecovery": None,          # Optional recovered email address

    "phoneNumber": None,            # Optional recovered phone number

    "others": None                  # Additional data (e.g., full name)

})

Step-by-Step Implementation

Step 1: Choose the Appropriate Category

Navigate to holehe/modules/ and select or create the relevant category folder. Existing categories include social_media, forum, software, transport, shopping, and others.

Step 2: Create the Module File

Create a new Python file named after the website. For example, to add support for example.com under social media:


holehe/modules/social_media/example.py

Step 3: Implement the Async Check

Use this template adapted from existing modules like holehe/modules/social_media/twitter.py:


# File: holehe/modules/social_media/example.py

from holehe.core import *
from holehe.localuseragent import *

async def example(email, client, out):
    name = "example"
    domain = "example.com"
    method = "register"
    frequent_rate_limit = False

    try:
        # Replace with actual endpoint that tests email availability

        req = await client.get(
            "https://api.example.com/v1/users/email_available",
            params={"email": email},
            headers={"User-Agent": ua}
        )
        
        # Parse response—adjust logic based on actual API behavior

        exists = not req.json().get("available", True)

        out.append({
            "name": name,
            "domain": domain,
            "method": method,
            "frequent_rate_limit": frequent_rate_limit,
            "rateLimit": False,
            "exists": exists,
            "emailrecovery": None,
            "phoneNumber": None,
            "others": None,
        })
    except Exception:
        # Handle network errors or rate limits gracefully

        out.append({
            "name": name,
            "domain": domain,
            "method": method,
            "frequent_rate_limit": frequent_rate_limit,
            "rateLimit": True,
            "exists": False,
            "emailrecovery": None,
            "phoneNumber": None,
            "others": None,
        })

Step 4: Optional — Update __init__.py

Most category folders include an __init__.py with an __all__ list. While not strictly required for Holehe's dynamic import system, adding your module name enables explicit imports:


# holehe/modules/social_media/__init__.py

__all__ = [
    "twitter",
    "example",  # Add your module here

    # ... other modules

]

Testing Your Custom Module

No additional command-line flags are needed. Simply run Holehe normally:

holehe user@example.com

Your new check appears automatically in the output. The import_submodules call in holehe/core.py loads every .py file under holehe/modules/ recursively, making your module available immediately.

Error Handling Best Practices

Follow the pattern established in launch_module and existing site implementations:

  • Wrap all network operations in try/except Exception blocks
  • Set rateLimit: True when catching exceptions that likely indicate rate limiting
  • Always append a result to out — never leave the output list empty

This ensures Holehe continues operating even when individual checks fail, and users receive consistent feedback about which sites encountered problems.

Key Files in the Holehe Source

File Purpose
holehe/core.py Core driver containing import_submodules and orchestration logic
holehe/modules/social_media/twitter.py Reference implementation showing production-grade error handling and response parsing
holehe/modules/<category>/<your_module>.py Your custom module implementing the new website check
holehe/localuseragent.py User-agent strings available for request headers

Summary

  • Holehe automatically discovers modules through import_submodules("holehe.modules") in holehe/core.py
  • Create a file in the appropriate category under holehe/modules/
  • Define one async function with signature async def <name>(email, client, out)
  • Append standardized result dictionaries to the out parameter
  • No registration step required — save the file and run holehe

Frequently Asked Questions

Can I add a module without modifying the main Holehe package?

Yes, if you install Holehe in development mode with pip install -e ., your custom modules in the local holehe/modules/ hierarchy are loaded alongside the core modules. For fully external modules, you would need to fork the repository, as the dynamic import system is hardcoded to scan holehe.modules.

What HTTP client should I use inside my module?

Use the client parameter provided to your function — it is an httpx.AsyncClient instance managed by Holehe. This ensures connection pooling, timeout handling, and retry policies remain consistent across all checks. Do not create your own client instances.

How do I determine if an email is registered on a site?

Each site exposes registration flows differently. Common techniques include: checking email availability during signup, testing password reset flows, or examining API responses for profile existence indicators. Study holehe/modules/social_media/twitter.py and similar modules to see how existing implementations detect registration status for specific platforms.

Why does my new module not appear in the output?

Verify that: (1) your Python file is saved in a subdirectory of holehe/modules/, (2) the function name matches the filename, (3) the function is async, and (4) the signature exactly matches async def name(email, client, out). Run with debugging enabled to see import errors: python -c "from holehe.core import import_submodules; import_submodules('holehe.modules')".

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 →