How `localuseragent` Selects Realistic User Agents in holehe for Undetectable OSINT Requests

The localuseragent module in megadose/holehe maintains a curated JSON dictionary of realistic browser User-Agent strings that each OSINT module randomly samples to mimic genuine web traffic.

The holehe/localuseragent.py file serves as the central repository for HTTP User-Agent headers across the entire holehe OSINT framework. Rather than hardcoding browser fingerprints in each module, holehe consolidates all UA strings into one location, enabling consistent, maintainable request polymorphism.


What the localuseragent Module Contains

At the core of holehe/localuseragent.py is a single global variable ua defined on line 3. This variable stores a parsed JSON structure containing categorized browser signatures:

ua = json.loads('''{
    "browsers": {
        "chrome": [ … list of Chrome UA strings … ],
        "firefox": [ … list of Firefox UA strings … ],
        "safari":  [ … list of Safari UA strings … ],
        "iOS":     [ … list of iOS UA strings … ]
    }
}''')

The dictionary organizes User-Agent strings by browser family, making it trivial to match the appropriate fingerprint to a target platform's expected traffic patterns.


How User Agents Are Selected in holehe Modules

Each OSINT module imports the ua dictionary and selects a random entry at request time. This pattern appears consistently throughout the codebase.

Import Patterns

Modules use one of two import styles:

from holehe.localuseragent import ua

Or wildcard import:

from holehe.localuseragent import *

Random Selection Implementation

The selection mechanism relies on Python's random.choice() against the appropriate browser list:

'User-Agent': random.choice(ua["browsers"]["chrome"])

This approach yields a non-deterministic, realistic browser fingerprint for every HTTP request.


Real-World Usage in Core Modules

Facebook Module (holehe/modules/social_media/facebook.py)

The Facebook checker demonstrates standard UA selection:

import random
from holehe.localuseragent import ua

def check_facebook(email):
    headers = {
        'User-Agent': random.choice(ua["browsers"]["chrome"]),
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    }
    # perform request …

Spotify Module (holehe/modules/music/spotify.py)

Spotify's module follows the same pattern:

from holehe.localuseragent import ua

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

Steam Module (Wildcard Import Example)

When using wildcard imports, the ua variable remains directly accessible:

from holehe.localuseragent import *

def check_steam(email):
    headers = {
        'User-Agent': random.choice(ua["browsers"]["firefox"]),
    }
    # perform request …

Why Randomized User-Agents Matter for OSINT

Evasion of Bot Detection

Static User-Agent strings trigger fingerprinting defenses. By randomizing across plausible browser signatures, holehe requests appear as organic, human-driven traffic rather than automated scanning.

Centralized Maintenance

All browser strings live in localuseragent.py. Updating Chrome versions, adding new Safari signatures, or pruning outdated Firefox UAs requires editing a single file. Changes propagate automatically to every module that imports ua.

Platform-Appropriate Signatures

The categorized structure (chrome, firefox, safari, iOS) lets modules select contextually appropriate headers. A mobile-centric service might prefer ua["browsers"]["iOS"], while enterprise platforms may expect desktop Chrome patterns.


Key Files and Their Roles

File Purpose
holehe/localuseragent.py Master dictionary of categorized User-Agent strings exposed as ua
holehe/modules/social_media/facebook.py Demonstrates from holehe.localuseragent import ua import and random selection
holehe/modules/music/spotify.py Uses random.choice(ua["browsers"]["chrome"]) in production requests
holehe/modules/software/office365.py Shows alternative pattern: passing UA via function argument (user_agent)

Summary

  • localuseragent.py stores all User-Agent strings as a parsed JSON dictionary in the global ua variable
  • Modules import ua and call random.choice() to select non-deterministic, realistic browser fingerprints
  • Four browser categories exist: chrome, firefox, safari, and iOS
  • This architecture enables polymorphic requests that evade bot detection while remaining centrally maintainable

Frequently Asked Questions

Does holehe rotate User-Agents per request or per session?

Per request. The random.choice() call executes fresh for each HTTP request, meaning consecutive checks—even within the same module—may present different browser fingerprints. This maximizes entropy against rate-limiting systems.

Can I add custom User-Agent strings to holehe?

Yes. Edit holehe/localuseragent.py and append strings to the appropriate browser list inside the JSON structure. All modules importing ua will immediately access your additions without code changes elsewhere.

Why does holehe include iOS UAs separately from Safari?

Mobile Safari on iOS presents distinct headers from desktop Safari, including device identifiers and AppleWebKit versioning. The separate iOS category lets modules targeting mobile-first platforms (Instagram, Snapchat, etc.) select appropriate mobile fingerprints.

What happens if localuseragent.py fails to import?

The import failure would cascade to any module attempting from holehe.localuseragent import ua, causing an ImportError at module load time. The file has no external dependencies beyond Python's standard json library, making such failures rare.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →