# How Holehe's CSV Export Works and What Data It Includes

> Discover how Holehe's CSV export works with the -C flag. Learn what OSINT data it includes in a timestamped UTF-8 file. Understand the core export function.

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

---

**Holehe's CSV export is triggered by the `-C/--csv` flag and writes all OSINT scan results to a timestamped UTF-8 file using the `export_csv()` function in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py).**

When running email reconnaissance with holehe, you can persist findings to a structured CSV file for further analysis, reporting, or integration with other tools. According to the megadose/holehe source code, this export mechanism is lightweight yet comprehensive, capturing every data point returned by the 120+ supported modules.

## How to Enable CSV Export in Holehe

### Command-Line Usage

Pass the `-C` or `--csv` flag when executing holehe from the terminal:

```bash
$ holehe victim@example.com -C

```

The tool executes all modules, aggregates results, and writes them to a filename with the pattern `holehe_<timestamp>_<email>_results.csv`. Upon completion, holehe prints the full path to the exported file.

### Where the Flag Is Parsed

The argument is defined in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) at lines 192-194:

```python
parser.add_argument("-C","--csv", default=False, required=False,
                    dest="csvoutput", action='store_true',
                    help="Create a csv with the results")

```

When `args.csvoutput` evaluates to `True`, the main execution flow calls `export_csv(data, args, email)` immediately after all modules complete.

## The export_csv Function: Implementation Details

The core logic resides in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) at lines 54-64:

```python
def export_csv(data, args, email):
    if args.csvoutput:
        timestamp = int(time.time())
        filename = f"holehe_{timestamp}_{email}_results.csv"
        with open(filename, 'w', newline='', encoding='utf-8') as f:
            fc = csv.DictWriter(f, fieldnames=data[0].keys())
            fc.writeheader()
            fc.writerows(data)
        print(f"All results have been exported to {filename}")

```

Key implementation characteristics:

- **Timestamped filenames** prevent collisions when scanning the same target multiple times
- **`newline=''`** ensures Windows compatibility by suppressing extra blank lines
- **`csv.DictWriter`** maps dictionary keys directly to CSV columns
- **UTF-8 encoding** handles international characters in email addresses and response data

## What Data Fields the CSV Contains

Each row in the exported CSV represents one module's execution result. The column headers derive dynamically from `data[0].keys()`, ensuring the CSV structure always matches the internal data format.

| Field | Description | Example Values |
|-------|-------------|--------------|
| `name` | Internal module identifier | `twitter`, `gmail`, `adobe` |
| `domain` | Target service domain | `twitter.com`, `adobe.com` |
| `rateLimit` | Boolean indicating throttling status | `True`, `False` |
| `exists` | Boolean indicating account discovery | `True` (found), `False` (not found) |
| `emailrecovery` | Obfuscated recovery email | `v***@gmail.com`, `None` |
| `phoneNumber` | Obfuscated recovery phone | `+1 ***-***-1234`, `None` |
| `others` | Miscellaneous metadata | Full name, signup date, location, etc. |

These fields are populated by individual modules in `holehe/modules/` and collected into the `data` list passed to `export_csv()`.

## Programmatic CSV Export Example

You can also invoke `export_csv()` directly when embedding holehe in Python applications:

```python
import httpx
import trio
from holehe.core import export_csv, get_functions, import_submodules

async def scan_and_export(email: str):
    # Load all OSINT modules

    modules = import_submodules("holehe.modules")
    functions = get_functions(modules)
    
    # Collect results from all modules

    results = []
    async with httpx.AsyncClient(timeout=10) as client:
        for func in functions:
            await func(email, client, results)
    
    # Export to CSV using minimal args object

    class Args:
        csvoutput = True
    
    export_csv(results, Args(), email)

# Execute the scan

trio.run(scan_and_export, "target@example.com")

```

This approach mirrors the CLI behavior while allowing custom result processing before export.

## CSV vs. Terminal Output: Key Differences

- **Terminal output** renders results as formatted tables with color-coded status indicators
- **CSV export** preserves the complete raw dataset including all metadata fields, even when `exists=False`
- **CSV files** include rate-limited and failed attempts, giving you visibility into data quality and coverage gaps

## Summary

- Holehe's CSV export is implemented in the `export_csv()` function within [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) (lines 54-64)
- Activation requires the `-C/--csv` flag parsed at lines 192-194 of the same file
- Output filenames follow the pattern `holehe_<timestamp>_<email>_results.csv`
- Seven standard fields capture module results: `name`, `domain`, `rateLimit`, `exists`, `emailrecovery`, `phoneNumber`, and `others`
- The `csv.DictWriter` class generates headers dynamically from result dictionary keys

## Frequently Asked Questions

### Does holehe append to existing CSV files or overwrite them?

Holehe creates a **new file with a Unix timestamp** on every export, so existing files are never modified or overwritten. This design ensures historical scan preservation without manual file management.

### What happens if no accounts are found—will the CSV still be created?

Yes. The CSV is generated regardless of findings, containing rows where `exists=False` for all queried services. This negative data is valuable for confirming account absence across platforms.

### Can I customize the CSV filename or output directory?

The current implementation does not expose filename or path configuration through CLI arguments. To customize output locations, use the programmatic API and modify the `filename` variable in `export_csv()` before the file open operation.

### Why does the CSV contain `None` values for some fields?

`None` appears when a service either does not provide recovery contact information or the module failed to extract it. The `others` field is particularly variable—populated only when modules return additional metadata beyond the standard schema.