Skip to content

medama-io/go-useragent

Repository files navigation

go-useragent

go-useragent is a high-performance zero-allocation Go library designed to parse browser name and version, operating system, and device type information from user-agent strings with sub-microsecond parsing times.

It achieves this efficiency by using a modified hybrid trie data structure to store and rapidly look up user-agent tokens. It utilizes heuristic rules, tokenizing a list of user-agent strings into a trie during startup. During runtime, the parsing process involves a straightforward lookup operation.

This project is actively maintained and used by the lightweight website analytics project Medama.

Installation

go get -u github.com/medama-io/go-useragent

Usage

This type of parser is typically initialized once at application startup and reused throughout the application's lifecycle. While it doesn't offer the exhaustive coverage of traditional regex-based parsers, it can be paired with one to handle unknown edge cases, where the trie-based parser acts as a fast path for the majority of user-agents.

Example

package main

import (
    "fmt"
    "github.com/medama-io/go-useragent"
)

func main() {
    // Create a new parser. Initialize only once during application startup.
    ua := useragent.NewParser()

    // Example user-agent string.
    str := "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"

    // Parse the user-agent string.
    agent := ua.Parse(str)

    // Access parsed information using agent fields.
    fmt.Println(agent.GetBrowser())  // Chrome
    fmt.Println(agent.GetOS())       // Windows
    fmt.Println(agent.GetVersion())  // 118.0.0.0
    fmt.Println(agent.IsDesktop())  // true
    fmt.Println(agent.IsMobile())   // false
    fmt.Println(agent.IsTablet())   // false
    fmt.Println(agent.IsTV())       // false
    fmt.Println(agent.IsBot())      // false

    // Helper functions.
    fmt.Println(agent.GetMajorVersion())  // 118
}

Refer to the pkg.go.dev documentation for more details on available fields and their meanings.

Benchmarks

Benchmarks were performed against ua-parser/uap-go and mileusena/useragent on an Apple M3 Pro Processor.

cd ./benchmarks
go test -bench=. -benchmem ./...

MedamaParserGetSingle-12        2916867             408.5 ns/op               0 B/op          0 allocs/op
MileusnaParserGetSingle-12      1322602             917.3 ns/op             600 B/op         16 allocs/op
UAPParserGetSingle-12            986428              1159 ns/op             233 B/op          8 allocs/op

MedamaParserGetAll-12             57078             20037 ns/op               0 B/op          0 allocs/op
MileusnaParserGetAll-12           28375             42301 ns/op           28031 B/op        716 allocs/op
UAPParserGetAll-12                18645             56951 ns/op           10179 B/op        344 allocs/op

Acknowledgements

  • The library draws inspiration from the techniques outlined in this Raygun blog post.