Matrix Intentional Mentions explained

Published on Friday, December 15, 2023
Tags: matrix, notes

Previously I have written about how push rules generate notifications and how read receipts mark notificiations as read in the Matrix protocol. This article is about a change that I instigated to improve when a “mention” (or “ping”) notification is created. (This is a “highlight” notification in the Matrix specification.)

This was part of the work I did at Element to reduce unintentional pings. I preferred thinking of it in the positive — that we should only generate a mention on purpose, hence “intentional” mentions. MSC3952 details the technical protocol changes, but this serves as a bit of a higher-level overview (some of this content is copied from the MSC).

Note

This blog post assumes that default push rules are enabled, these can be heavily modified, disabled, etc. but that is ignored in this post.

Legacy mentions

The legacy mention system searches for the current user’s display name or the localpart of the Matrix ID [1] in the text content of an event. For example, an event like the following would generate a mention for me:

{
  // Additional fields ignored.
  "content": {
    "body": "Hello @clokep:matrix.org!"
  }
}

A body content field [2] containing clokep or Patrick Cloke would cause a “highlight” notification (displayed as red in Element). This isn’t uncommon in chat protocols and is how IRC and XMPP.

Some of the issues with this are:

There were some prior attempts to fix this, but I would summarize them as attempting to reduce edge-cases instead of attempting to rethink how mentions are done.

Intentional mentions

I chose to call this “intentional” mentions since the protocol now requires explicitly referring to the Matrix IDs to mention in a dedicated field, instead of implicit references in the text content.

The overall change is simple: include a list of mentioned users in a new content field, e.g.:

{
  // Additional fields ignored.
  "content": {
    "body": "Hello @clokep:matrix.org!"
    "m.mentions": {
      "user_ids": ["@clokep:matrix.org"]
    }
  }
}

Only the m.mentions field is used to generate mentions, the body field is no longer involved. Not only does this remove a whole class of potential bugs, but also allows for “hidden” mentions and paves the way for mentions in extensible events (see MSC4053).

That’s the gist of the change, although the MSC goes deeper into backwards compatibility, and interacting with replies or edits.

Comparison to other protocols

The m.mentions field is similar to how Twitter, Mastodon, Discord, and Microsoft Teams handle mentioning users. The main downside of this approach is that it is not obvious where in the text the user’s mention is (and allows for hidden mentions).

The other seriously considered approach was searching for “pills” in the HTML content of the event. This is similar to how Slack handles mentions, where the user ID is encoded with some markup [3]. This has a major downside of requiring HTML parsing on a hotpath of processing notifications (and it is unclear how this would work for non-HTML clients).

Can I use this?

You can! The MSC was approved and included in Matrix 1.7, Synapase has had support since v1.86.0; it is pretty much up to clients to implement it!

Element Web has handled (and sent intentional mentions) since v1.11.37, although I’m not aware of other clients which do (Element X might now). Hopefully it will become used throughout the ecosystem since many of the above issues are still common complaints I see with Matrix.

[1]This post ignores room-mentions, but they’re handled very similarly.
[2]Note that the plaintext content of the event is searched not the “formatted” content (which is usually HTML).
[3]This solution should also reduce the number of unintentional mentions, but doesn’t allow for hidden mentions.