See who has actually seen your Mattermost message—at a glance. Tiny viewer avatars appear naturally beneath your post and update live as teammates read it. Hover over them for the full list, names, and viewing times.
No noisy checkmarks. No text being covered. Just a quiet, human answer to: “Has anyone seen this yet?”
- Alive: avatars appear in real time while the conversation is open.
- Compact: up to 10 tiny faces stay beside the message; a small
+shows when more viewers are available. - Useful on hover: see larger avatars, names, and the time each person first viewed the post.
- Out of the way: receipts sit after the message instead of covering its first characters.
- Works where you talk: channels, direct messages, grouped posts, and the right-hand thread sidebar are supported.
Nothing appears until another person views your message, and you are never counted as a viewer of your own post.
- Download the plugin archive from the
latest release.
Choose the asset named
com.github.core3750x.viewer-avatars-*.tar.gz—not GitHub's source-code archives. - Open System Console → Plugin Management in Mattermost.
- Upload the archive and enable Viewer Avatars.
- Hard-refresh any open Mattermost tabs.
That is it. Mattermost 9.1 or newer is required. By default, receipts expire after 90 days; an administrator can change the retention period under System Console → Plugins → Viewer Avatars.
Viewer Avatars is deliberately stricter than a simple “page was open” signal:
- a view counts only when at least 55% of the post is visible in the foreground browser tab;
- only channel members can record a view;
- only the post author can request that post's viewer list;
- live updates are delivered only to the author's Mattermost sessions;
- receipt data is deleted together with the post;
- receipt data expires automatically after the configured retention period;
- the normal message view loads at most 10 viewer IDs and profiles per post;
- larger viewer lists are loaded in pages only while their popover is open.
The plugin stores only the viewer's Mattermost user ID and first-view timestamp in Mattermost's own plugin KV store. It has no external service, analytics, or third-party tracking.
Development and architecture
- Go 1.23.9 or newer
- Node.js 20 or newer
- npm
go test ./...
npm --prefix webapp ci
npm --prefix webapp test
npm --prefix webapp run typecheck
npm --prefix webapp run build./scripts/build.shThe multi-platform archive is written to dist/.
The server exposes authenticated batch endpoints for recording views and loading viewer summaries and pages. Posts with up to 10 viewers occupy one KV entry. Larger receipts are promoted into 32 deterministic, sparse shards. Writes are coalesced briefly, deduplicated, and stored with atomic compare-and-set plus expiry, reducing hot-key contention in a high-availability Mattermost deployment.
The webapp observes rendered posts with IntersectionObserver, reads
Mattermost's Redux state for post and profile metadata, and mounts avatar
stacks through React portals. Its post caches are bounded, WebSocket events
contain only the new viewer, and the full popover list is paginated and
virtualized. Closing the popover releases the loaded pages and profiles.