# RobotJS: Node.js Desktop Automation for Mouse, Keyboard and Screen

> RobotJS is a native Node.js addon that drives the mouse and keyboard and reads pixels from the screen. It installs as a prebuilt binary on most platforms, but the API is still pre-1.0 and macOS needs explicit user approval.

**octalmage/robotjs** — Node.js Desktop Automation. 

- Repository: https://github.com/octalmage/robotjs
- Website: http://robotjs.dev
- Stars: 12,777 · Forks: 1,002
- Language: C
- License: MIT
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/octalmage-robotjs

## What RobotJS solves, and who ends up using it

RobotJS exists for the case where the thing you need to automate has no API. A legacy internal tool, a Java desktop client, a game launcher, an installer that only ships as a GUI: none of these expose an interface a script can call. RobotJS instead moves the operating system's cursor, sends key events, and reads back the colour of individual pixels. From Node.js, that means a test or migration script can click through a wizard the same way a person would.

The audience is narrow but real. The README's own Story section says the author is a long-time AutoHotkey user and wanted that style of automation inside Node.js, and the package keywords list automation, GUI, mouse, keyboard, screenshot, pixel and autohotkey. So the target reader is a JavaScript developer who already writes Node tooling and wants AutoHotkey-like reach without leaving the ecosystem. The README also links a wiki page of projects built on RobotJS, which is the project's own pointer to what people actually do with it.

It is not a test framework, not a browser driver, and not a UI element inspector. It has no notion of a button or a window. Everything is coordinates and pixels, which is both the source of its generality and the reason scripts are brittle.

## How RobotJS works: a native addon with a coordinate-based model

RobotJS is a C addon loaded into the Node process, not a separate daemon and not a remote protocol. The repository layout shows this plainly: a binding.gyp at the top level, a src/ directory of C sources, an index.js entry point, and an index.d.ts typings file. package.json sets main to index.js and typings to index.d.ts, and declares gypfile true. The two runtime dependencies are node-addon-api and node-gyp-build.

That last dependency explains the install model. Published packages ship Node-API prebuilds for Linux, macOS and Windows on x64 and arm64, and node-gyp-build resolves the right binary at install time. The prebuilds directory is listed in the package files array, so the binaries travel with the npm tarball. Targets outside that matrix fall back to compiling from source, which is where the toolchain requirements in the Building section apply.

The API divides into four areas, and the README's Progress table lists all four at 100%: Mouse, Keyboard, Screen and Bitmap. Mouse and keyboard are output. Screen capture and pixel reading are input. The image search layer sits on top: robot.screen.capture() returns a capture object, and that object exposes findImage, findImages, countImage, findColor, findColors, countColor, colorAt, save and click. Image searches return the target's top-left coordinates in capture space, and click converts those to screen coordinates and clicks the target's centre. That coordinate translation is a detail worth knowing before you write your own offset maths.

Multi-monitor handling is explicit rather than automatic. robot.getDisplays() lists displays, and you pass a rectangle from one display into robot.screen.capture(x, y, width, height). The FAQ states that a capture rectangle cannot span multiple displays, and that on Linux the reported data is the current X11 screen. So a two-monitor layout is two capture spaces you have to reconcile yourself.

## Installing RobotJS and running a first script

The README's installation path is a single npm command, and on x64 or arm64 Linux, macOS and Windows the prebuild should mean no compiler runs at all.

```bash
npm install robotjs
```

If your platform or Node version is outside the prebuild matrix, the install compiles from source and you need the toolchain the Building section lists. On Linux that includes Python 3, make, a C/C++ compiler and libxtst-dev. The README gives the apt command for the last one.

```bash
sudo apt-get install libxtst-dev
```

For a manual source build, the README points at node-gyp: install it globally, then rebuild.

```bash
npm install -g node-gyp
node-gyp rebuild
```

With the module installed, the smallest useful script is the keyboard example from the README: type a string, then tap a named key.

```js
const robot = require("robotjs");

robot.typeString("Hello World");
robot.keyTap("enter");
```

Run that with node and, assuming the target window has focus, the text appears and the return key is pressed. Nothing is returned to your process, so there is no confirmation to assert on. Focus is your responsibility: RobotJS sends input to whatever is in front, and the README offers no window-targeting call to change that.

The screen side is where you get data back. The README's pixel example reads the cursor position, then the colour under it.

