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.pystores all User-Agent strings as a parsed JSON dictionary in the globaluavariable- Modules import
uaand callrandom.choice()to select non-deterministic, realistic browser fingerprints - Four browser categories exist:
chrome,firefox,safari, andiOS - 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →