meteor-user-status: online and idle state for Meteor users
Track user connection state and inactivity in Meteor.
At a glance
- What is it?
- meteor-user-status is a Meteor package that keeps track of connection data for your users, IP addresses, user agents and client-side activity, and writes it into Meteor.users so that you can render an online users box with online in green and idle in orange. It also exposes a per-session collection on the server and a client monitor that detects inactivity, and version 2 splits the package into a Meteor 3 line and a Meteor 2 line.
- Who is it for?
- meteor-user-status suits a Meteor application that needs to show who is currently connected, or who has gone quiet, without writing a presence layer by hand, and it suits applications that already publish Meteor.users reactively.
- 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 157 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Connection state written into Meteor.users
meteor-user-status keeps track of user connection data, such as IP addresses, user agents and client-side activity, and tracks this information in Meteor.users as well as some other objects.
The point of it is the online users box that most chat-style applications end up needing: seeing which users are online and which are idle, rendered with online in green and idle in orange. The README shows that picture, and the stated purpose is to let you easily see users that are online.
There is a demo application at user-status.meteor.com with its source in the demo directory of the repository, and the README points at it as a complete example of what can be tracked, including inactivity, IP addresses and user agents. That demo is more useful than the documentation for understanding how the pieces fit together, because it shows the client monitor, the publication and the template together rather than in isolation.
The package is MIT licensed and lives under the Meteor-Community-Packages organisation, which is where the maintained community packages live after the main Meteor package collection moved on. The repository topics are hacktoberfest and meteor, and the last push was on 2026-05-19. The release history shows v1.0.1 in June 2021, v1.1.0 in February 2024 and v2.0.0 on 2026-05-19, which is the same day as the last push.
So the audience is a Meteor developer who needs presence, and the package's value is that it is the maintained community answer to that question rather than something you write yourself in every application.
Install, and the branch that matches your Meteor version
The install is the usual Meteor package add:
$ meteor add mizzao:user-statusThe compatibility note is the part to read before you install, because the package name does not change between the two lines.
The 2.0.0 release candidates target Meteor 3.0 and newer, and use the stable mizzao:[email protected] package. Meteor 2.x applications should stay on the 1.x line of this package until the application is ready to migrate to Meteor 3.
That is the whole of the compatibility story, and it is a common situation in the Meteor ecosystem: the framework moved to a new release, the package followed, and applications that cannot move yet stay on the older line. The consequence for you is that meteor add installs the version for your Meteor version, but you need to know which one you got before you read the rest of the documentation.
There is also a deployment detail that will bite you if you skip it. To read client IP addresses properly, you must set the HTTP_FORWARDED_COUNT environment variable for your app, and make sure that IP address headers are forwarded for any reverse proxy installed in front of the app. The README links the Meteor documentation on this.
The reason is straightforward: the address the server sees is the address of the last hop, so behind a proxy it is the proxy's address unless the chain is declared and the headers are passed along. The package reads what the server has, so if the server has the wrong address, the package records the wrong address.
The status fields, and what lastActivity really means
The package maintains two kinds of status: a general user online flag in Meteor.users, and some additional data for each session. It uses timesync to maintain the server's time across all clients, regardless of whether they have the correct time.
That last point is worth pausing on, because it is what makes idle detection meaningful. If the client clock is wrong, comparing a client-side timestamp with a server-side timestamp produces nonsense, so the package keeps the server's time authoritative on both sides.
Meteor.users receives a status field, updated automatically if the user logs in or logs out, closes their browser or otherwise disconnects. A user is online if at least one connection with that userId is logged in. The fields are:
- online, true if there is at least one connection online for this user - lastLogin, information about the most recent login of the user, with the fields date, ipAddr and userAgent - idle, true if all connections for this user are idle, which requires idle tracking to be turned on for all connections - lastActivity, if the user was idle, the last time an action was observed
The lastActivity field carries a caveat that the README spells out: it is only available when the user is online and idle, and it does not maintain the user's last activity in real time or a stored value indefinitely, with lastLogin described as a coarse approximation to that. The README links issue 80 for more on this.
So the semantics are per session and per moment rather than per user and per day. lastActivity is the time of the last observed action for a user who is currently idle, and it is not a historical record of when the user last did anything. If you want that, you need to store it yourself.
The idle flag is also stricter than it looks. It is true only when all of a user's connections are idle, and only when idle tracking is on for all of them, so a user with one connection that has never reported is not marked idle.
Publishing and observing the status from the client
The status data lives on the server, so the client needs a publication to see it, and the README shows the shape:
Meteor.publish("userStatus", function() {
return Meteor.users.find({ "status.online": true }, { fields: { ... } });
});Two details are visible in that snippet and both matter for a real application. The query filters on the nested status.online field, so only online users are published, and the fields projection limits what is sent, which matters when you have thousands of users and only need the name and the flag.
The alternative to publishing is to observe the collection directly, and the README gives that form too, with an added and a removed handler for a user coming online and going offline. That is the pattern you want for actions that follow presence, such as notifying somebody when a colleague signs in.
For templates, a reactive cursor in a helper is the simplest form, and the README shows a userPill template with a labelClass helper that returns label-warning when the user is idle, label-success when online, and label-default otherwise, using bootstrap classes. The idle check comes first deliberately, because a user can be both online and idle, and the pill should show the idle state in that case.
Making this directly available on the client allows for useful renderings of user state, and the reactive cursor handles the updating: when a user goes offline the publication stops matching them and the document is removed from the client, and when they come back it is added again.
The client monitor that decides a user is idle
The client side of the package is a UserStatus object that monitors a client's idle state automatically, and by default it listens for all clicks and keypresses in window as signals of a user's action.
The functions are a small API with clear responsibilities. startMonitor takes an object with three fields: threshold, the amount of time before a user is counted as idle, interval, how often to check if a client has gone idle, and idleOnBlur, whether to count a window blur as a user going idle. stopMonitor stops the running monitor. pingMonitor lets you signal manually that the user is doing something and reset the idle monitor, and it is there for the cases where the automatic event handlers are not catching what you need, such as an application where the meaningful action is a drag or a scroll rather than a click. isIdle is a reactive variable saying whether the user is currently idle, and isMonitoring is a reactive variable for whether the monitor is running.
The last one, lastActivity, is a reactive variable for the last action recorded by the user, according to server time. The README is explicit about its cost: since this variable will be invalidated a lot and cause many recomputations, it is best used only for debugging or diagnostics, as in the demo.
That is a real design constraint rather than a footnote. A reactive variable that changes on every keystroke invalidates every computation that depends on it, and if a template depends on it, the whole component re-renders on each keypress. Keeping it for diagnostics avoids that cost for the application that does not need it.
The idleOnBlur option deserves attention for applications that are used in a tabbed interface. A user who switches to another tab to check something will be counted as idle, and in a messaging application that can be read as something other than idle.
The per-connection collection and the startup selector
On the server, the UserStatus.connections collection is in memory and holds information for all connections on the server.
Its fields are _id for the connection id, userId if the connection is authenticated, ipAddr for the remote address of the connection, userAgent, loginTime for when the user logged in with this connection if authenticated, and idle, true if idle monitoring is enabled on this connection and the client has gone idle.
The ipAddr field carries an important consequence that the README states: a user logged in from different places will have one document per connection. So the collection is per session, not per user, and it is the natural place to answer questions about where somebody is currently connected from, which the per-user status document cannot answer.
Then there is the startup behaviour, which is an operational detail that matters at scale. On startup meteor-user-status automatically resets online users to offline using the default selector { "status.online": true }, then marks users online again as connections are reestablished.
That default writes to every user document that was marked online, which on a large user base is a lot of writes on every server start. The startupQuerySelector Meteor package option lets you change it, and the README shows the wider selector that also matches status.idle and status.lastActivity, with the stated benefit that it reduces server and database load during startup if you have a large number of users.
The last note in the README is about integration with another package. If your project uses aldeed:collection2 with a schema attached to Meteor.users, you need to add the status items to the schema to allow modifications of the status, otherwise the package's writes are rejected by the schema.
Where this package is the wrong tool
The limitations of this approach come from the fact that it tracks live connections.
Presence here means a DDP connection is open and logged in. When a user's laptop sleeps or the network drops, the connection eventually closes and the user goes offline, even though the person is still working. If your application needs a durable notion of who is around, such as a team roster that should show someone as present because they said so, this package does not provide it and you would store that separately.
The idle detection is a heuristic too. It watches clicks and keypresses in the window, and the window blur behaviour is configurable. A user reading a long document without touching the keyboard is counted as idle, and there is no way for the server to distinguish that from someone who walked away.
There is also the Meteor version split to plan around. The 2.0 line targets Meteor 3 and newer, so an application that intends to stay on Meteor 2 stays on the 1.x line, and the two lines have different documentation, since the README's compatibility section is written to tell you which you are reading.
The alternative is to write the presence layer yourself, using Meteor.onConnection on the server to record connections in a collection of your own and publishing what you need. The difference in approach is that you own the schema, the storage and the semantics, and you can record what you consider meaningful, such as a last seen timestamp that survives disconnection. What you give up is the timesync agreement between client and server, the idle monitoring on the client and the per-connection collection that this package gives you already, which is why most projects reach for the package first and add a small amount of their own only where the gap shows.
Editorial conclusion
meteor-user-status suits a Meteor application that needs to show who is currently connected, or who has gone quiet, without writing a presence layer by hand, and it suits applications that already publish Meteor.users reactively. It does not suit an application whose notion of presence must survive a disconnected client, since the package tracks live DDP connections rather than a durable presence record, and it does not suit a Meteor 2 application that intends to stay there, because the 2.0 line targets Meteor 3 and newer. Check three things before you adopt it: that you set HTTP_FORWARDED_COUNT and forward the IP headers when a reverse proxy sits in front of your app, or the addresses you record will be the proxy's, which branch you install according to your Meteor version, and whether the idle tracking thresholds suit your users, since the default listener watches all clicks and keypresses in the window. The last push to the repository was on 2026-05-19 and the current release is v2.0.0.
Frequently asked questions
What does meteor-user-status track?
It keeps track of user connection data, such as IP addresses, user agents and client-side activity, in Meteor.users and in a per-connection collection on the server. Meteor.users receives a status field with online, lastLogin, idle and lastActivity.
How do I install meteor-user-status?
With meteor add mizzao:user-status. The 2.0.0 line targets Meteor 3.0 and newer and uses the stable mizzao:[email protected] package, while Meteor 2.x applications should stay on the 1.x line until they are ready to migrate.
Why do I need HTTP_FORWARDED_COUNT to read client IP addresses?
To read client IP addresses properly you must set the HTTP_FORWARDED_COUNT environment variable for your app and make sure that IP address headers are forwarded for any reverse proxy installed in front of it, because otherwise the server only sees the address of the proxy.
How does idle tracking work in meteor-user-status?
On the client the UserStatus object monitors the idle state, by default listening for all clicks and keypresses in window. startMonitor takes a threshold, the amount of time before a user is counted as idle, an interval for how often to check, and idleOnBlur for whether a window blur counts as idle, and pingMonitor lets you signal activity manually.
What is the startupQuerySelector option for?
On startup the package resets online users to offline using the default selector { "status.online": true } and then marks them online again as connections reestablish. The startupQuerySelector package option lets you widen that selector, which the README notes reduces server and database load during startup if you have a large number of users.
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/meteor-community-packages-meteor-user-status)Was this useful?