Device Detector

May 7, 2026 ยท View on GitHub

Device Detector is a Crystal shard for parsing User-Agent strings. It detects bots, browsers, browser engines, operating systems, client applications, devices, vendors, models, and a few specialized device classes such as TVs, cameras, consoles, car browsers, and portable media players.

The parser uses regex data from matomo-org/device-detector and embeds it into the shard at compile time.

Installation

Add the shard to your application's shard.yml:

dependencies:
  device_detector:
    github: creadone/device_detector

Then install dependencies:

shards install

Usage

require "device_detector"

user_agent = "Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36 Edge/12.0"

response = DeviceDetector::Detector.new(user_agent).call

response.browser?             # => true
response.browser.name         # => "Microsoft Edge"
response.browser.version      # => "12.0"
response.os.name              # => "Windows"
response.os.version           # => "10"
response.traffic_type         # => "human"

Use #call to run the full parser stack. Use #lite when you only need bot and mobile-device detection:

full_response = DeviceDetector::Detector.new(user_agent).call
lite_response = DeviceDetector::Detector.new(user_agent).lite

Response#raw returns the raw parser output:

pp response.raw

The raw value is an Array(Hash(String, Hash(String, String))). Missing values are represented as empty strings in the raw data; typed accessors return String?.

Response API

Each detected section has a predicate and an object-style accessor:

response.browser?        # => Bool
response.browser.name    # => String?
response.browser.version # => String?

Available sections and fields:

SectionPredicateFields
Botbot?bot.name
Browserbrowser?browser.name, browser.version
Browser enginebrowser_engine?browser_engine.name
Cameracamera?camera.device, camera.vendor
Car browsercar_browser?car_browser.model, car_browser.vendor
Consoleconsole?console.model, console.vendor
Feed readerfeed_reader?feed_reader.name, feed_reader.version
Librarylibrary?library.name, library.version
Mediaplayermediaplayer?mediaplayer.name, mediaplayer.version
Mobile appmobile_app?mobile_app.name, mobile_app.version
Mobile devicemobile?mobile.vendor, mobile.type, mobile.model
OSos?os.name, os.version
PIMpim?pim.name, pim.version
Portable media playerportable_media_player?portable_media_player.model, portable_media_player.vendor
TVtv?tv.model, tv.vendor
Vendor fragmentvendorfragment?vendorfragment.vendor

Legacy flat accessors are still available for compatibility:

response.browser_name
response.browser_version
response.mobile_device?
response.mobile_device_vendor
response.mobile_device_type
response.mobile_device_model
response.camera_model

Traffic Type

Response#traffic_type returns "bot" when a bot or client library was detected. Otherwise it returns "human".

response.traffic_type # => "bot" | "human"

Benchmarks

Run benchmarks in release mode:

crystal run --release bench/raw_response.cr

Example result for parsing 10,000 unique user-agent strings:

Crystal 1.17.1 (2025-07-22)
LLVM: 21.1.0
Default target: aarch64-apple-darwin23.1.0

workload: 10000 unique user-agents
full:  3738.70 user-agent/sec (2.674724s)
lite: 11038.74 user-agent/sec (0.905900s)

The benchmark enforces a minimum full-parser speed of 150 user-agent/sec.

Development

Install dependencies:

shards install

Run tests:

crystal spec

Run the linter:

bin/ameba

Check formatting:

crystal tool format --check src spec script bench

Updating Regexes

Regex files live under src/device_detector/regexes and are based on matomo-org/device-detector.

To refresh them:

crystal run script/update_regexes.cr
crystal spec
bin/ameba

Review the regex diff before committing it.

Contributing

  1. Fork the repository.
  2. Create a feature branch.
  3. Make the change with tests when behavior changes.
  4. Run crystal spec, bin/ameba, and the formatter check.
  5. Open a pull request.

Contributors

  • @creadone Sergey Fedorov - creator, maintainer
  • @delef Ivan Palamarchuk - new API, code optimization
  • @zaycker Yuriy Zaitsev - parser order fix