# User-Agent Parser - Browser, OS, Device + Bot Detection (`eliai/user-agent-parser`) Actor

Parse up to 1,000 User-Agent strings per run: browser + version, OS, device, engine, CPU, and isBot verdict covering search crawlers, AI crawlers (GPTBot, ClaudeBot...), HTTP libraries and monitors. $0.0004 per UA, no start fee, junk strings never charged. For log analysis and traffic audits.

- **URL**: https://apify.com/eliai/user-agent-parser.md
- **Developed by:** [Broke to Built](https://apify.com/eliai) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.32 / 1,000 parsed user agents

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## User-Agent Parser - Browser, OS, Device and Bot Detection, in Bulk

**Turn raw User-Agent strings into structured fields**: browser and version, operating system, device
type and vendor, rendering engine, CPU architecture - plus an `isBot` verdict covering search
crawlers, AI training crawlers, SEO tools, social preview fetchers, HTTP libraries and uptime
monitors. Up to 1,000 UAs per run. $0.0004 per string. Implausible strings are recorded free.

Log analysis, traffic-quality audits, analytics enrichment, filtering bots out before you bill for
traffic: they all start with "what actually sent this request?"

### What you get

Per string, one record with these exact fields:

- `ok` - true when the string was parsed
- `userAgent` - the string you sent
- `browser` - `name`, `version`, `major`
- `os` - `name`, `version`
- `device` - `vendor`, `model`, `type` (mobile, tablet, console, smarttv, wearable, embedded)
- `engine` - `name`, `version`
- `cpu` - `architecture`
- `isBot` - boolean
- `error` - present instead of the fields when the string was not a plausible UA. Never charged.

Unmatched fields come back as `null`, never missing, so the record shape is stable across every row.

### Example 1: a real mobile browser

Input:

```json
{ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1" }
```

Output (real run, 2026-08-15):

```json
{
  "ok": true,
  "browser": { "name": "Mobile Safari", "version": "17.5", "major": "17" },
  "os": { "name": "iOS", "version": "17.5" },
  "device": { "vendor": "Apple", "model": "iPhone", "type": "mobile" },
  "engine": { "name": "WebKit", "version": "605.1.15" },
  "cpu": { "architecture": null },
  "isBot": false
}
```

### Example 2: an AI crawler and a command-line client

Input:

```json
{
  "userAgents": [
    "Mozilla/5.0 (compatible; GPTBot/1.1; +https://openai.com/gptbot)",
    "curl/8.4.0"
  ]
}
```

Output (real run, same session, trimmed):

```json
[
  { "userAgent": "Mozilla/5.0 (compatible; GPTBot/1.1; +https://openai.com/gptbot)", "ok": true, "isBot": true,
    "browser": { "name": null, "version": null, "major": null }, "os": { "name": null, "version": null } },
  { "userAgent": "curl/8.4.0", "ok": true, "isBot": true,
    "browser": { "name": null, "version": null, "major": null }, "os": { "name": null, "version": null } }
]
```

Both are flagged `isBot: true` even though neither carries a browser or OS to parse - that is the
curated signature list doing the work the parsing library alone would not.

**When `userAgents` is filled, the single `userAgent` field is ignored** - you are charged for the
strings you listed and nothing else.

### Example 3: enriching a log file

Input:

```json
{ "userAgents": ["...UA from line 1...", "...UA from line 2...", "..."], "maxItems": 1000 }
```

One record and one charge per string, up to 1,000 per run. Join the results back onto your log rows
by the `userAgent` field, then split on `isBot` to separate real traffic from crawlers.

### Pricing

**$0.0004 per User-Agent parsed.** No start fee. One event covers one string parsed into every field
above plus the bot verdict. Strings that are not plausible User-Agents (under 3 characters, or
containing control characters) are recorded as `ok: false` and never charged, so a log file with
mangled rows only bills for the rows that parsed.

Enriching 10,000 log lines costs $4.

Honest comparison: on 2026-08-07 a store search for "user agent parser" and "ua parser" returned
scrapers rather than parsers - there was no directly comparable paid incumbent to quote a price
against, so this is priced at the floor of our ladder rather than against a competitor.

Also honest: `ua-parser-js` is a free open-source library, and it is exactly what this Actor uses. If
you already run Node or Python, parsing locally costs nothing. Pay for this when you want it as a
hosted step, in bulk, inside a no-code pipeline, or as a tool an AI agent can call - and for the
`isBot` list, which the library does not give you.

### When NOT to use this

- **Detecting adversarial bots.** A scraper that sends a perfect Chrome User-Agent is indistinguishable
  from Chrome by string alone. No UA parser can fix a lying client. Combine with IP reputation, rate
  patterns and behavioural signals for anything adversarial. This catches the honest bots - which is
  most crawler traffic.
- **Getting exact browser versions from modern Chrome.** Chrome freezes its UA version. Fine-grained
  version and platform data live in Client Hints headers (`Sec-CH-UA-*`), which are not part of the UA
  string and cannot be recovered from it.
- **Device model detail for desktops.** Desktop UAs legitimately carry no device type, vendor or
  model - the spec only marks mobile, tablet and similar explicitly. `null` there is correct, not a
  parse failure.
- **Brand-new browser releases on day one.** Parsing follows the pinned library version, so a browser
  released after it can land as an unknown until the library updates.
- **A handful of strings, once.** Free web parsers exist for that. This is for volume.

### Honest limits

- Parsing via `ua-parser-js` 1.0.41 (pinned) - the de-facto standard library.
- `isBot` combines the library's own classification with a curated substring list (search crawlers,
  AI crawlers, SEO tools, social fetchers, HTTP clients, headless browsers, monitors). It is a
  signature list, so it is exact on the bots it knows and blind to ones it does not.
