I need to check the user's operating system and conditionally render an element based on the result.
<kbd>Ctrl + K</kbd>
for Windows and <kbd>⌘ + K</kbd>
for MacOS.
I could do this in a client component; however, I wanted to avoid the flicker effect that occurs during hydration, so I tried to implement it server-side instead. I wrote this middleware.ts code below:
import { NextResponse, type NextRequest, userAgent } from "next/server";
export function middleware(request: NextRequest) {
const url = request.nextUrl
const { os } = userAgent(request)
url.searchParams.set('os', os.name || "");
return NextResponse.rewrite(url);
}
The middleware adds the user's operating system name as a query parameter to the URL of incoming requests, but now the page is being dynamically generated because of searchParams. Same thing happens if I try to use cookies or headers instead. As far as I know, it's not possible to use something like generateStaticParams to opt back into static generation.
Perhaps this can be solved if I use a dynamic or parallel route, but there must be a simpler solution that I am missing here.
I need to check the user's operating system and conditionally render an element based on the result.
<kbd>Ctrl + K</kbd>
for Windows and <kbd>⌘ + K</kbd>
for MacOS.
I could do this in a client component; however, I wanted to avoid the flicker effect that occurs during hydration, so I tried to implement it server-side instead. I wrote this middleware.ts code below:
import { NextResponse, type NextRequest, userAgent } from "next/server";
export function middleware(request: NextRequest) {
const url = request.nextUrl
const { os } = userAgent(request)
url.searchParams.set('os', os.name || "");
return NextResponse.rewrite(url);
}
The middleware adds the user's operating system name as a query parameter to the URL of incoming requests, but now the page is being dynamically generated because of searchParams. Same thing happens if I try to use cookies or headers instead. As far as I know, it's not possible to use something like generateStaticParams to opt back into static generation.
Perhaps this can be solved if I use a dynamic or parallel route, but there must be a simpler solution that I am missing here.
Share Improve this question asked Feb 13 at 18:14 Orkhan FattayevOrkhan Fattayev 11 Answer
Reset to default 0You can detect os based on user-agent
header. Here is a example:
getOSFromUA:
export const getOSFromUA = (userAgent: string | null): string | null => {
if (!userAgent) return null
const ua = userAgent.toLowerCase()
if (ua.includes('win')) return 'Windows'
if (ua.includes('mac')) return 'macOS'
if (ua.includes('linux')) return 'Linux'
if (ua.includes('android')) return 'Android'
if (ua.includes('like mac') || ua.includes('ios')) return 'ios'
return null
}
Server component:
import { getOSFromUA } from '@/utils'
import { headers } from 'next/headers'
const Home = async () => {
const headersRes = await headers()
const os = getOSFromUA(headersRes.get('user-agent'))
return <div>
Your operating system is {os}
</div>
}
export default Home