User-agent intelligence for GoodAnalytics, wrapping :ua_inspector.
The single owner of UAInspector access in the library. Pure functions — no Ecto, no side effects:
parse/1— normalize a user agent into a storable device maplabel/1— humanize a UA string or a stored device maphumanize_type/1— collapse a raw device type into a coarse bucketbot?/1— crawler predicate
parse/1 stores raw :ua_inspector field values (names + versions); consumers
group/humanize via label/1 and humanize_type/1.
Summary
Functions
True when the user agent is a known crawler/bot. Tolerates blanks.
Collapse a raw :ua_inspector device type into a coarse breakdown bucket.
Humanize a UA string or a stored device map into a short label.
Normalize a user agent into a device map. Empty map when blank/unknown.
Maps a parse/1 device map onto event-grain column attrs.
Types
Functions
True when the user agent is a known crawler/bot. Tolerates blanks.
Collapse a raw :ua_inspector device type into a coarse breakdown bucket.
Humanize a UA string or a stored device map into a short label.
@spec parse(String.t() | nil) :: device_map()
Normalize a user agent into a device map. Empty map when blank/unknown.
@spec to_event_attrs(device_map() | nil) :: %{optional(atom()) => String.t()}
Maps a parse/1 device map onto event-grain column attrs.
Keys absent from the device map are omitted so the Event changeset leaves
the corresponding column NULL. The raw :ua_inspector device type is stored
verbatim (humanize_type/1 is applied at read time, not here). For bots,
device_type is "bot" and bot_name carries the crawler name.