Modify User-Agent Headers in Chrome: The QA Engineer’s Handbook
The User-Agent header is one of the most useful request headers for QA testing — and one of the most overlooked.
Every HTTP request your browser sends includes a User-Agent string that identifies the browser, OS, and version. Servers use this to detect device types, route requests, serve platform-specific content, and enforce access controls. For QA, this means User-Agent is a direct handle for testing how your application responds to different clients — without owning physical devices, maintaining emulators, or making code changes.
This guide covers what the User-Agent header does, what QA scenarios it unlocks, and how to modify it persistently in Chrome using a browser extension.
What the User-Agent Header Does
The User-Agent value is a string the browser sets on every outgoing HTTP request. A typical Chrome User-Agent on Windows looks like:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
Mobile Chrome on Android:
Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36
iOS Safari:
Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1
Server-side code, backend APIs, CDNs, and analytics systems all read this string to make routing and rendering decisions. From the server’s perspective, the User-Agent tells it what kind of client it’s talking to.
Why QA Engineers Modify User-Agent Headers
Testing Responsive and Mobile-Specific Code Paths
Many applications serve different responses based on User-Agent. A mobile User-Agent may trigger:
- A different HTML template or reduced-feature layout
- Mobile-specific API response fields
- Different redirect behavior (mobile app deep-link vs. web)
- Different image sizes or media served
Chrome DevTools’ device emulation changes the viewport and touch simulation — but it does not change the User-Agent sent in requests unless you explicitly set it. Backend logic that branches on User-Agent won’t fire from DevTools viewport emulation alone.
Modifying the User-Agent header directly tests the server-side code path, not just the CSS media query behavior.
Detecting Bot-Detection and Rate-Limiting by Client
Some APIs and web applications apply stricter rate limits or access controls to requests that look like scripts or bots. A programmatic-looking User-Agent (like python-requests/2.28.0 or curl/7.88.1) may trigger:
- CAPTCHA challenges
- Reduced rate limit thresholds
- 403 responses
- Different content served
QA testing for these code paths requires sending requests with specific User-Agents. With a header editor, you can test how your application responds to both legitimate browser User-Agents and unusual client strings.
Validating User-Agent Based Feature Flags
Some teams use User-Agent matching for controlled rollouts or feature gating:
- Beta features only available on newer browser versions
- Legacy browser fallback behavior
- Internal-only tooling gated on a custom User-Agent value (e.g.,
X-Internal-QA: truepattern using UA as a proxy)
Testing these paths from your standard development browser requires overriding the User-Agent the browser sends.
Verifying Analytics and Client Tracking
Analytics systems often segment by browser type, OS, and version using the User-Agent. QA for analytics pipelines may require:
- Confirming that mobile and desktop User-Agents are classified correctly
- Testing that bot-flagged User-Agents are excluded from metrics
- Validating that legacy browser User-Agents don’t break tracking code
Injecting specific User-Agent values during QA testing verifies the classification logic without requiring real devices.
How to Modify User-Agent Headers in Chrome
Option 1: Chrome DevTools (Session-Only)
Chrome DevTools provides a built-in User-Agent override via More tools → Network conditions.
- Select a preset from Chrome’s list (iOS Safari, various Android browsers) or enter a custom string
- The override applies to the current tab for the current session
- It resets when you close DevTools or the tab
This works for quick one-off tests. It doesn’t persist across sessions and doesn’t support multiple URL-scoped profiles — you get one active User-Agent override at a time, applying to all requests from that tab.
Option 2: Browser Extension (Persistent, URL-Scoped)
A browser extension using Chrome’s declarativeNetRequest API can apply User-Agent rules persistently, scoped to specific URLs or domains.
HeaderSnap supports User-Agent modification as a standard header rule. The setup:
- Open HeaderSnap and select a profile (or create one: “Mobile QA,” “Legacy browser testing,” etc.)
- Add a new rule:
- Header name:
User-Agent - Value: paste the User-Agent string you want to send
- Action:
set - URL pattern: scope it to your application domain (e.g.,
https://app.yourapp.com/*) or set it broader if you’re testing third-party API behavior
- Header name:
- Enable the rule
The User-Agent override is now active for all requests matching your URL pattern — across sessions, until you disable the rule.
Practical QA Test Cases Using User-Agent Override
Mobile Responsive Server-Side Logic
Scenario: Your API serves different JSON fields based on whether the client is mobile or desktop.
Setup:
- Profile: “Mobile Chrome — Android”
- Rule:
User-Agent→Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36 - URL pattern:
https://api.yourapp.com/*
Navigate to your application and trigger the API call. Inspect the response — it should include the mobile-specific fields. Disable the rule, reload, verify the desktop response.
Legacy Browser Fallback
Scenario: Your application has a fallback page for IE11 or old Chrome versions.
Setup:
- Profile: “Legacy IE11”
- Rule:
User-Agent→Mozilla/5.0 (Windows NT 10.0; Trident/7.0; rv:11.0) like Gecko - URL pattern:
https://yourapp.com/*
Load the application with this rule active. Verify the legacy fallback triggers correctly.
Bot/Crawler Simulation
Scenario: Your API should reject requests from known scrapers.
Setup:
- Profile: “Python scraper UA”
- Rule:
User-Agent→python-requests/2.28.0 - URL pattern:
https://api.yourapp.com/*
Make a request with this profile active. Verify the API returns the expected error (403, CAPTCHA redirect, etc.). Disable the rule and verify normal browser requests are permitted.
Managing Multiple User-Agent Test Cases
For QA workflows that involve regularly switching between User-Agents, profiles are the most efficient approach:
| Profile name | User-Agent string | URL pattern |
|---|---|---|
| Mobile Chrome Android | Mozilla/5.0 (Linux; Android 14; Pixel 8)... | app.yourapp.com/* |
| iOS Safari | Mozilla/5.0 (iPhone; CPU iPhone OS 17_0...) | app.yourapp.com/* |
| Legacy Chrome 80 | Mozilla/5.0 ... Chrome/80.0.0.0 ... | app.yourapp.com/* |
| Python scraper | python-requests/2.28.0 | api.yourapp.com/* |
Enable the relevant profile before each test case. The per-rule toggle makes it easy to switch without recreating rules.
User-Agent Strings Reference
Commonly used User-Agent strings for QA testing:
Mobile Chrome on Android (Pixel 8, Chrome 122):
Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36
iOS Safari (iPhone, iOS 17):
Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1
Chrome on Windows (Chrome 122):
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
Firefox on macOS (Firefox 123):
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:123.0) Gecko/20100101 Firefox/123.0
Python requests (common scraper):
python-requests/2.28.0
Googlebot:
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Getting Started
HeaderSnap is a free Chrome extension. No account required, no proxy setup, no certificate installation. Install it, create a profile for mobile testing or bot simulation, add a User-Agent rule, and you’re set — no DevTools required, no configuration reset between sessions.
All features are free.