RepoPilotOpen in app →

fnando/browser

Do some browser detection with Ruby. Includes ActionController integration.

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 11mo ago
  • 24+ active contributors
  • MIT licensed
Show 4 more →
  • CI configured
  • Tests present
  • Slowing — last commit 11mo ago
  • Concentrated ownership — top contributor handles 69% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/fnando/browser)](https://repopilot.app/r/fnando/browser)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/fnando/browser on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: fnando/browser

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/fnando/browser shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 11mo ago
  • 24+ active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Slowing — last commit 11mo ago
  • ⚠ Concentrated ownership — top contributor handles 69% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live fnando/browser repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/fnando/browser.

What it runs against: a local clone of fnando/browser — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in fnando/browser | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | Last commit ≤ 363 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>fnando/browser</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of fnando/browser. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/fnando/browser.git
#   cd browser
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of fnando/browser and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "fnando/browser(\\.git)?\\b" \\
  && ok "origin remote is fnando/browser" \\
  || miss "origin remote is not fnando/browser (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 363 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~333d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/fnando/browser"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

A Ruby gem that parses HTTP User-Agent strings to identify browsers, devices, platforms, and bots with high accuracy. It provides detailed detection (Chrome vs Chromium, IE version ranges, device type like iPhone/iPad/Kindle, OS versions) and integrates directly into Rails ActionController for request-level browser detection. Monolithic gem structure: lib/browser/base.rb and lib/browser/browser.rb form the core detection engine. Device detection split into lib/browser/device/*.rb (iPhone, Android, Kindle, etc.). Bot detection uses lib/browser/bot/ with pluggable matchers (KeywordMatcher, KnownBotsMatcher, EmptyUserAgentMatcher). External data in bot_exceptions.yml and bots.yml. ActionController middleware at lib/browser/action_controller.rb.

👥Who it's for

Rails developers building responsive web applications who need reliable client-side detection to serve device-specific content, feature flags, or graceful degradation without JavaScript UA parsing. Also useful for analytics teams and API servers that need to classify requests.

🌱Maturity & risk

Production-ready and actively maintained. The repo has comprehensive GitHub Actions CI (ruby-tests.yml), multiple Gemfile versions supporting Rails 7.0+, well-organized test structure, and detailed CHANGELOG.md. Last activity appears current based on gemfiles for recent Rails versions.

Low risk. Single maintainer (fnando) is a concern for long-term viability, but the gem has narrow, stable scope (UA parsing) with minimal external dependencies. UA detection requires periodic updates to bot_exceptions.yml and bots.yml as new bots/browsers emerge, so maintenance cadence matters. No major breaking changes visible in recent structure.

Active areas of work

Active maintenance with recent Rails 7.0 and 7.1 Gemfile additions. Focus appears to be keeping bot/browser detection rules current (bot_exceptions.yml, bots.yml) rather than major feature work. Likely processing new UA patterns and bot discoveries.

🚀Get running

git clone https://github.com/fnando/browser.git
cd browser
bundle install
bundle exec rake test

Daily commands:

bundle exec rake test          # Run test suite
bundle exec rubocop           # Lint check
rake -T                        # See all available tasks

🗺️Map of the codebase

  • lib/browser/browser.rb: Core browser detection logic with methods like chrome?, firefox?, edge?—entry point for most detection queries
  • lib/browser/base.rb: Foundation class handling User-Agent parsing and version extraction used by all detection subclasses
  • lib/browser/device/base.rb: Device detection parent class; all device-specific detection (iPhone, Android, Kindle) inherits from here
  • lib/browser/bot/known_bots_matcher.rb: Loads and matches against bots.yml and bot_exceptions.yml to classify User-Agents as bots with search_engine? classification
  • lib/browser/action_controller.rb: Rails integration that injects request.browser helper into ActionController, enabling detection in controllers/views
  • bots.yml: Canonical list of known bot User-Agent patterns; core data file requiring maintenance as new bots appear
  • bot_exceptions.yml: Override rules for false positives/negatives in bot detection; allows fine-tuning without modifying bots.yml
  • lib/browser/detect_version.rb: Centralized version string extraction logic used across all browser/device/platform detection to parse version numbers

🛠️How to make changes

For new browser detection: add method to lib/browser/browser.rb following existing patterns (firefox?, chrome?, etc.) and update detection logic in lib/browser/base.rb. For new devices: create lib/browser/device/[name].rb inheriting Device::Base. For bot updates: edit bot_exceptions.yml (overrides) and bots.yml (primary list), then update lib/browser/bot/known_bots_matcher.rb to use them. Tests in test/ mirror the lib structure.

🪤Traps & gotchas

No required environment variables. The gem is self-contained and data-driven (bots.yml, bot_exceptions.yml are loaded at parse time, not runtime). Watch out: User-Agent string parsing is regex-based and inherently fragile—new browser releases or bot implementations may not be detected until bots.yml is updated. Rails integration expects ActionController to be loaded; won't fail but browser detection helper won't exist if Rails isn't present. Accept-Language parsing is lightweight but locale strings vary widely; test with real Accept-Language headers if building locale features on top.

💡Concepts to learn

  • User-Agent string parsing via regex — The entire gem is built on regex matching against UA strings; understanding how patterns are layered (bot detection first, then browser, then device) is essential to debugging false positives or extending detection
  • Pluggable matcher pattern (bot detection) — lib/browser/bot/*.rb uses multiple independent matchers (EmptyUserAgentMatcher, KeywordMatcher, KnownBotsMatcher) that each vote on whether a UA is a bot; new matchers can be added without modifying existing code
  • Accept-Language header parsing — lib/browser/accept_language.rb parses RFC 7231 Accept-Language to extract preferred locales with quality weights; needed if you're using browser.accept_language for i18n routing
  • Version constraint matching (IE version ranges) — Methods like ie?(['>8', '<10']) use Gem::Requirement for version comparison; allows semantic version matching without writing custom comparison logic
  • Middleware integration pattern (Rails ActionController) — lib/browser/action_controller.rb injects request.browser as a helper using ActionDispatch middleware; understanding how this hooks into Rails request lifecycle is key to using it effectively
  • Inheritance vs composition for browser/device/platform detection — The gem uses both: base classes for common logic (Browser::Base) but composition for cross-cutting concerns (browser.device, browser.platform objects); mixing both patterns requires careful design
  • YAML-driven data files for bot/exception lists — bots.yml and bot_exceptions.yml allow non-developers to maintain detection rules without code changes; critical for long-term maintenance as new bots emerge
  • woothee/woothee — Multi-language UA parser (JavaScript, Python, Ruby) solving same problem with different philosophy; good reference for alternative parsing strategies
  • userAgent/detect.py — Python equivalent for UA detection; useful if you need cross-platform user-agent detection beyond Ruby
  • matthewd/rails-hybrid-renderer — Companion gem for Rails that uses browser detection to serve mobile vs desktop templates—typical use case for fnando/browser
  • fnando/name-of-person — Same maintainer (fnando); demonstrates similar gem structure and maintenance style across Ruby utility libraries
  • useragent/useragent — Older Ruby UA parser now deprecated; fnando/browser was built as a more maintained alternative with Rails integration

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive test coverage for lib/browser/device/* detectors

The repo has 20+ device detector classes (iPad, iPhone, Android, PlayStation, Xbox, etc.) but there's no visible test file structure in the repo listing. Given the complexity of device detection via user agents and the critical nature of accurate detection, adding unit tests for each device class would catch regressions and edge cases. This is especially important since device detection logic is notoriously fragile across different user agent formats.

  • [ ] Create test/browser/device/ directory structure mirroring lib/browser/device/
  • [ ] Add unit tests for lib/browser/device/iphone.rb, ipad.rb, android.rb covering various iOS/Android versions and user agent formats
  • [ ] Add tests for gaming devices (lib/browser/device/playstation*.rb, xbox*.rb, switch.rb) with real-world user agent strings
  • [ ] Verify tests run in ruby-tests.yml workflow and achieve >90% coverage for device detection classes

Add integration tests for lib/browser/action_controller.rb Rails middleware

The repo includes ActionController integration (lib/browser/action_controller.rb) but there's no evidence of Rails integration tests. This middleware is critical for Rails developers using the gem, and integration tests would ensure compatibility across Rails 7.0 and 7.1 (already in gemfiles/). This prevents breaking changes in future Rails releases.

  • [ ] Create test/browser/action_controller_test.rb with Rails request helpers
  • [ ] Test that browser object is properly injected into ActionController::Base (via before_action or similar)
  • [ ] Add tests for both gemfiles/7_0.gemfile and gemfiles/7_1.gemfile in CI
  • [ ] Verify middleware correctly parses User-Agent from request headers and populates browser helper methods

Add test coverage for bot detection (lib/browser/bot/*.rb) with real bot user agents

The repo has sophisticated bot detection with three matchers (EmptyUserAgentMatcher, KeywordMatcher, KnownBotsMatcher) that rely on bots.yml and bot_exceptions.yml config files. Without tests, it's unclear if bot detection accurately identifies crawlers, which affects analytics and security. Real-world bot user agents from Googlebot, Bingbot, etc. should be tested to ensure the keyword and known_bots matchers work correctly.

  • [ ] Create test/browser/bot/known_bots_matcher_test.rb and test/browser/bot/keyword_matcher_test.rb
  • [ ] Add test cases using real user agent strings from Googlebot, Bingbot, Yandexbot, and other major crawlers loaded from bots.yml
  • [ ] Test edge cases: malformed bots.yml entries, empty user agents (EmptyUserAgentMatcher), and bot exceptions from bot_exceptions.yml
  • [ ] Add regression tests to ensure newly detected bots don't break existing bot?() method behavior

🌿Good first issues

  • Add detection tests for emerging browsers (check if lib/browser/browser.rb has test coverage for all ?-methods like sougou_browser?, epiphany?—likely some are missing tests in test/)
  • Expand Device::Unknown fallback handling—many devices in lib/browser/device/ may not cover all tablets/consoles; could add PlayStation Vita or Nintendo Switch detection tests or new device types
  • Create a bot detection reason logger—Bot#why? exists but lib/browser/bot/*.rb matchers don't expose which pattern matched; adding diagnostic output would help debug false positives

Top contributors

Click to expand

📝Recent commits

Click to expand
  • dd88933 — Add development dependencies. (fnando)
  • 0fae12e — Update workflow dependencies. (fnando)
  • 251767a — Fix branch reference from master to main (#556) (Jealrock)
  • f5dc0c9 — Bump up version (6.2.0). (fnando)
  • 7488c3b — Add funding_uri to gemspec (#549) (andrew)
  • 6e9b7be — Add epiphany (gnome web) browser detection. (#552) (fnando)
  • e71ee1b — Bump up version (6.1.0) (fnando)
  • ed6473d — Detect Chrome when requesting desktop site. (#548) (fnando)
  • a263513 — Add AppSignal and Checkly bots (#546) (conarro)
  • 0b2645a — Add more bots (mostly related to AI crawlers). (fnando)

🔒Security observations

The Browser gem is a relatively low-risk library focused on parsing and detecting browser types from user agent strings. It doesn't appear to have critical security vulnerabilities, as it primarily performs detection and classification rather than executing user input or accessing sensitive resources. The main security considerations are around proper handling of user agent data when it's logged or displayed elsewhere in the application, avoiding ReDoS in regex patterns, and keeping bot detection lists current. The codebase follows good practices with no obvious hardcoded credentials or dangerous patterns. Dependency security depends on the gem's direct and transitive dependencies, which should be regularly audited using tools like 'bundle audit' or Dependabot.

  • Low · User Agent String Processing Without Sanitization — lib/browser.rb, lib/browser/browser.rb, and related detection modules. The Browser gem processes user agent strings directly from HTTP requests. While the library itself focuses on detection rather than output, if user agent data is logged or displayed without proper escaping, it could potentially be exploited for log injection or XSS attacks in admin panels that display user agent information. Fix: Ensure that any user agent strings are properly escaped when logged or displayed in web interfaces. Use context-appropriate escaping (HTML escaping for web output, JSON escaping for JSON output, etc.).
  • Low · Hardcoded Bot Detection Lists — bot_exceptions.yml, bots.yml, lib/browser/bot/known_bots_matcher.rb. The library uses hardcoded bot and exception lists in bot_exceptions.yml and bots.yml files. These lists require manual maintenance and updates. Outdated bot detection could miss new malicious bots or misclassify legitimate traffic. Fix: Implement a mechanism to regularly update bot detection lists. Consider using external bot detection services or community-maintained datasets. Document the update frequency and process.
  • Low · Regular Expression Complexity in User Agent Parsing — lib/browser/detect_version.rb and browser detection modules (chrome.rb, firefox.rb, etc.). User agent parsing often involves complex regular expressions. While not immediately exploitable, poorly crafted regexes could be vulnerable to ReDoS (Regular Expression Denial of Service) attacks if user agents with specially crafted patterns are processed. Fix: Review all regular expressions used in user agent parsing for potential ReDoS vulnerabilities. Use regex testing tools to identify catastrophic backtracking. Consider adding input length validation for user agent strings.
  • Low · No Input Validation on User Agent String Length — lib/browser.rb, lib/browser/browser.rb. The library accepts user agent strings without apparent length validation. Extremely long user agent strings could cause performance issues or memory exhaustion. Fix: Implement reasonable length limits on user agent strings before processing (e.g., max 500-1000 characters). RFC 7231 doesn't mandate a limit, but practical limits improve security and performance.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.