All posts

A presence ring that remembers nothing

The circle around a profile photo in Nemi says what that person is doing right now. It is built so that it can only ever say right now: one word per account, overwritten in place, shown only to people you already work with. Play with the real ring below and see what each viewer is actually sent.

Privacy · · 9 min read

Every profile photo in Nemi sits inside a thin coloured ring. It used to be coloured by the plan that account paid for, which is the one fact about a person that never changes between one look and the next. We replaced it with something you can actually use: what that person is doing right now.

Presence is useful and it is also exactly the kind of feature that turns into surveillance without anybody deciding it should. A green dot becomes a “last seen” line, the line becomes a history, and the history becomes a report on who was at their desk. So the ring was built the other way round. We started from what it must never be able to say, and made those things impossible to store rather than merely hidden.

What does the ring around a profile photo show?

One of five things about what you are doing: that you have Nemi open, that you are working on a document, that you are moving files, that you are in a call, or that you were here a moment ago and your tab has gone to the background. On your own photo, and only there, it also shows how full your storage is. Each of those is an arc of the ring, and when two are true at once they share the circle with a soft crossfade between them.

This is the real thing. The ring below is drawn by the same component markup, the same painter and the same animation code as the one in the app. The only difference is that you are deciding what Anna is doing, instead of her browser.

The ring, as each viewer receives it

The ring says: In a meeting, Storage 62% full

One turn every 9 seconds

What Anna is doing

One choice, because one word is all that is stored.

62% full
Who is looking

Share of the circle each arc is given

  • In a meeting171°
  • Storage (only ever sent to Anna)189°
Change what Anna is doing and watch the new arc grow while the others make room. Then switch the viewer: the audience filter here is the same one the server runs before it answers anybody about anybody.

The ring turns, and how fast tells you something without a label. A call turns it once every 9 seconds; simply having Nemi open, once every 26. The liveliest signal sets the pace. If you have asked for less motion, on your device or in Nemi's own accessibility settings, it holds still and shows the same colours. And colour is never the only carrier: hover a ring and it says the same thing in words, and a screen reader reads that sentence out.

Who can see whether I am online?

Only the people you already work with in Nemi: somebody you are connected with, or a member of a workspace you are in. A connection is mutual, so it takes both of you to agree to it. Nobody else can ask for your ring, and an account id copied off a page gets nothing back. Presence is not a directory. The statistics on a link you send are built with the same instinct: record as little about people as the feature needs.

That check is done on our servers, for every ring, every time. A screen that shows avatars asks for up to 60 of them in one request, and this is what happens to that list before an answer goes back.

What happens to a request for six rings

YYoualways yoursBBenworkspace mateCChloeconnectionDDanshared a file onceEEveworkspace mate, sharing offFFemiworkspace mate

1/4A contact list asks about everybody on it

Your own ring, two workspace mates, a connection, and somebody you once shared a file with.

The switch is in Settings, under Style. Turning it off is silent: to everybody else you look like somebody who is not in Nemi at the moment, not like somebody who has hidden. A badge saying “presence hidden” would be a status of its own, and people would read it as one. Your own ring keeps working on your own screen either way. The help page on the ring walks through it.

Why is storage only on my own ring?

Because how close you are to your limit is nobody else's business, and the safe way to keep something private is to never send it. The tempting design is to compute one ring per person and dim the private parts when a colleague is looking. That puts the private part in every colleague's browser, one forgotten condition away from being drawn.

Nemi does the opposite. Every signal declares who it is for, and the ring a colleague receives is built from a list that never contained your storage in the first place. A bug in a component cannot leak a number the component was never given. That is what the playground shows when you switch the viewer: the storage arc does not fade, it is simply not there.

Does Nemi keep a history of when I was working?

No, and it could not hand one over if asked, because none is written. What is stored is one row per account holding one word and one timestamp: what your browser last said you were doing, and when. Every report overwrites that row. Nothing is appended, so there is nowhere a history could accumulate.

The same day, stored two ways

09:0012:0015:0018:00

A presence log

What we did not build: every report, appended and kept.

101

rows about Anna by 10:30, and growing every minute

  1. 10:30In a meeting
  2. 10:29In a meeting
  3. 10:28In a meeting
  4. 10:27In a meeting
  5. 10:26In a meeting
  6. and 96 more above

“What was Anna doing at 10:15?” It can answer: in a meeting.

What Nemi keeps

One row per account, overwritten in place.

1

row about Anna, at any time of day

word
meeting
at
10:30

Her ring now: In a meeting

