Documentation
¶
Overview ¶
Package useragent provides middleware that performs lightweight parsing of the User-Agent request header into a small struct and stores it on the request for downstream handlers. It is a spiritual, dependency-free port of the Node "express-useragent" middleware and the "useragent" npm package, but deliberately tiny: rather than shipping a large table of regular expressions covering hundreds of browsers and devices, it recognises only a handful of common browser families and operating systems using plain substring matching. The goal is to give downstream handlers a fast, coarse signal ("this looks like mobile Chrome on Android") without pulling in any third-party parsing library.
Reach for this middleware when you want to branch on broad client categories — for example, serving a lighter template to mobile clients, recording coarse browser statistics, or logging an OS breakdown — and can tolerate approximate results. It is not suitable as a security control or for precise device fingerprinting; the User-Agent header is client-supplied and easily spoofed, and the detection here is intentionally shallow. For blocking specific agents outright see the sibling useragentblock package, which this package does not itself perform.
Chain position is early: mount New with app.Use before any handler that needs the parsed result. On each request the middleware reads the "User-Agent" request header via req.Get, calls Parse on it, and stores the resulting UserAgent value on the request with req.Set(Key, ua) where Key is the constant "useragent". It never writes response headers, never short-circuits, and always calls next() so the request continues down the chain. Downstream handlers retrieve the value with From(req), which returns the parsed UserAgent and a boolean reporting whether the middleware ran.
The parsing semantics live in Parse and are worth understanding. Detection is lower-cased and ordered so that more specific tokens win: "edg" is checked before "chrome" (Edge advertises Chrome), "crios" counts as Chrome and Opera's "opr"/"opera" is matched before the generic engines. Unknown browsers and operating systems fall back to the literal string "Unknown" rather than an empty value, and Raw always preserves the original header. The Mobile flag is a simple OR over the "mobi", "android", "iphone" and "ipad" tokens, so an Android tablet or an unusual UA string may be classified only approximately.
Compared with the Node originals this port is far narrower in scope: it does not expose version numbers, bot/crawler detection, device model names, the long list of per-vendor booleans (isChrome, isIE, isBot, and so on), or platform sub-classification beyond the coarse OS field. Only Edge, Opera, Firefox, Chrome and Safari are recognised as browsers, and only Android, iOS, Windows, macOS and Linux as operating systems; everything else is reported as "Unknown". Treat the output as a hint, not a contract, and if you need richer data parse req.Get("User-Agent") yourself.
Example ¶
Example wires the useragent middleware into an express application and drives it with a synthetic request through httptest. The middleware parses the incoming User-Agent header and stores the result on the request, so a later handler can recover it with useragent.From. Here the downstream handler reports the detected browser, operating system and mobile flag back in the response body. Because the parser is deterministic for a fixed input string, the output is stable and can be checked with an Output comment. This mirrors how a real backend might branch on coarse client categories.
package main
import (
"fmt"
"net/http/httptest"
"github.com/malcolmston/express"
"github.com/malcolmston/express/middleware/useragent"
)
func main() {
app := express.New()
app.Use(useragent.New())
app.Get("/", func(req *express.Request, res *express.Response, next express.Next) {
ua, _ := useragent.From(req)
res.Send(fmt.Sprintf("browser=%s os=%s mobile=%t", ua.Browser, ua.OS, ua.Mobile))
})
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("User-Agent", "Mozilla/5.0 (Linux; Android 13; Pixel) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Mobile Safari/537.36")
w := httptest.NewRecorder()
app.ServeHTTP(w, r)
fmt.Println(w.Body.String())
}
Output: browser=Chrome os=Android mobile=true
Index ¶
Examples ¶
Constants ¶
const Key = "useragent"
Key is the request value key under which the parsed UserAgent is stored.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type UserAgent ¶
type UserAgent struct {
// Browser is a coarse browser family name (e.g. "Chrome", "Firefox",
// "Safari") or "Unknown".
Browser string
// OS is a coarse operating-system name (e.g. "Windows", "macOS",
// "Android") or "Unknown".
OS string
// Mobile reports whether the agent appears to be a mobile device.
Mobile bool
// Raw is the original User-Agent header value.
Raw string
}
UserAgent is the result of basic substring-based User-Agent detection.