Created
August 21, 2026 12:42
-
-
Save quantumproxies/9974c4819b7a11c5cab63009b3e159f5 to your computer and use it in GitHub Desktop.
What your user-agent says about you, from the shell — plus why UA rotation alone does nothing https://quanticdata.io/tools/user-agent/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # What a server actually sees, and why rotating the user-agent alone changes nothing. | |
| # | |
| # ./qd-ua.sh # your current UA, parsed | |
| # ./qd-ua.sh "Mozilla/5.0 (…)" # parse any UA string | |
| # | |
| # Interactive lookup: https://quanticdata.io/tools/user-agent/ | |
| set -euo pipefail | |
| ECHO_SERVICE="${ECHO_SERVICE:-https://httpbin.org}" | |
| # The echo service is a convenience, not a dependency — everything below still | |
| # works if it is down, which public echo endpoints regularly are. | |
| echo_json() { | |
| curl -sS -m 15 "$@" 2>/dev/null | jq . 2>/dev/null | |
| } | |
| UA="${1:-$(echo_json "$ECHO_SERVICE/user-agent" | jq -r '."user-agent" // empty' || true)}" | |
| UA="${UA:-$(curl --version | head -1 | awk '{print "curl/"$2}')}" | |
| echo "user-agent" | |
| echo " $UA" | |
| echo | |
| echo "what a server reads out of it" | |
| case "$UA" in | |
| *Chrome/*) printf " browser Chrome %s\n" "$(sed -n 's/.*Chrome\/\([0-9.]*\).*/\1/p' <<<"$UA")" ;; | |
| *Firefox/*) printf " browser Firefox %s\n" "$(sed -n 's/.*Firefox\/\([0-9.]*\).*/\1/p' <<<"$UA")" ;; | |
| *Safari/*) echo " browser Safari" ;; | |
| *curl/*) echo " browser curl — this is not a browser and every anti-bot vendor knows it" ;; | |
| *python*|*requests*) echo " browser a Python client, announcing itself" ;; | |
| *) echo " browser unrecognised" ;; | |
| esac | |
| case "$UA" in | |
| *Windows*) echo " platform Windows" ;; | |
| *Macintosh*|*"Mac OS X"*) echo " platform macOS" ;; | |
| *Android*) echo " platform Android" ;; | |
| *iPhone*|*iPad*) echo " platform iOS" ;; | |
| *Linux*) echo " platform Linux" ;; | |
| esac | |
| case "$UA" in | |
| *Mobile*) echo " form mobile" ;; | |
| *) echo " form desktop" ;; | |
| esac | |
| echo | |
| echo "everything else the server sees" | |
| # `|| true` matters: under `set -e` a failed substitution would end the script. | |
| HEADERS=$(echo_json "$ECHO_SERVICE/headers" -H "User-Agent: $UA") || true | |
| if [ -n "$HEADERS" ]; then | |
| printf '%s' "$HEADERS" | jq -r '.headers | to_entries[] | " \(.key): \(.value)"' | |
| else | |
| echo " ($ECHO_SERVICE is not answering — set ECHO_SERVICE to another echo endpoint)" | |
| fi | |
| cat <<'NOTE' | |
| Rotating the user-agent alone accomplishes nothing. A server fingerprints the whole | |
| request: header ORDER, the TLS/JA3 handshake, HTTP/2 settings frames, and whether the | |
| sec-ch-ua hints agree with the UA string. A Chrome 140 user-agent arriving with | |
| Python's TLS signature and no client hints is MORE distinctive than plain curl. | |
| Coherence is the point: | |
| - mobile exit IP -> mobile user-agent AND sec-ch-ua-mobile: ?1 | |
| - German exit -> Accept-Language starting with de | |
| - Chrome UA -> Chrome's header order and TLS fingerprint | |
| That last one is not something you can set from curl. It is what | |
| https://quanticdata.io/web-scraping-api/ does for you server-side. | |
| UA lookup: https://quanticdata.io/tools/user-agent/ | |
| NOTE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment