Skip to main content

User-Agent Parsing Done Right

This module takes a smaller, faster, modern approach to User-Agent parsing. It's a dependency-free pure-Python parser weighing only 25 kB, with strong handling of current browsers and crawlers. Despite its light weight, uarite identifies both browsers and crawlers more accurately than any competing implementation tested here.

It returns structured classification, but also the thing most applications eventually need: a short pretty description.

Add it to your project:

uv add uarite

Usage

from uarite import uaparse

r = uaparse("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36")

r.pretty    # "Chrome/152 Windows"
r.engine    # "Chromium"
r.os        # "Windows"
r.kind      # "browser"
r.url       # ""

r = uaparse("Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.6885.65 Mobile Safari/537.36; compatible; facebookexternalhit/1.1; +http://www.facebook.com/externalhit_uatext.php")

r.pretty    # "Facebook"
r.kind      # "social"
r.provider  # "Meta"
r.url       # "http://www.facebook.com/externalhit_uatext.php"

Output

uaparse(ua) returns a UA dataclass with string fields. Any field may be empty when the information is unavailable.

Field Content
pretty Compact display string; raw UA when unrecognized
engine Chromium, Gecko, Safari, ArkWeb
os Windows, macOS, Linux, iOS, Android, HarmonyOS
kind browser, ai, search, social, analytics, spider
url Crawler information URL
provider Provider of a known crawler family

The pretty field is intended for UIs and logs. The url can be attached to it as a link when available.

The engine and os fields are intentionally broad. The kind field distinguishes browsers from AI collectors, search engines, social previews, monitoring tools, generic spiders, and ordinary HTTP clients. Any non-browser kind represents automated traffic.

Detection is necessarily limited by what the User-Agent reveals. Crawlers can masquerade as ordinary browsers or other crawlers, so sites that need stronger identification should use additional methods rather than relying on UA detection alone.

Comparison

There are plenty of UA parsers for Python. This comparison includes the ua-parser family — the official port of the large upstream project, benchmarked with all three of its regex backends (Python, RE2, Rust) — plus user-agents, which builds on it with higher-level device detection, and fastuaparser, a single-file heuristic parser in the same weight class as uarite. Among those excluded: user-agent-parser crashes on real-world strings; httpagentparser misidentifies most bots and browser OSes; device-detector has a massive 26 MB install and extremely slow parsing; and crawlerdetect only distinguishes bots from non-bots. The user-agents package has been unmaintained since 2020 but is kept as a reference point.

Installed size tracks the design. The minimal heuristic parsers are tiny: fastuaparser installs in 15 kB, uarite in 30 kB. Everything built on ua-parser's regex database starts around half a megabyte, and its accelerated backends add several megabytes of native code.

The benchmark and test scripts are available in the repository's scripts folder.

Accuracy

The table below compares representative User-Agent formats with fastuaparser and ua-parser. The user-agents wrapper produces nearly identical results to ua-parser and is left out.

