# How to Add a New Social Media Module to holehe: A Step-by-Step Guide

> Learn how to add a new social media module to holehe with this step-by-step guide. Discover how to create async coroutines, implement metadata, and register your module efficiently.

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

---

**To add a new social media module to holehe, create an async coroutine in the `holehe/modules/medias/` directory that accepts `email`, `client`, and `out` parameters, implement the required metadata structure, and register the function in the category's [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) file.**

holehe is an open-source email OSINT tool that checks for account existence across hundreds of platforms using an extensible plugin architecture. Its modular design allows developers to add support for new services by implementing standardized async functions that the core engine automatically discovers. This guide walks you through the exact process to add a new social media module to holehe, referencing the actual source code structure from the megadose/holehe repository.

## Understanding the Module Architecture in holehe

holehe employs a dynamic plugin system where each service is implemented as a standalone async function. The central engine in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) discovers available modules by importing the `MODULES` dictionary exposed through [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) files across category folders. Each module follows a strict contract: it receives an email string, an `httpx.AsyncClient` instance, and a shared output list, then appends a standardized result dictionary containing nine mandatory keys.

## Step-by-Step Guide to Adding a Social Media Module

### Choose the Correct Category Directory

Social media platforms belong in `holehe/modules/medias/`. If your target service requires a new sub-category, create a dedicated folder and ensure it exposes a `MODULES` list via its own [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) so the core loader can discover it.

### Create the Module File with the Standard Async Signature

Create a Python file (e.g., [`instagram.py`](https://github.com/megadose/holehe/blob/main/instagram.py)) inside the chosen directory. Define a single coroutine with this exact signature:

```python
async def instagram(email, client, out):

```

The `client` parameter provides a reusable `httpx.AsyncClient` for HTTP requests, while `out` is a list where you must append the result dictionary.

### Implement the Coroutine with Required Metadata

First, declare the static metadata variables: `name`, `domain`, `method`, and `frequent_rate_limit`. For request headers, reuse the `ua` helper imported from [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py), following the pattern established in existing modules like **Blablacar** ([`holehe/modules/transport/blablacar.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/transport/blablacar.py)).

Wrap all HTTP calls in a `try/except` block to catch connectivity or rate-limit errors. Append a dictionary to the `out` list containing these mandatory keys: `name`, `domain`, `method`, `frequent_rate_limit`, `rateLimit`, `exists`, `emailrecovery`, `phoneNumber`, and `others`. Set `rateLimit=True` when exceptions occur.

### Register the Module in __init__.py

Edit [`holehe/modules/medias/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/medias/__init__.py) to import your function and append it to the `MODULES` list:

```python
from .instagram import instagram
MODULES.append(instagram)

```

The core loader iterates over this list in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) and invokes each coroutine during execution.

### Test Your Implementation

Run the project's test suite using `python -m unittest` to verify that your new module integrates correctly without breaking existing functionality.

## Complete Implementation Example

The following example demonstrates a minimal Instagram module following the holehe architectural pattern:

```python
from holehe.core import *
from holehe.localuseragent import *

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

    headers = {
        "User-Agent": random.choice(ua["browsers"]["firefox"]),
        "Accept": "application/json",
        "Content-Type": "application/json",
        "X-Requested-With": "XMLHttpRequest",
    }

    try:
        resp = await client.get(
            f"https://www.instagram.com/web/accounts/web_signup_ajax/",
            params={"email": email},
            headers=headers,
        )
        data = resp.json()
    except Exception:
        out.append(
            {
                "name": name,
                "domain": domain,
                "method": method,
                "frequent_rate_limit": frequent_rate_limit,
                "rateLimit": True,
                "exists": False,
                "emailrecovery": None,
                "phoneNumber": None,
                "others": None,
            }
        )
        return None

    exists = data.get("email")
    out.append(
        {
            "name": name,
            "domain": domain,
            "method": method,
            "frequent_rate_limit": frequent_rate_limit,
            "rateLimit": False,
            "exists": bool(exists),
            "emailrecovery": None,
            "phoneNumber": None,
            "others": None,
        }
    )

```

Register the module in [`holehe/modules/medias/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/medias/__init__.py):

```python
from .instagram import instagram
MODULES.append(instagram)

```

## Summary

- **Create async function**: Define `async def servicename(email, client, out)` in the appropriate subdirectory under `holehe/modules/`.
- **Implement metadata**: Include `name`, `domain`, `method`, and `frequent_rate_limit` variables at the function start.
- **Handle errors**: Wrap HTTP calls in `try/except` blocks and set `rateLimit=True` when catching exceptions.
- **Standardize output**: Append dictionaries containing all nine required keys (`name`, `domain`, `method`, `frequent_rate_limit`, `rateLimit`, `exists`, `emailrecovery`, `phoneNumber`, `others`) to the `out` list.
- **Register module**: Import and append the function to `MODULES` in the category's [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) file.
- **Use helpers**: Import `ua` from [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py) for realistic user-agent headers, as demonstrated in [`holehe/modules/transport/blablacar.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/transport/blablacar.py).

## Frequently Asked Questions

### What is the exact function signature required for a holehe module?

The function must be an async coroutine named after the service, accepting three parameters: `email` (string), `client` (httpx.AsyncClient), and `out` (list). The loader in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) calls each module with these exact arguments during the OSINT enumeration process.

### How does holehe automatically discover new modules?

The core engine imports the `MODULES` list from package [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) files throughout the `holehe/modules/` directory tree. When you append your coroutine to `MODULES` in [`holehe/modules/medias/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/medias/__init__.py), the discovery system automatically includes it in the execution cycle without requiring central registry edits.

### What fields are mandatory in the result dictionary appended to the out list?

Every result must contain nine specific keys: `name`, `domain`, `method`, `frequent_rate_limit`, `rateLimit`, `exists`, `emailrecovery`, `phoneNumber`, and `others`. The `exists` field indicates account presence as a boolean, while `rateLimit` signals whether the service blocked the request.

### How should I handle rate limiting in my social media module?

Wrap all external HTTP requests in a `try/except` block. If an exception occurs or the response indicates throttling, immediately append a result with `rateLimit=True` and `exists=False`, then return. Refer to lines 30-38 of [`holehe/modules/transport/blablacar.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/transport/blablacar.py) for the standard error-handling pattern used across the codebase.