A user agent parser that identifies browsers, operating systems, devices, and bots.
$ dotnet add package UaDetector.LiteA powerful user agent parser inspired by Device Detector
UaDetector is a fast and precise user agent parser, built on top of the largest and most up-to-date user agent database from the Matomo Device Detector project. It identifies browsers, operating systems, devices, clients, and bots.
The library is optimized for speed with in-memory caching of regular expressions and frozen dictionaries for lookup operations. It maintains compatibility with the original regex patterns and detection rules.
In addition to the main UaDetector parser, individual sub-parsers are available: OsParser, BrowserParser,
ClientParser, and BotParser. Each can be used independently when only specific information is needed from
the user agent string.
| Package | Description |
|---|---|
| UaDetector | User agent parser optimized for speed |
| UaDetector.Lite | Memory-optimized variant with slower parsing speed |
| UaDetector.Abstractions | Shared models, enums, and constants |
| UaDetector.MemoryCache | Memory cache built on Microsoft.Extensions.Caching.Memory |
OsNames, OsFamilies, CpuArchitectures, BrowserNames, BrowserFamilies, BrowserEngines, BrandNamesOsCode, BrowserCode, BrandCode, ClientType, DeviceType, and BotCategory are enums, making them suitable for database storageTo use UaDetector, register it in Program.cs with the AddUaDetector() method.
To use a sub-parser, register it using its dedicated method: AddOsParser(), AddBrowserParser(), AddClientParser(), or AddBotParser().
All sub-parsers, except AddBotParser(), can be configured via UaDetectorOptions using the Options pattern as shown below.
using UaDetector;
builder.Services.AddUaDetector();
| Option | Type | Default | Description |
|---|---|---|---|
VersionTruncation | enum | Minor | Controls how version numbers are shortened (e.g., None, Major, Minor, Patch, Build). |
DisableBotDetection | bool | false | Disables bot detection entirely, skipping bot-related checks and parsing. |
Each parser provides two TryParse() methods: one that accepts only the user agent string and another
that accepts both the user agent string and a collection of HTTP headers.
For more accurate detection, it is recommended to provide the HTTP headers.
[!TIP] Avoid directly instantiating parsers. The first call to TryParse causes a noticeable delay due to the creation of regular expression objects. To prevent this one-time cost during runtime, register the service with dependency injection, as shown earlier.
[ApiController]
public class UaDetectorController : ControllerBase
{
private readonly IUaDetector _uaDetector;
public UaDetectorController(IUaDetector uaDetector)
{
_uaDetector = uaDetector;
}
[HttpGet]
[Route("ua-detector")]
public IActionResult GetUserAgentInfo()
{
var userAgent = HttpContext.Request.Headers.UserAgent.ToString();
var headers = Request.Headers.ToDictionary(
h => h.Key,
h => h.Value.ToArray().FirstOrDefault()
);
if (_uaDetector.TryParse(userAgent, headers, out var result))
{
return Ok(result);
}
return BadRequest("Unrecognized user agent");
}
}
The BotParser class provides an additional IsBot() method to determine whether a user agent string represents a bot.
using UaDetector.Parsers;
var botParser = new BotParser();
const string userAgent = "Mozilla/5.0 (compatible; Discordbot/2.0; +https://discordapp.com)";
if (botParser.IsBot(userAgent))
{
Console.WriteLine("Bot detected");
}
else
{
Console.WriteLine("No bot detected");
}
Input:
Mozilla/5.0 (Linux; Android 14; SAMSUNG SM-S926B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/23.0 Chrome/115.0.0.0 Mobile Safari/537.36
Output:
{
"os": {
"name": "Android",
"code": 1,
"version": "14",
"cpuArchitecture": null,
"family": "Android"
},
"browser": {
"name": "Samsung Browser",
"code": 512,
"version": "23.0",
"family": "Chrome",
"engine": {
"name": "Blink",
"version": "115.0"
}
},
"client": null,
"device": {
"type": 1,
"model": "Galaxy S24+",
"brand": {
"name": "Samsung",
"code": 1496
}
},
"bot": null
}
Static registry classes offer bidirectional lookups for converting between enum codes and their corresponding string names.
The BrowserRegistry, OsRegistry, and BrandRegistry classes provide type-safe access to predefined values.
// Get browser name from enum code
string browserName = BrowserRegistry.GetBrowserName(BrowserCode.Safari);
// Returns: "Safari"
// Try to get browser code from name (case-insensitive)
if (BrowserRegistry.TryGetBrowserCode("Safari", out var browserCode))
{
Console.WriteLine($"Browser Code: {browserCode}"); // Output: Browser Code: Safari
}
else
{
Console.WriteLine("Browser not found");
}
To enable caching, install the UaDetector.MemoryCache package and configure it using the UseMemoryCache() extension method.
using UaDetector;
using UaDetector.MemoryCache;
builder.Services.AddUaDetector(options =>
{
options.UseMemoryCache();
});
| Option | Type | Default | Description |
|---|---|---|---|
MaxKeyLength | int | 256 | Maximum length allowed for a cache key. Entries with longer keys will not be cached. |
Expiration | TimeSpan? | null | Entries will expire after this duration, regardless of how frequently they are accessed. |
SlidingExpiration | TimeSpan? | null | Entries will expire if they haven't been accessed within this time period. The expiration timer resets each time the entry is accessed. |
ExpirationScanFrequency | TimeSpan | 1 minute | Interval between automatic scans that evict expired cache entries. |
MaxEntries | long? | null | Maximum number of entries allowed in the cache. When the limit is reached, least recently used entries will be evicted. |
EvictionPercentage | double | 0.05 | Percentage of cache entries to evict when MaxEntries limit is reached. Eviction runs asynchronously. When the cache is full, new entries will not be cached until eviction completes. |
Note: For full documentation, visit the GitHub repository.