API reference · v1

One endpoint, one JSON shape.

Base URL https://useragentparser.xyz. Requests and responses are JSON over HTTPS. Every key in the response is always present; unknown values are null.

Quickstart

  1. Get a free API key — 1,000 credits, no card.
  2. Send a user-agent string. One request = one credit.
curl https://useragentparser.xyz/v1/parse \
  -H "X-Api-Key: $UAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"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"}'

Authentication

Send your API key in the X-Api-Key header (Authorization: Bearer uap_… works too). Get a key on the account page — it is shown once; you can generate a new one at any time, and the previous key stops working within a minute.

Keep the key on your server. If you call the API from a browser, anyone can read the key from your page and spend your credits.

Parse one user agent

POST /v1/parse
Content-Type: application/json
X-Api-Key: uap_…

{"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"}

Costs 1 credit. The API never reads your own User-Agent header — always pass the string you want parsed.

There is deliberately no GET variant: URLs end up in request logs, and we promise not to log the strings you send. A GET returns 405 explaining this — use POST with a JSON body.

Response fields

{
  "browser": { "name": "Mobile Safari", "version": "17.5", "major": "17", "type": null },
  "engine":  { "name": "WebKit", "version": "605.1.15" },
  "os":      { "name": "iOS", "version": "17.5" },
  "device":  { "type": "mobile", "vendor": "Apple", "model": "iPhone" },
  "cpu":     { "architecture": null },
  "bot":     { "isBot": false, "isAIBot": false }
}
FieldTypeValues
browser.namestring | nulle.g. Chrome, Mobile Safari, Edge, GPTBot, curl
browser.versionstring | nullFull version as written in the string, e.g. 131.0.0.0
browser.majorstring | nullMajor version only, e.g. 131 — handy for grouping
browser.typestring | nullcrawler, cli, library, fetcher, inapp, email, mediaplayer — or null for an ordinary browser
engine.namestring | nullRendering engine, e.g. Blink, WebKit, Gecko
engine.versionstring | nulle.g. 605.1.15
os.namestring | nulle.g. Windows, macOS, iOS, Android, Linux
os.versionstring | nulle.g. 17.5, 14, 10
device.typestring | nullmobile, tablet, smarttv, console, wearable, xr, embedded — or null. Desktop browsers report no device type, so null usually means desktop.
device.vendorstring | nulle.g. Apple, Samsung, Google
device.modelstring | nulle.g. iPhone, SM-S921B, Pixel 8
cpu.architecturestring | nulle.g. amd64, arm64, ia32 — when the string reveals it
bot.isBotbooleantrue for crawlers, CLIs, HTTP libraries and fetchers
bot.isAIBotbooleantrue for AI crawlers and assistants (GPTBot, ClaudeBot, PerplexityBot, …)

Every key is always present; values the string does not reveal are null. We may add new fields in future; we will not remove or rename existing ones within /v1.

Each successful response carries X-Credits-Remaining: your approximate remaining balance.

Parse up to 100 at once

POST /v1/parse/batch
{"userAgents": ["Mozilla/5.0 (…)", "curl/8.5.0", ""]}

→ {"results": [ {…parsed…}, {…parsed…}, {"error": {"code": "invalid_request", "message": "…"}} ]}

Results come back in input order. Each valid string costs 1 credit; invalid entries return an inline error and are free.

Errors

Errors use HTTP status codes and a JSON body: {"error": {"code": "…", "message": "…"}}.

StatuscodeMeaning
400invalid_requestMissing/empty user agent, or longer than 2,048 characters
400—Malformed JSON body (rejected before it reaches the API; the body may not be JSON)
401unauthorizedMissing or invalid API key
402insufficient_creditsNot enough credits — top up; the same key keeps working afterwards
405method_not_allowedGET with the user agent in the URL — use POST
413payload_too_largeMore than 100 items in a batch, or body over 256 KB
5xxinternalOur fault — safe to retry with backoff; not charged

Credits

  • 1 credit = 1 parsed user agent. New accounts get 1,000 free credits.
  • Each purchase is valid for 24 months. Credits expiring soonest are used first.
  • No subscription and no automatic charges: when credits run out, requests return 402 until you top up.
  • Balance accounting is near-real-time; under heavy parallel load you may briefly be served a few requests past zero — those are on us.
  • Packs start at €5 for 25,000 credits; see pricing. Prices exclude tax; taxes may apply depending on your location and are calculated at checkout. Every purchase comes with an invoice.

Server-side Google Tag Manager

Streaming events from server-side GTM to BigQuery or a warehouse? Our free sGTM variable template adds browser, OS, device and bot fields to every event — no code, no parser library in your container.

Download the sGTM template (.tpl)

  1. In your server container: Templates → Variable templates → New → ⋮ → Import, choose the downloaded file, Save.
  2. Create a Constant variable holding your API key, e.g. {{UAP key}}.
  3. Variables → New → the UserAgent Parser template you imported: API key {{UAP key}}, pick what to return — e.g. Device category, Browser name, Is AI crawler or the full object.
  4. Use the variable in your BigQuery / warehouse tag (or any tag) like any other value.
SettingDefaultNotes
User-agent sourceevent data user_agentSet by the GA4 client. Alternatively the incoming request's User-Agent header or a custom value.
Returnfull objectOr one field: browser.name, os.name, device.type, bot.isAIBot, … plus Device category (desktop / mobile / tablet / bot / …).
Cacheon, 24 hResults are cached per user-agent on each sGTM instance, so returning browsers cost one credit per instance per day — not one per event.
Timeout2,000 msOn timeout, errors or an empty balance the variable is simply undefined; your event is never blocked.

Each variable that misses the cache makes its own request. If you need several fields per event, use one variable returning the full object where your tag accepts objects, or rely on the cache — once a user-agent is cached, every further field for it is free.

n8n, Make and Zapier

No-code tools can’t install a parser library, but they can make an HTTP request. Use their generic HTTP step:

Method      POST
URL         https://useragentparser.xyz/v1/parse
Header      X-Api-Key: ‹your key, stored as a credential›
Body type   JSON
Body        { "userAgent": ‹user-agent field from the trigger› }

Then branch on the result, e.g. device.type equals mobile, or bot.isAIBot is true. In n8n this is the HTTP Request node, in Make the HTTP → Make a request module, in Zapier Webhooks by Zapier → POST.

Browsers and CORS

The parse endpoints send CORS headers for any origin, so they can be called from a browser — but see the note about exposing your key under Authentication.

What we keep

We do not store or log the user-agent strings you send: they are parsed in memory and only a request count is kept against your credits. The API accepts them in POST bodies only, never in URLs, so they never land in URL logs. Details in the privacy policy.