# How Holehe Implements User-Agent Rotation: A Deep Dive into the Source Code

> Discover how Holehe implements User-Agent rotation by randomly selecting browser fingerprints from its source code for each HTTP request. Understand its mimicry techniques.

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

---

**Holehe rotates User-Agent strings by randomly selecting from a centralized JSON dictionary of browser fingerprints stored in [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py), then applying `random.choice()` on every HTTP request to mimic real browser traffic.**

This email reconnaissance tool hides its automated nature by varying the `User-Agent` header for each service check it performs. Understanding how User-Agent rotation works in Holehe helps security researchers and developers implement similar evasion techniques in their own tools.

## Central User-Agent Store in localuseragent.py

All supported browsers and their fingerprint strings are defined once in [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py). This file contains a JSON-encoded dictionary named **`ua`** where each key maps to a list of real-world User-Agent strings.

The structure organizes browsers under a `browsers` key:

```python

# Simplified structure of holehe/localuseragent.py

ua = {
    "browsers": {
        "chrome": [
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.0...",
            # ... dozens more Chrome variants

        ],
        "firefox": [
            "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101...",
            # ... Firefox variants

        ],
        "iOS": [
            "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X)...",
            # ... mobile Safari strings

        ],
        "safari": [
            # ... Safari desktop strings

        ]
    }
}

```

This centralized approach means updates—adding new UA strings or browser categories—propagate automatically to every module without code duplication.

## Import Pattern Across Service Modules

Individual modules that interact with external services import this dictionary directly. The pattern appears consistently across Holehe's codebase:

```python
from holehe.localuseragent import ua
import random

```

For example, in [`holehe/modules/social_media/facebook.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/facebook.py), the module imports `ua` at the top level, making the full collection available for all requests to Facebook's endpoints.

## Random Selection Per Request

Before each request, Holehe builds a headers dictionary and fills the `User-Agent` entry with `random.choice()` from the appropriate browser list:

```python
headers = {
    "User-Agent": random.choice(ua["browsers"]["chrome"]),
    "Accept": "application/json, text/plain, */*",
    "Origin": "https://www.facebook.com",
    "DNT": "1",
}

```

By calling `random.choice` every time a request executes, Holehe ensures consecutive calls use different UA strings. This pattern repeats across virtually every module—Instagram, Twitter, Reddit, Tumblr, Snapchat, and more.

## Practical Code Examples

### Selecting a Random Chrome User-Agent

```python
from holehe.localuseragent import ua
import random

# Choose a Chrome UA each time the function runs

chrome_ua = random.choice(ua["browsers"]["chrome"])
print(chrome_ua)

```

### Asynchronous Request with UA Rotation (Facebook Module)

```python
import random
from holehe.localuseragent import ua

async def facebook(email, client, out):
    headers = {
        "User-Agent": random.choice(ua["browsers"]["chrome"]),
        "Accept": "application/json, text/plain, */*",
        "Accept-Encoding": "gzip, deflate",
        "Referer": "https://www.facebook.com/login/identify",
    }
    # Request logic continues...

```

### Browser-Agnostic Rotation Function

```python
def random_ua(browser: str = "chrome") -> str:
    """
    Return a random User-Agent string for the requested browser.
    Accepted values: 'chrome', 'firefox', 'iOS', 'safari', ...
    """
    return random.choice(ua["browsers"][browser])

# Example usage

headers = {"User-Agent": random_ua("firefox")}

```

## Key Files Implementing User-Agent Rotation

| File | Role |
|------|------|
| [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py) | Central repository of browser-specific User-Agent strings (`ua`) |
| [`holehe/modules/social_media/facebook.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/facebook.py) | Demonstrates import of `ua` and random Chrome selection |
| [`holehe/modules/social_media/instagram.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/instagram.py) | Uses Chrome UA rotation for Instagram checks |
| [`holehe/modules/social_media/tumblr.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/tumblr.py) | Shows rotation with the `iOS` UA list |
| [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) | Follows same pattern for Twitter/X requests |
| [`holehe/modules/social_media/snapchat.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/snapchat.py) | Random UA selection for Snapchat endpoints |
| [`holehe/modules/transportation/blablacar.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/transportation/blablacar.py) | Cross-domain reuse of the rotation pattern |

## Why This User-Agent Rotation Strategy Works

- **Variability**: Real browsers send many different UA strings; rotating them mimics this natural variance across sessions and requests.
- **Simplicity**: The single central list in [`localuseragent.py`](https://github.com/megadose/holehe/blob/main/localuseragent.py) keeps maintenance trivial—one file update affects all modules.
- **Low overhead**: `random.choice` operates in O(1) time, adding negligible latency to each HTTP request.

## Summary

- Holehe implements **User-Agent rotation** through a centralized dictionary in [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py)
- The **`ua`** variable contains browser-specific lists of realistic fingerprint strings
- Every module imports `ua` and calls **`random.choice()`** before each request
- This lightweight pattern appears consistently across **social media**, **transportation**, and other service modules
- The O(1) selection performance ensures no meaningful slowdown in asynchronous operation

## Frequently Asked Questions

### How does Holehe avoid using the same User-Agent repeatedly?

Holehe calls `random.choice()` fresh for every HTTP request rather than caching a selection. This means even rapid sequential requests to the same service receive different UA strings, preventing fingerprinting based on static headers.

### What browsers does Holehe's User-Agent rotation support?

According to the source in [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py), the `ua` dictionary includes `chrome`, `firefox`, `iOS`, and `safari` keys. Individual modules select the browser type most appropriate for their target service—Chrome for desktop sites, iOS for mobile-heavy platforms.

### Can I add custom User-Agent strings to Holehe?

Yes. Since [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py) uses a plain Python dictionary structure, you can append strings to any browser list. New entries automatically become available to all modules that import `ua` without requiring code changes elsewhere.

### Does User-Agent rotation completely prevent blocking?

No single technique guarantees evasion. However, as implemented in megadose/holehe, User-Agent rotation combines with other request randomization (headers, timing) to reduce bot detection probability. The source code shows this is one layer in a broader operational security strategy.