isMobile: a 1.3 kB user agent check that tells you when not to use it
A simple JS library that detects mobile devices.
At a glance
- What is it?
- The README opens by recommending responsive design instead. What remains is a small, honest detector with a documented iPadOS heuristic and an announced breaking change.
- Who is it for?
- isMobile is a good library for the narrow case it was built for, which is a redirect or a server-side rendering decision where you must branch on device class before the page renders. It is a poor choice for deciding layout, and the README says so before it describes a single function.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 10 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The README argues against using it
This is the most distinctive thing about the project. Under the heading asking why use isMobile, the browser section opens by saying you might not need this library, that in most cases responsive design solves controlling how things render across screen sizes, and that a mobile first approach is recommended instead.
It then names the edge case that produced the library: redirecting users to a completely separate mobile site. That is a decision you have to make before rendering, which is exactly the situation responsive CSS cannot solve, because a redirect is a navigation rather than a layout.
The size constraint follows from that use case. The README states the script is currently about 1.3 kB minified and had to stay small and simple because it needs to execute in the `<head>`. The reasoning is stated carefully: JavaScript in the head blocks downloading and rendering of all assets while it parses and executes, which is generally bad. For mobile redirection the author does not mind, because the point is to start the redirect before the device begins downloading anything else. For non-mobile platforms the script must execute fast so the browser gets back to loading assets.
That is a coherent design brief for a 1.3 kB library, and it explains most of the decisions that follow.
Two call shapes, one result object
In a browser the library runs during initial page load and creates a JavaScript object with the results. In Node you import the function and pass a user agent string, and it returns the same shape of object. The README is precise that in a browser these are properties of the global `isMobile` object, while in Node `isMobile` is whatever you named the variable.
The Node side is three lines:
import isMobile from 'ismobilejs';
const userAgent = req.headers['user-agent'];
console.log(isMobile(userAgent).any);The browser side, when imported through a bundler, calls the exported function. With no argument it reads the browser's navigator, and you can also pass `window.navigator` explicitly. Both forms are shown in the README, and the argument being optional was a bug fix in v1.1.1, closing issue 129.
The server-side motivation the README gives is to minimise the bytes sent back to visitors, plus the general case of having your own use for it.
Every property it sets, group by group
The result object is documented as a set of booleans, and the grouping is the API. Apple has `phone`, `ipod`, `tablet`, and `device` for any mobile Apple device. Android has `phone`, `tablet`, and `device`, with a note that OkHttp user agents match the Android group. Amazon Silk has its own `phone`, `tablet` and `device`, and also passes the Android checks.
Windows has `phone`, `tablet` and `device` for Windows Phone, Windows Tablet and any Windows mobile device. An Other group covers `blackberry_10`, `blackberry`, `opera` for Opera Mini, `firefox`, `chrome`, and `device` for any of them.
Three aggregate groupings sit above those, and they are the ones most callers actually want: `any` for any device matched, `phone` for anything in a phone group, and `tablet` for anything in a tablet group. In practice a redirect check reads `isMobile.any` and nothing else, which is the smallest surface a redirect needs.
iPadOS in desktop mode, and why the user agent is not enough
The most technically interesting part of the README is the iPadOS handling, and it comes with an unusually good explanation of its own limits.
An iPad in desktop browsing mode reports a Macintosh user agent, so server-side detection from the User-Agent header alone cannot identify it. In the browser, isMobile uses a heuristic: `navigator.platform === 'MacIntel'` together with `navigator.maxTouchPoints > 1`.
That heuristic is why the call signature matters. Passing only `window.navigator.userAgent` discards the platform and touch information the heuristic needs, so you must call `isMobile()` or `isMobile(window.navigator)`. A navigator-shaped object with `userAgent`, `platform` and `maxTouchPoints` also works.
The README then warns about device emulation: emulating a device may change the user agent without supplying the same platform and touch values as real hardware, so an emulated result is not verification on a physical device, and all three values should be checked when investigating a mismatch. It closes the section by saying device detection is a heuristic and that responsive design or feature detection are preferable where those address the use case.
Distribution: npm, bundlers, and a jsDelivr script tag
Install for Node is a standard package add, and the published name differs from the repository name:
npm install ismobilejsYarn works the same way. The README also documents loading a published browser bundle from jsDelivr in a plain HTML page, pinning a specific version and reading the global result object:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/isMobile.min.js"></script>
<script>
console.log(isMobile.apple.tablet);
</script>The example pins 1.1.1 with the note that it includes the iPadOS detection heuristic. There is a warning about inlining: if you inline `dist/isMobile.min.js` from your chosen release, a separately maintained copy of the minified implementation can omit later detection fixes.
The build section gives the manual path. Use Node.js 24 via `nvm use`, then `npm ci` and `npm run build`, which produces three outputs: a CommonJS build in `./cjs/index.js`, an ES module build in `./esm/index.js`, and a browser build at `./dist/isMobile.min.js`, with types written to `types`. The `package.json` confirms that mapping with `main`, `module`, `jsdelivr` and `types` fields, and marks `sideEffects` only for the browser bundle.
Tooling, versions and a breaking change on the way
The repository is small and well equipped for it. There is a `src/` directory, `scripts/` for the build, `tsconfig.json` alongside `tsconfig.build.json`, `vitest.config.mjs`, `.oxlintrc.json` for linting, `prettier.config.js` and a `release.config.cjs` for semantic-release, plus a `.nvmrc` pinning the Node version.
The `package.json` script list is worth reading because the `check` script is the whole contribution gate in one line: lint, format check, typecheck, build, test, and a package test. Tests are split into unit and browser projects under Vitest, and there is a separate `test:package` using Node's built-in test runner against the built output. The README tells contributors to run `npm run check` before submitting.
The version field in `package.json` is `0.0.0-development`, which is how semantic-release keeps a placeholder in source. The releases on record are v1.0.4, v1.1.0 and v1.1.1, the last on 2020-04-14, and v1.1.0's single feature was iPad support on iOS 13.
The pending breaking change is announced in the README rather than hidden. The next major release removes `apple.universal` from detection results and TypeScript declarations, because the `iOS-universal … Mac` signature no longer makes `apple.device` or `any` true, and no real-world device example was verified for it, as issue 303 records. `apple.device` is the replacement for anyone wanting any supported mobile Apple device.
Editorial conclusion
isMobile is a good library for the narrow case it was built for, which is a redirect or a server-side rendering decision where you must branch on device class before the page renders. It is a poor choice for deciding layout, and the README says so before it describes a single function. Two practical notes. The build uses semantic-release with the version field pinned to `0.0.0-development` in `package.json`, so the tag is the source of truth and the newest published tag on record is v1.1.1 from 2020-04-14, while the repository was pushed on 2026-09-27. And the next major release removes `apple.universal`, so any code reading that property needs changing before it disappears.
Frequently asked questions
How do I detect a mobile device in Node.js?
Install the `ismobilejs` package, import the default export, and pass the user agent string. The function returns an object whose `any` property tells you whether a mobile device matched, with `phone` and `tablet` also available as aggregates.
Can isMobile detect an iPad in desktop mode?
In the browser, yes, using a heuristic that combines `navigator.platform === 'MacIntel'` with `navigator.maxTouchPoints > 1`. Server-side from the User-Agent header alone, no, because an iPad in desktop mode reports a Macintosh user agent.
What size is the isMobile library and where should it load?
About 1.3 kB minified. The README recommends it run in the `<head>` because it needs to decide before the page renders, while noting that blocking scripts in the head otherwise slows down asset loading.
What is the npm package name for this library?
`ismobilejs`. The GitHub repository is called isMobile, but the published package that you install in Node or pull from jsDelivr is named ismobilejs.
Is apple.universal still available?
Not after the next major release. It is being removed from detection results and TypeScript declarations because no verified real device produces the `iOS-universal … Mac` signature. Use `apple.device` for any mobile Apple device instead.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kaimallea-ismobile)