“What was Anna doing at 10:15?” There is no answer. That word was overwritten at 10:16.

An invented working day. The left column is the log we chose not to build; the right is the one row Nemi keeps. The timings (one report a minute, away after a few minutes, quiet after twenty) are the product's own constants.

The row holds no object either. It can say “in a meeting” and it cannot say which meeting, because the column has nowhere to put one. The same goes for which document, which file, which workspace and which page. A contact list is entitled to “working on a document”; it is not entitled to the name of the document, and the cheapest way to keep that promise is to have no field for it.

The honest way not to build a log of who worked when is to have nowhere to put it.

A policy that says “we do not look at the log” can change in an afternoon. A table with one row per person cannot become a history without somebody building a different table, and the privacy policy states the shape in section 3.20 so that change would be visible. The one word is stored as it is, not encrypted the way what you write is, because it is a status rather than something you wrote.

When does the ring go quiet?

Your browser reports what you are doing only while a Nemi tab is open and in front of you. It reports when that changes, and otherwise once a minute. A tab in the background does not send the regular report, which is what makes “away” mean something without a timer of ours having to decide whether you are at your desk. The server then reads the age of that one row.

60 s

between reports while the tab is in front of you

2.5 min

a report keeps you shown as here: two reports plus slack

20 min

after which away becomes a quiet ring

The gap between those numbers is deliberate. A ring that blinks off whenever one report is late teaches people to distrust it, so a report keeps you present for two and a half minutes, long enough to survive one that went missing. After that the ring says away. After twenty minutes it stops saying anything, because a person who closed their laptop at six has not told anybody that they are “away”; they have simply gone home.

What are the downsides of presence without a history?

Being unable to remember has real downsides, and we chose them. There is no “last seen three hours ago”. You cannot look back and see when a colleague was around yesterday, and neither can an administrator. A ring can be up to a couple of minutes behind the truth, because it is fed by a report a minute rather than a live connection per person. And a guest who opens a share link has no account, so they have no ring and nothing about them is recorded here at all.

So the ring answers one question, now, for the right people, and then forgets. If you are in a Meet call it says so to your team, and when the call ends there is no record that it ever did. How the call itself travels is a story of its own.

Questions people ask

Can people see when I was last online in Nemi?

No. Nemi has no last seen line, because it keeps no history to draw one from. It stores one word and one time per account, what your browser last said you were doing, and every new report overwrites it.

Who can see my online status in Nemi?

Only people you already work with: somebody you are connected with, which takes both of you to agree, or a member of a workspace you are in. Our server checks that for every ring it sends, so an account id copied off a page gets nothing back.

How do I hide my online status in Nemi?

Open Settings, then Style, and switch off Show your ring to people you work with. To everybody else you then look like somebody who is not in Nemi at the moment, not like somebody who has hidden. Your own ring keeps working on your own screen.

Is showing an online status a privacy risk?

It becomes one when the status is stored as a history, because a history of when somebody was online is a record of their working day. A live status that only colleagues can see, that is never logged and that can be switched off tells far less. Those are the three things worth checking in any app that shows one.

Can my manager see when I was working yesterday?

Not in Nemi. There is no record of what anybody was doing yesterday, for you, for a colleague or for an administrator. The ring only says what is true right now, and it goes quiet by itself when you close Nemi.

Does my status show which document or meeting I am in?

No. The ring can say that you are in a meeting or working on a document, but never which one, and never which workspace or page. Nemi stores no field that could hold that, so it cannot be shown or leaked.

How long before Nemi shows me as away?

While a Nemi tab is in front of you, your browser reports once a minute. If no report arrives for two and a half minutes, your ring says away, and after twenty minutes it goes quiet altogether.

Where the numbers come from

  • The signals, their audiences, the painter and the timings: lib/dynamic-ring/model.ts (RING_SIGNALS, signalsForAudience, ringPaint, RING_PING_INTERVAL_MS, RING_ACTIVE_MS, RING_AWAY_MS, RING_BATCH_LIMIT)
  • Who may see whose ring, and the one overwritten row: lib/dynamic-ring/server.ts (ringStatusesFor, reportPresence)
  • Reporting only while the tab is visible: components/dynamic-ring/RingReporter.tsx
  • The ring's drawing and motion: components/dynamic-ring/DynamicRing.tsx, components/dynamic-ring/useRingAnimation.ts
  • What is stored, who sees it, how to switch it off: /privacy, section 3.20

Read next

Use the thing we write about.

Files, docs, sheets, photos, calendar and meetings in one account.