# How User-Agent Strings Are Managed in Holehe Modules: Centralized JSON and Per-Module Randomization

> Discover how Holehe modules manage User-Agent strings using a centralized JSON dictionary for random sampling. Learn to mimic realistic browser fingerprints effectively.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: internals
- Published: 2026-08-23

---

**Holehe manages User-Agent strings through a centralized JSON dictionary in [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py) that modules import via wildcard and sample randomly to mimic realistic browser fingerprints.**

The open-source OSINT tool **Holehe** (maintained by megadose) takes a deliberate approach to HTTP header management. Rather than hardcoding User-Agent strings across its ~800 modules, the project centralizes all values in a single source file. This design ensures consistency while allowing each module to randomize requests and blend in with legitimate traffic.

## Centralized User-Agent Storage in localuseragent.py

All User-Agent strings live in **[`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py)**, which defines a JSON object named **`ua`** containing browser-family groupings.

```python

# holehe/localuseragent.py

import json

ua = json.loads('''{
  "browsers": {
    "chrome": [
      "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
      "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36",
      …
    ],
    "firefox": [
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0",
      …
    ],
    "safari": [
      "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Safari/605.1.15",
      …
    ],
    "iOS": [
      "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1",
      …
    ]
  }
}''')

```

The structure supports four browser families: **`chrome`**, **`firefox`**, **`safari`**, and **`iOS`**. Each contains multiple realistic strings representing different platforms and versions.

## Module-Level Implementation Pattern

Every Holehe module follows the same three-step pattern for User-Agent management.

### Step 1: Wildcard Import

Modules import the entire `localuseragent` namespace:

```python

# Example: holehe/modules/transport/blablacar.py

from holehe.localuseragent import *
import random

```

This wildcard approach gives direct access to `ua` without repetitive import statements across hundreds of files.

### Step 2: Random Selection

Modules use **`random.choice()`** to select from their preferred browser family:

```python

# holehe/modules/transport/blablacar.py (line 12)

headers = {
    'User-Agent': random.choice(ua["browsers"]["firefox"]),
    ...
}

```

Each request thus carries a different User-Agent, preventing signature-based blocking.

### Step 3: Request Construction

The selected string joins other headers in the final request configuration.

## Browser Family Selection Strategy

Holehe modules strategically choose browser families to match expected client behavior on target services:

| Module Category | Typical Browser Choice | Rationale |
|-----------------|------------------------|-----------|
| Software/tech services | **Chrome** | Matches dominant desktop browser market share |
| Social media platforms | **Firefox** | Diversifies fingerprint; avoids over-representing Chrome |
| Mobile-centric services | **iOS** | Mimics authentic mobile app traffic |

## Advanced Pattern: Persistent User-Agent Variables

Some modules deviate from inline `random.choice()` calls to reuse a single User-Agent across multiple related requests. The Tumblr module demonstrates this technique:

```python

# holehe/modules/social_media/tumblr.py (lines 11-20)

usrag = random.choice(ua["browsers"]["iOS"])
...
"User-Agent": usrag

```

By storing the randomized iOS UA in **`usrag`**, the module maintains session consistency—critical for services that correlate consecutive requests from the same "device."

## Complete Implementation Examples

### Standard Chrome Selection

```python
from holehe.localuseragent import *
import random, requests

def check_service(email):
    url = "https://example.com/api"
    headers = {
        "User-Agent": random.choice(ua["browsers"]["chrome"]),
        "Accept": "application/json",
    }
    resp = requests.get(url, headers=headers)
    return resp.json()

```

### iOS Session Persistence (Tumblr-Style)

```python
from holehe.localuseragent import *
import random, requests

def tumblr_profile(username):
    usrag = random.choice(ua["browsers"]["iOS"])
    url = f"https://www.tumblr.com/api/read/json?type=post&filter=raw&num=10&username={username}"
    headers = {"User-Agent": usrag}
    resp = requests.get(url, headers=headers)
    return resp.json()

```

## Key Source Files

- **[`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py)** — Central JSON dictionary of browser-specific User-Agent strings
- **[`holehe/modules/transport/blablacar.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/transport/blablacar.py)** — Standard Firefox UA randomization
- **[`holehe/modules/social_media/tumblr.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/tumblr.py)** — Custom `usrag` variable with iOS persistence

## Summary

- **Single source of truth**: The `ua` dictionary in [`localuseragent.py`](https://github.com/megadose/holehe/blob/main/localuseragent.py) centralizes all User-Agent strings
- **Wildcard imports** provide clean module-level access without import proliferation
- **Per-request randomization** via `random.choice()` prevents fingerprinting
- **Strategic browser selection** matches target service expectations
- **Session persistence variables** support multi-request workflows when needed

## Frequently Asked Questions

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

Yes. Edit [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py) and append strings to the appropriate browser list within the `ua` JSON structure. All modules will automatically access new entries through the existing wildcard import pattern.

### Why does Holehe use wildcard imports instead of explicit imports?

Wildcard imports from `localuseragent` eliminate repetitive `import` statements across ~800 modules. The trade-off—namespace pollution—is acceptable because `ua` is the only exported name and collision risk is minimal in this controlled codebase.

### How does random User-Agent selection improve OSINT effectiveness?

Services tracking request signatures see varied browser fingerprints instead of a single automated pattern. This reduces detection likelihood and prevents IP-based blocking triggered by consistent header signatures.

### What happens if a module doesn't specify a browser family?

All modules explicitly select a family (`chrome`, `firefox`, `safari`, or `iOS`). The codebase contains no fallback default; each module author deliberately chooses based on the target service's typical user base.