# How Holehe Modules Are Organized by Category: A Technical Guide

> Discover how Holehe modules are organized by category within the megadose/holehe repository. Learn how service checks are grouped for clarity and efficient development.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: deep-dive
- Published: 2026-08-17

---

**Holehe groups all service-specific checks into the `holehe.modules` package, where each sub-directory represents a distinct category (social media, shopping, programming, etc.) and every Python file implements a check for a specific platform.**

Understanding how Holehe modules are organized by category is essential for contributing to the megadose/holehe repository or extending its reconnaissance capabilities. The project uses a clean hierarchical structure that separates services by domain, allowing the core loader to dynamically discover and execute checks without manual registration.

## The `holehe.modules` Package Structure

The repository stores every service check inside the `holehe/modules/` directory. Each immediate sub-directory represents a **category** (or domain), while individual `.py` files within those folders implement concrete platform checks.

For example, the path [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) indicates:
- **Category**: `social_media`
- **Service**: `twitter`

The current categories reflected in the source tree include:

- **transport** – [`blablacar.py`](https://github.com/megadose/holehe/blob/main/blablacar.py) and other travel platforms
- **sport** – [`bodybuilding.py`](https://github.com/megadose/holehe/blob/main/bodybuilding.py) and fitness communities
- **software** – [`office365.py`](https://github.com/megadose/holehe/blob/main/office365.py), [`lastpass.py`](https://github.com/megadose/holehe/blob/main/lastpass.py), [`adobe.py`](https://github.com/megadose/holehe/blob/main/adobe.py)
- **social_media** – [`twitter.py`](https://github.com/megadose/holehe/blob/main/twitter.py), [`instagram.py`](https://github.com/megadose/holehe/blob/main/instagram.py), [`facebook.py`](https://github.com/megadose/holehe/blob/main/facebook.py)
- **shopping** – [`amazon.py`](https://github.com/megadose/holehe/blob/main/amazon.py), [`ebay.py`](https://github.com/megadose/holehe/blob/main/ebay.py), [`vivino.py`](https://github.com/megadose/holehe/blob/main/vivino.py)
- **real_estate** – [`vrbo.py`](https://github.com/megadose/holehe/blob/main/vrbo.py) and property rental services
- **programing** – [`github.py`](https://github.com/megadose/holehe/blob/main/github.py), [`codecademy.py`](https://github.com/megadose/holehe/blob/main/codecademy.py), [`replit.py`](https://github.com/megadose/holehe/blob/main/replit.py)
- **porn** – [`pornhub.py`](https://github.com/megadose/holehe/blob/main/pornhub.py), [`xvideos.py`](https://github.com/megadose/holehe/blob/main/xvideos.py)
- **music** – [`spotify.py`](https://github.com/megadose/holehe/blob/main/spotify.py), [`soundcloud.py`](https://github.com/megadose/holehe/blob/main/soundcloud.py), [`lastfm.py`](https://github.com/megadose/holehe/blob/main/lastfm.py)
- **medias** – [`flickr.py`](https://github.com/megadose/holehe/blob/main/flickr.py), [`ello.py`](https://github.com/megadose/holehe/blob/main/ello.py), [`komoot.py`](https://github.com/megadose/holehe/blob/main/komoot.py)
- **mails** – [`yahoo.py`](https://github.com/megadose/holehe/blob/main/yahoo.py), [`gmail.py`](https://github.com/megadose/holehe/blob/main/gmail.py), [`mail_ru.py`](https://github.com/megadose/holehe/blob/main/mail_ru.py)
- **forum** – [`mybb.py`](https://github.com/megadose/holehe/blob/main/mybb.py), [`blackworldforum.py`](https://github.com/megadose/holehe/blob/main/blackworldforum.py), [`codeigniter.py`](https://github.com/megadose/holehe/blob/main/codeigniter.py)
- **crm** – [`hubspot.py`](https://github.com/megadose/holehe/blob/main/hubspot.py), [`zoho.py`](https://github.com/megadose/holehe/blob/main/zoho.py), [`pipedrive.py`](https://github.com/megadose/holehe/blob/main/pipedrive.py)
- **company** – Reserved package for future corporate services

Each category folder contains an intentionally empty [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py). The loader does not require explicit imports; it discovers modules by traversing the directory tree.

## How the Core Loader Discovers Categories

In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), the `import_submodules` function walks the package tree using `pkgutil.walk_packages` to import every file dynamically:

```python
modules = import_submodules("holehe.modules")
websites = get_functions(modules, args)

```

The `import_submodules` utility preserves the hierarchical path, importing modules as fully-qualified names like `holehe.modules.social_media.twitter`. Subsequently, `get_functions` extracts callable objects whose fully-qualified names contain more than three parts, converting each service file into an asynchronous function ready for execution.

This design means **no registration is required** when adding new services. Placing a new `.py` file in the appropriate category folder automatically includes it in the next run.

## Programmatically Listing Modules by Category

You can inspect the categorical organization at runtime using the same utilities the core employs:

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

# Load every submodule under holehe.modules

all_modules = import_submodules("holehe.modules")

# Retrieve the callable check functions

functions = get_functions(all_modules)

# Print the category and module name

for fn in functions:
    print(f"Category: {fn.__module__}")  # e.g., holehe.modules.social_media.twitter

    print(f"Function: {fn.__name__}")    # e.g., twitter

```

The output reveals the module structure, showing which services belong to which categories based on their import paths.

## Running Individual Category Checks

To execute a specific check from a category manually, import the function directly from its category path and run it asynchronously:

```python
import httpx
import trio
from holehe.modules.social_media.twitter import twitter

async def run_check(email):
    async with httpx.AsyncClient() as client:
        out = []
        await twitter(email, client, out)
        print(out)

# Execute the check

trio.run(run_check, "example@example.com")

```

This pattern works for any service, whether from `holehe.modules.shopping.amazon` or `holehe.modules.programing.github`.

## Extending Categories with New Services

Adding coverage for a new platform requires only two steps:

1. Identify the appropriate category folder (or create a new one if the domain is unique)
2. Place a Python file implementing the async check function into that folder

The core loader in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) will automatically detect the new file on the next execution, preserving the categorical organization without modifying the main program logic.

## Summary

- **Holehe modules are organized by category** through sub-directories under `holehe/modules/`, where folder names represent service domains (social_media, shopping, programing, etc.)
- **Dynamic loading** occurs via `import_submodules` in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), which walks the package tree and imports every module without explicit registration
- **Individual checks** reside as Python files within category folders (e.g., [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py))
- **Empty [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) files** mark directories as Python packages while allowing the loader to discover contents automatically
- **Extensibility** is built-in: adding a new service requires only placing a file in the correct category directory

## Frequently Asked Questions

### How does Holehe load modules from different categories?

Holehe uses `pkgutil.walk_packages` in the `import_submodules` function (located in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)) to recursively discover all Python files under `holehe/modules/`. It imports each file while preserving the hierarchical path structure, then `get_functions` extracts the callable check objects. This dynamic approach eliminates the need for a central registry or manual imports when new categories or services are added.

### Where are the social media checks located in Holehe?

Social media checks reside in the `holehe/modules/social_media/` directory. Specific implementations include [`twitter.py`](https://github.com/megadose/holehe/blob/main/twitter.py), [`instagram.py`](https://github.com/megadose/holehe/blob/main/instagram.py), and [`facebook.py`](https://github.com/megadose/holehe/blob/main/facebook.py). Each file contains an async function matching the filename (e.g., `async def twitter(...)`), which the core loader executes when checking for account existence on those platforms.

### Can I add my own custom category to Holehe?

Yes. Create a new sub-directory under `holehe/modules/` with the desired category name (e.g., `holehe/modules/crypto/`), include an empty [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) file, and place your service check files inside. The next time Holehe runs, `import_submodules` will automatically detect the new category and load any Python files it contains, making them available for execution alongside existing categories.

### Why are the [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) files empty in category folders?

The empty [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) files serve only as package markers to designate directories as Python packages, enabling `pkgutil.walk_packages` to traverse them. Since [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) discovers modules by walking the filesystem rather than importing specific names, no initialization code or explicit imports are required in these files. This keeps the category structure clean and minimizes maintenance when adding or removing services.