- Up to 1,000 strings per run.

### FAQ

**How do I parse User-Agent strings in bulk?**
Send `{"userAgents": [...]}` with up to 1,000 strings. Each returns one record with the same field
shape, so the output drops straight into a dataframe or a database table.

**Which bots does it detect?**
Search crawlers (Google, Bing, Yandex, Baidu, DuckDuckGo, Sogou), AI crawlers (GPTBot, ChatGPT,
ClaudeBot and Anthropic, CCBot, PerplexityBot, Amazonbot, Bytespider), SEO tools (Ahrefs, Semrush,
MJ12, DotBot, Screaming Frog), social preview fetchers (Facebook, Twitter, LinkedIn, Slack, Discord,
WhatsApp, Telegram, Pinterest, Reddit), HTTP clients (curl, wget, python-requests, axios, okhttp,
Go, Java, Guzzle, node-fetch), headless and scraping stacks (HeadlessChrome, PhantomJS, Scrapy), and
uptime monitors (Pingdom and similar).

**Can I use it to find AI training crawlers in my logs?**
Yes, this is a common use. Parse your log's UA column in batches, filter `isBot: true`, then match
the specific names in `userAgent` for the AI crawlers you care about before deciding on robots.txt
rules.

**Does it handle Client Hints or Chrome's reduced User-Agent?**
It parses what the string contains - Chrome's frozen UA still yields browser, OS and engine. The
fine-grained data lives in separate headers and is not recoverable from the UA string.

**Why is `device.type` null for most of my traffic?**
Because most of it is desktop, and desktop UAs do not declare a device type. That is correct
behaviour, not a miss.

**What counts as an implausible string?**
Under 3 characters, or containing control characters. Those return `{"ok": false, "error": "..."}`
and are never charged, so a mangled log column does not cost you.

**Can an AI agent call this as a tool?**
Yes, through the Apify MCP server - an agent investigating traffic can classify a UA without you
writing an integration.

### Use from code or AI agents

```bash
curl -s "https://api.apify.com/v2/acts/EliAI~user-agent-parser/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -X POST -H 'Content-Type: application/json' \
  -d '{"userAgents": ["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36"]}'
```

Agents: connect [Apify MCP](https://mcp.apify.com) and call the `EliAI/user-agent-parser` tool.

- **Capability:** parse one or many User-Agent strings into browser / os / device / engine / cpu plus a bot verdict
- **Required input:** `userAgent` (string) or `userAgents` (array)
- **Returns:** one record per string; `browser.name` and `isBot` are the headline fields
- **Bounded:** 1,000 strings per run; failures isolate per string
- **Side effects:** none

# Actor input Schema

## `userAgent` (type: `string`):

A single User-Agent string to parse.

## `userAgents` (type: `array`):

Multiple User-Agent strings to parse in one run. When this list is filled, the single User-Agent above is ignored, so you are only charged for the strings you listed.

## `maxItems` (type: `integer`):

Maximum number of User-Agent strings to parse in a single run.

## Actor input object example

```json
{
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
  "userAgents": [
    "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1",
    "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
  ],
  "maxItems": 50
}
```

# Actor output Schema

## `results` (type: `string`):

Every item this run produced, as JSON.

## `resultsCsv` (type: `string`):

The same items as a spreadsheet-ready CSV.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "userAgents": [
        "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1",
        "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("eliai/user-agent-parser").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "userAgents": [
        "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1",
        "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("eliai/user-agent-parser").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
  "userAgents": [
    "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1",
    "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
  ]
}' |
apify call eliai/user-agent-parser --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,eliai/user-agent-parser"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/1R0iYzaOTekZ32v0B/builds/4cbkSRrAsV3Cwf9lq/openapi.json
