Note
A library for generating realistic browser headers for macOS and Windows platforms — always the freshest Chrome headers.
- Always fresh: Focus on providing the most up-to-date Chrome headers!
- Platform specific: Tailored for macOS and Windows environments
- Smart caching: API calls only once per week to minimize overhead
- Simple API: Easy-to-use, property-based interface
- Zero dependencies: No external dependencies required
- Thread-safe: Built for concurrent applications
- Clean architecture: SOLID principles with proper separation of concerns
pip install MacWinUAWith Poetry:
poetry add MacWinUA- Python 3.10 or higher
from macwinua import ua
# Get any Chrome User-Agent string (random)
ua_string = ua.chrome
# Get a macOS Chrome UA
mac_ua = ua.mac
# Get a Windows Chrome UA
win_ua = ua.windows
# Get the latest available version's UA
latest_ua = ua.latest
# Alias for random Chrome UA
random_ua = ua.randomfrom macwinua import ua
# Basic Chrome headers
headers = ua.get_headers()
# macOS Chrome headers
mac_headers = ua.get_headers(platform="mac")
# Windows Chrome headers
win_headers = ua.get_headers(platform="win")
# Specific Chrome version
ver_headers = ua.get_headers(chrome_version="139")
# Specific platform + version
combo_headers = ua.get_headers(platform="mac", chrome_version="138")
# Add custom headers (merged)
custom_headers = ua.get_headers(extra_headers={"X-API-KEY": "mykey"})
# Use with requests
import requests
response = requests.get("https://example.com", headers=ua.get_headers())For even more concise code:
from macwinua import get_chrome_headers
headers = get_chrome_headers() # random
mac_headers = get_chrome_headers(platform="mac")
win_headers = get_chrome_headers(platform="win", chrome_version="139")from macwinua import HeaderGenerator
# Create a new instance (uses singleton DataManager internally)
my_ua = HeaderGenerator()
# Force refresh data from API (bypasses 7-day cache)
my_ua.force_update()
# Use the same methods as the singleton
headers = my_ua.get_headers(platform="win")from macwinua import force_update
# Force refresh the global singleton with latest data from API
force_update()
# Now all calls will use the refreshed data
headers = ua.get_headers()import requests
from macwinua import ua
# Create a session
session = requests.Session()
# Configure with macOS Chrome headers
session.headers.update(ua.get_headers(platform="mac"))
# Make requests
response = session.get("https://httpbin.org/headers")
print(response.json()["headers"]["User-Agent"])
# Change to Windows headers for next request
session.headers.update(ua.get_headers(platform="win"))
response = session.get("https://httpbin.org/headers")
print(response.json()["headers"]["User-Agent"])import httpx
from macwinua import get_chrome_headers
async def fetch_data():
headers = get_chrome_headers(platform="mac", chrome_version="139")
async with httpx.AsyncClient(headers=headers) as client:
response = await client.get("https://httpbin.org/headers")
return response.json()
# Run the async function
import asyncio
result = asyncio.run(fetch_data())
print(result["headers"]["User-Agent"])from macwinua import HeaderGenerator
import random
import requests
import time
class UARotator:
def __init__(self):
self.ua_generator = HeaderGenerator()
self.platforms = ["mac", "win"]
self.used_uas = set()
def get_fresh_headers(self, max_attempts=10):
"""Get headers that haven't been used recently."""
for _ in range(max_attempts):
platform = random.choice(self.platforms)
headers = self.ua_generator.get_headers(platform=platform)
ua_string = headers["User-Agent"]
if ua_string not in self.used_uas:
self.used_uas.add(ua_string)
# Keep only last 20 UAs to prevent infinite growth
if len(self.used_uas) > 20:
self.used_uas.pop()
return headers
# If all attempts failed, return any headers
return self.ua_generator.get_headers()
# Usage
rotator = UARotator()
session = requests.Session()
for i in range(5):
fresh_headers = rotator.get_fresh_headers()
session.headers.update(fresh_headers)
response = session.get("https://httpbin.org/headers")
ua_string = response.json()["headers"]["User-Agent"]
platform = "macOS" if "Macintosh" in ua_string else "Windows"
print(f"Request {i+1} ({platform}): ...{ua_string[-50:]}")
time.sleep(1)Currently supports:
- Chrome versions: Latest 3 versions - automatically updated
- Platforms: macOS and Windows
- Automatic version detection: Fetches latest versions from Google's API
- Smart caching: Updates version data weekly
ua.chrome→ Random Chrome User-Agent stringua.mac→ Random macOS Chrome User-Agent stringua.windows→ Random Windows Chrome User-Agent stringua.latest→ User-Agent from latest Chrome versionua.random→ Alias forua.chrome
ua.get_headers(platform=None, chrome_version=None, extra_headers=None)→ Complete headers dictua.force_update()→ Force refresh data from API
get_chrome_headers(**kwargs)→ Convenience function using singletonforce_update()→ Force refresh singleton data
HeaderGenerator(data_manager=None)→ Create header generator instanceUAError→ Base exception classAPIFetchError→ API-related errorsCacheError→ Cache-related errorsDataValidationError→ Data validation errors
MacWinUA follows clean architecture principles with proper separation of concerns:
constants.py: Configuration, supported versions, type definitionsexceptions.py: Custom exception classes for different error typescore.py: Data processing components (caching, API fetching, data management)ua.py: User-facing interface for header generation
- Single Responsibility Principle: Each class has one clear purpose
- Open/Closed Principle: Easy to extend with new platforms or features
- Dependency Injection: Components are loosely coupled and testable
- Thread Safety: All operations are thread-safe for concurrent use
- Version Detection: Fetches latest 3 Chrome versions from Google's official API
- Smart Caching: Caches version data locally for 7 days to minimize API calls
- Header Generation: Creates realistic headers with proper sec-ch-ua values
- Fallback System: Uses hardcoded latest 3 versions (139, 138, 137) if API fails
- Thread Safety: All operations are thread-safe for concurrent applications
- Cache Location:
~/.macwinua/macwinua_cache.jsonin user's home directory - Cache Duration: 7 days
- Auto Refresh: Automatically refreshes expired cache on next use
- Force Refresh: Use
force_update()to bypass cache - Fallback: Uses built-in versions (139, 138, 137) if API is unavailable
from macwinua import ua, UAError, APIFetchError, CacheError, DataValidationError
try:
headers = ua.get_headers(platform="mac", chrome_version="139")
except UAError as e:
print(f"UA Error: {e}")
except APIFetchError as e:
print(f"API Error: {e}")
except CacheError as e:
print(f"Cache Error: {e}")
except DataValidationError as e:
print(f"Data Validation Error: {e}")This project uses Poetry for dependency management and packaging.
# Clone the repository
git clone https://github.com/Nuung/MacWinUA.git
cd MacWinUA
# Setup Python 3.10+ with pyenv (optional)
pyenv install 3.13.0
pyenv local 3.13.0
# Install dependencies
poetry install
# Activate the virtual environment
poetry shell# Run all tests
pytest
# Run with coverage
pytest --cov=macwinua --cov-report=html
# Run specific test file
pytest tests/test_ua.py
pytest tests/test_core.py
# Run with verbose output
pytest -v# Run linter
poetry run ruff check macwinua/ tests/
# Run formatter
poetry run ruff format macwinua/ tests/
# Run type checker
poetry run mypy macwinua/# Install pre-commit hooks
pre-commit install
# Run manually on all files
pre-commit run --all-filesThe pre-commit hooks automatically run:
- Ruff linting and formatting
- MyPy type checking
- Pytest tests
[!WARNING] > These checks run in CI pipeline, ensuring consistency between local development and automated testing.
MacWinUA is designed for high performance:
- Singleton Pattern: Shared data manager reduces memory usage
- Smart Caching: Minimizes API calls (once per week maximum)
- Thread Safety: Efficient concurrent access with minimal locking
- Memory Efficient: Lightweight data structures and minimal dependencies
# Simple performance test
import time
from macwinua import ua
# Test header generation speed
start = time.time()
for _ in range(1000):
headers = ua.get_headers()
end = time.time()
print(f"Generated 1000 headers in {end-start:.3f}s")
# Typical result: ~0.010s (100,000 headers/second)Unlike fake-useragent and similar libraries, MacWinUA focuses specifically on:
- Always up-to-date headers (including sec-ch-ua values)
- Realistic header combinations for perfect browser impersonation
- Chrome-only focus with macOS and Windows platforms
- Zero dependencies and lightweight design
- Smart caching to minimize API overhead
- Thread-safe operations for production applications
- Clean architecture following SOLID principles
We welcome contributions! Please ensure your code follows our standards:
- Code Style: Use Ruff for linting and formatting
- Type Hints: Full type coverage with MyPy
- Tests: 100% test coverage for new code
- Documentation: Update README and docstrings
- Architecture: Follow SOLID principles and existing patterns
This project is licensed under the MIT License - see the LICENSE.md file for details.