Case uarite¹ fastuaparser² ua-parser³
Chrome, Windows Chrome/152 Windows Chrome - Windows Chrome/152 Windows
Safari, macOS Safari/18 macOS Safari - Mac OS X Safari/18 Mac OS X Mac
Opera, Linux Opera/106 Linux Opera - Linux Opera/106 Linux
Chrome, Android (no model) Chrome/152 Android Chrome - Android Mobile Chrome Mobile/152 Android K❌
Chrome, Android (Pixel) Chrome/118 Pixel 6 Chrome - Android Mobile Chrome Mobile/118 Android Pixel 6
Edge, Android (model code) Edge/110 Galaxy S7 Edge - Android Mobile Edge Mobile/110 Android Samsung SM-G930P
Firefox, Android Firefox/154 Android 15 Firefox - Android Mobile Firefox Mobile/154 Android Generic Smartphone
Safari, iPhone iPhone iOS 17 Safari - iOS Mobile Mobile Safari/17 iOS iPhone
Huawei HarmonyOS phone HuaweiBrowser/6 HarmonyOS Chrome - Android Mobile❌ Huawei Browser/6 Android❌ Huawei Browser
GPTBot GPTBot (AI) Bot GPTBot/1 Spider
Googlebot (disguised) Googlebot (search) Bot Googlebot/2 Android❌ Spider
Facebook preview (disguised) Facebook Chrome - Android Mobile❌ FacebookBot/1 Android Pixel 7 ❌
Meta crawler (disguised) Meta-ExternalAgent (AI) Bot Chrome/145 Windows ❌
WhatsApp preview WhatsApp Browser - Other❌ WhatsApp/10 Spider
Bytespider Bytespider Bot Bytespider/ Android❌ Generic Smartphone
BingPreview BingPreview Browser - Windows❌ BingPreview/1 Windows❌ Spider
AhrefsBot AhrefsBot Bot AhrefsBot/7 Spider
python-requests python-requests/2.32.5 Other Python Requests/2
  • ❌ marks incorrect data such as an OS from disguise, Android 10; K (compat) on modern devices, or a missed identity
  • ¹ r.pretty shown as is
  • ² parse_ua(ua) shown as is
  • ³ {r.user_agent.family}/{r.user_agent.major} {r.os.family} {r.device.family}

On our modern-browser test set, scoring only fully correct results (family, version, and OS all right): uarite 100%, ua-parser and user-agents 79%. The fastuaparser heuristic resolves the family and OS in 91% of cases, but reports no version numbers at all, so it cannot be scored on the full criterion.

Crawler detection was tested against real world UAs: uarite 97%, fastuaparser 84%, ua-parser 64%, user-agents 60%.

Performance

Import and first parse takes about 10 ms for uarite and effectively nothing for fastuaparser, compared with 50–90 ms for ua-parser depending on backend.

uarite 56 thousand, ua-parser native code variants Rust 26 thousand, RE2 14 thousand, and finally plain Python ua-parser and user-agents 3 thousand User-Agents parsed per second per CPU core, first parse of unseen strings, with equal shares of browser and crawler UAs. One-off setup costs excluded. Cached results and fastuaparser (1 million) are left out of the graph.

On raw speed fastuaparser wins: a few string searches per UA, no cache needed. The trade-off shows in the accuracy table above — no versions, no crawler names. All other parsers cache results. With cache hits, uarite reaches about 36 million lookups per second, compared with about 5 million for ua-parser and 600 000 for user-agents.

Why yet another UA parser

Rather than relying on a large historical regex database, the parser focuses on modern UA formats and parses them directly, choosing the most specific interpretation available. This keeps the implementation small while handling today's browsers and crawler traffic well. Until now, I had been using those other modules and building my own pretty-UA formatting on top of them, fixing by post processing issues the upstream didn't care of.

Eventually it became easier to start over with a parser designed around modern traffic. The result is uarite.

Hopefully it helps you too. Star my GitHub if it did.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uarite-0.2.1.tar.gz (110.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

uarite-0.2.1-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

Details for the file uarite-0.2.1.tar.gz.

File metadata

  • Download URL: uarite-0.2.1.tar.gz
  • Upload date:
  • Size: 110.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for uarite-0.2.1.tar.gz
Algorithm Hash digest
SHA256 45eee1ae4c1970c9d2000fb08379fc29c79f5fc76393dfffded4f715ce1663a4
MD5 7f05ee0448f40d4b70aadabb0aaf7897
BLAKE2b-256 cf752e26b21cc9c8ef7c3efa7c4ece19f5f5bc08429b069b21e2d05e6e4a6353

See more details on using hashes here.

File details

Details for the file uarite-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: uarite-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 11.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for uarite-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 af5c2e41df6ddaa7fa61bc2bdef5fbfaa46407092b33ab2cf06f75c6de4f3cdd
MD5 3154c9f13ead64db69b4fe2eb87c7d43
BLAKE2b-256 2a07804159a078268b67181d8d6cb04b759db4fe805ac6d27f5d1ccec7c06cf0

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.2

2 files

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page