```js
const robot = require("robotjs");

const mouse = robot.getMousePos();
const hex = robot.getPixelColor(mouse.x, mouse.y);
console.log(`#${hex} at x:${mouse.x} y:${mouse.y}`);
```

The console line prints a hex colour and the coordinates it was sampled at. If you plan to match images rather than single pixels, the README's Image Search example captures the screen, loads a BMP, and calls findImage with a tolerance option.

```js
const screen = robot.screen.capture();
const target = robot.image.load("./target.bmp");
const match = screen.findImage(target, { tolerance: 0.1 });
```

A match is truthy and carries the top-left capture coordinates; a miss is falsy. Note the tolerance value: exact pixel equality across renderers and scaling settings is unrealistic, so tune it against your own target rather than copying 0.1 blindly.

## macOS permissions, PNG support and the limits you hit in practice

The sharpest limitation is macOS. The README documents four functions: getAccessibilityPermission() and getScreenCapturePermission() report current grants, while requestAccessibilityPermission() and requestScreenCapturePermission() trigger the system prompts. The README is explicit that macOS still requires the user to approve each request, and that the accessibility prompt is asynchronous, so requestAccessibilityPermission() returns the current grant rather than the eventual one. You must poll getAccessibilityPermission() after the user responds. Any unattended macOS deployment therefore needs a human at the machine once, per application, and the README does not describe a way around that.

PNG is a second conditional. BMP loading and saving is always available. PNG is enabled in all published prebuilds, but for macOS and Linux source builds it is optional: you install libpng and pkg-config and force a source build with ROBOTJS_ENABLE_PNG=1. The README tells you to check robot.image.supportsPNG at runtime, which is the honest way to handle it, and also a sign that the capability is not uniform across installs.

Global hotkeys are the third. The FAQ says RobotJS does not support them, that the maintainer does not know whether it ever will, and that the suggested workaround is to handle hotkeys in Electron or NW.js instead. If your design starts with "when the user presses this key combination anywhere", RobotJS is the wrong layer.

There is also the API stability warning, stated at the top of the README: the exported functions could change at any time before 1.0.0. The current version in package.json is 0.9.1. Treat the surface as moving. And because everything is coordinate-based, a theme change, a font change or a DPI scaling difference can break a script that was passing yesterday, with no error other than a failed image match.

## RobotJS compared with AutoHotkey

The README's Story section names AutoHotkey directly as the inspiration, and the comparison is instructive because the two tools split the same problem differently. AutoHotkey is its own scripting language and runtime with first-class hotkey handling; the README's Story even points at AutoHotkey's imagesearch as an example of something hard to replicate elsewhere. RobotJS goes the other way: it is a library inside an existing Node process, so your automation shares a language, a package manager and a process with the rest of your tooling.

That difference decides most adoption questions. If you need global hotkeys, AutoHotkey has them and the RobotJS FAQ says RobotJS does not. If your automation needs to call an HTTP API, parse JSON and write to a database in the same script, RobotJS inherits that from Node and AutoHotkey does not. If you want to ship a single self-contained script to a non-developer, a Node project with a native addon is heavier than an AutoHotkey script.

The search data around RobotJS also surfaces NutJS as a phrase people use. The README does not describe NutJS, so I will not characterise it beyond noting that it appears in the same searches. What can be said from the README is that RobotJS's own differentiator is the image and pixel layer: capture objects with findImage, findImages, countImage, findColor, findColors, countColor, colorAt and save, all returning capture-space coordinates that click() translates for you.

## Maintenance, versioning and what the MIT licence means here

The repository is not archived, and the last push was on 2026-08-07. The release history shows v0.8.0 on 2026-07-24, v0.9.0 on 2026-08-06 and v0.9.1 on 2026-08-07, so the most recent release followed the most recent push by a short interval. The package version in package.json matches v0.9.1. That is the maintenance picture the repository supports; anything beyond it, such as how responsive issues are, is not something this review can judge.

The upgrade cost has two parts. First, the pre-1.0 warning means minor version bumps can rename or reshape exported functions, so pinning and reading the CHANGELOG.md between upgrades is the practical approach. Second, prebuild coverage is the thing that decides whether an upgrade is a download or a compile: a Node version outside the published matrix turns npm install into a source build with the full toolchain requirement. The package's prepack script runs scripts/verify-prebuilds.js, which suggests the project checks its own prebuild set before publishing, but the README does not describe what that script validates.

On licensing, package.json declares MIT, and the published files include a LICENSE.md at the top level and a LICENSES/ directory. The LICENSES/ directory matters for anyone auditing dependencies, because the README notes that macOS and Linux prebuilds include statically linked libpng. If your organisation reviews bundled third-party licences, that directory is where to look. This is a description of what the repository contains, not legal advice; your own counsel decides whether the terms fit your distribution.

## Conclusion

Adopt RobotJS if you need pixel-level screen reading and synthetic input from JavaScript on Linux, macOS or Windows, and you can live with a pre-1.0 API that the README says may change before 1.0.0. Do not adopt it if you need global hotkeys, since the README states these are not supported, or if you need a capture rectangle spanning two displays, which the FAQ rules out. Before committing, verify that a prebuild exists for your Node version and architecture, check robot.image.supportsPNG at runtime if you depend on PNG, and confirm the macOS accessibility and screen capture grants on the machine that will run the automation.

## FAQ

### How do I install RobotJS?

Install it with npm install robotjs. Published packages include Node-API prebuilds for Linux, macOS and Windows on x64 and arm64, and other targets fall back to a source build that needs the toolchain listed in the README's Building section.

### What is RobotJS?

It is a Node.js desktop automation library, described in its package metadata as Node.js Desktop Automation, that controls the mouse and keyboard and reads the screen. The README's Progress table lists Mouse, Keyboard, Screen and Bitmap modules as complete.

### What are the alternatives to RobotJS?

The README's Story section names AutoHotkey as the original inspiration, and the difference is that AutoHotkey is a standalone scripting runtime with hotkey support while RobotJS is a library inside a Node process. Searches also mention NutJS, but the README does not describe it.

### Can I use JavaScript for automation with RobotJS?

Yes. RobotJS is installed as an npm package and required into a Node script, so the automation runs in JavaScript. The README's examples use require("robotjs") and call functions such as typeString, keyTap, getMousePos and getPixelColor.

### Is there a Node.js alternative to RobotJS?

The README's Story section points to AutoHotkey as the original inspiration, but that is a separate scripting runtime rather than a Node package. The README does not name a Node.js alternative to RobotJS.

## Sources

- [License: MIT](https://github.com/octalmage/robotjs/blob/master/LICENSE)
- [octalmage/robotjs on GitHub](https://github.com/octalmage/robotjs)
- [Project website](http://robotjs.dev)
- [README](https://github.com/octalmage/robotjs/blob/master/README.md)
- [Releases](https://github.com/octalmage/robotjs/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/octalmage-robotjs
