Server-side user-agent parsing without the manual string gymnastics.
Ever needed to redirect mobile users or block bots before the page even renders? Next.js has a built-in helper for exactly that: userAgent. Instead of manually parsing raw header strings, you get a clean structured object with everything you need, right inside Middleware or a Route Handler.
What is userAgent?
userAgent is a helper exported from next/server. Pass it the incoming NextRequest and it returns a parsed object with structured client data — no regex required.
import { userAgent } from 'next/server'
Basic Usage
Here's a minimal example inside middleware:
import { NextRequest, NextResponse, userAgent } from 'next/server'
export function middleware(request: NextRequest) {
const { device, browser, os, isBot } = userAgent(request)
console.log(device) // { type: 'mobile', model: 'iPhone', vendor: 'Apple' }
console.log(browser) // { name: 'Safari', version: '17.0' }
console.log(os) // { name: 'iOS', version: '17.0' }
console.log(isBot) // false
return NextResponse.next()
What You Get
device
| Attribute | Sample Values |
|---|---|
type |
mobile, tablet, console, smarttv |
model |
iPhone, Galaxy S21 |
vendor |
Apple, Samsung, Google |
if (device.category === 'mobile') {
return NextResponse.redirect(new URL('/m', request.url))
}
browser
| Attribute | Sample Values |
|---|---|
name |
Chrome, Safari, Firefox |
version |
Major version string |
if (browser.identifier === 'Safari') {
// implement fixes or headers specific to Safari
}
OS
| Attribute | Sample Values |
|---|---|
name |
iOS, Android, Windows, macOS |
version |
OS version string |
if (os.platform === 'iOS') {
// manage behaviors specific to iOS
}
isBot
A boolean. Returns true if the request originates from a recognized crawler. Useful for delivering streamlined, SEO-optimized responses or skipping analytics pings entirely.
if (isAutomated) {
// bypass heavy JS hydration, deliver static HTML only
return NextResponse.rewrite(new URL('/seo-version', request.url))
}
cpu
Reveals the CPU architecture — useful when serving distinct WASM bundles for arm versus amd64 devices.
const { cpu } = userAgent(req)
console.log(cpu.arch) // 'arm', 'amd64', etc.
Practical Everyday Applications
- Send mobile users to /m before the layout loads
- Serve simpler static HTML to bots to improve SEO performance
- Apply server-side response headers tailored to specific browsers
- Skip analytics pings for crawlers
- Deliver CPU architecture-specific WASM bundles
A useful starting point — reroute mobile users before the layout even loads:
export function middleware(req: NextRequest) {
const { device } = userAgent(req)
if (device.category === 'mobile') {
return NextResponse.redirect(new URL('/m', req.url))
}
return NextResponse.next()
}
Key Things to Remember
Server-exclusive. You can use userAgent in Middleware and Route Handlers — not in Client Components. On the client side, use navigator.userAgent instead.
It makes your route dynamic. Using userAgent opts your route out of full static generation. Next.js won't cache it at build time since the response depends on the incoming request. Keep that in mind for performance-sensitive pages.
Not entirely reliable. The user-agent string comes from the client and can be spoofed or modified. Use it for progressive enhancement decisions, not hard security gating.
| Feature |
userAgent (Next.js) |
navigator.userAgent |
|---|---|---|
| Runs on | Server (Middleware / SSR) | Client only |
| Parsing | Built-in, structured | Manual (string) |
| Use case | Redirect, rewrite, SSR logic | Client-side UI logic |
| Bot detection |
isBot included |
Manual regex |
| Spoofable | Yes | Yes |
Summary
To understand your users at the request level in Next.js, userAgent is the right tool. It provides structured data about devices, browsers, operating systems, and bots — without depending on client-side APIs.
A practical starting point: use it in middleware to direct mobile users to /m while keeping desktop traffic on the main layout — no client-side JavaScript, no layout shift for the user.

Top comments (0)