Instant Messaging

This module adds support for sending human-readable messages to a room. It also adds support for associating human-readable information with the room itself such as a room name and topic.

Events

m.room.message


This event is used when sending messages in a room. Messages are not limited to be text. The msgtype key outlines the type of message, e.g. text, audio, image, video, etc. The body key is text and MUST be used with every kind of msgtype as a fallback mechanism for when a client cannot render a message. This allows clients to display something even if it is just plain text.

Event type: Message event

Content

Name Type Description
body string Required: The textual representation of this message.
msgtype string Required: The type of message, e.g. m.image, m.text

Examples

{
  "content": {
    "body": "Bee Gees - Stayin' Alive",
    "info": {
      "duration": 2140786,
      "mimetype": "audio/mpeg",
      "size": 1563685
    },
    "msgtype": "m.audio",
    "url": "mxc://example.org/ffed755USFFxlgbQYZGtryd"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "body": "thinks this is an example emote",
    "format": "org.matrix.custom.html",
    "formatted_body": "thinks \u003cb\u003ethis\u003c/b\u003e is an example emote",
    "msgtype": "m.emote"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "body": "something-important.doc",
    "filename": "something-important.doc",
    "info": {
      "mimetype": "application/msword",
      "size": 46144
    },
    "msgtype": "m.file",
    "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "body": "filename.jpg",
    "info": {
      "h": 398,
      "mimetype": "image/jpeg",
      "size": 31037,
      "w": 394
    },
    "msgtype": "m.image",
    "url": "mxc://example.org/JWEIFJgwEIhweiWJE"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "body": "Big Ben, London, UK",
    "geo_uri": "geo:51.5008,0.1247",
    "info": {
      "thumbnail_info": {
        "h": 300,
        "mimetype": "image/jpeg",
        "size": 46144,
        "w": 300
      },
      "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
    },
    "msgtype": "m.location"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "body": "This is an example notice",
    "format": "org.matrix.custom.html",
    "formatted_body": "This is an \u003cstrong\u003eexample\u003c/strong\u003e notice",
    "msgtype": "m.notice"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "admin_contact": "mailto:server.admin@example.org",
    "body": "Human-readable message to explain the notice",
    "limit_type": "monthly_active_user",
    "msgtype": "m.server_notice",
    "server_notice_type": "m.server_notice.usage_limit_reached"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "body": "This is an example text message",
    "format": "org.matrix.custom.html",
    "formatted_body": "\u003cb\u003eThis is an example text message\u003c/b\u003e",
    "msgtype": "m.text"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "body": "Gangnam Style",
    "info": {
      "duration": 2140786,
      "h": 320,
      "mimetype": "video/mp4",
      "size": 1563685,
      "thumbnail_info": {
        "h": 300,
        "mimetype": "image/jpeg",
        "size": 46144,
        "w": 300
      },
      "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
      "w": 480
    },
    "msgtype": "m.video",
    "url": "mxc://example.org/a526eYUSFFxlgbQYZmo442"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

m.room.message.feedback


NB: Usage of this event is discouraged in favour of the receipts module. Most clients will not recognise this event. Feedback events are events sent to acknowledge a message in some way. There are two supported acknowledgements: delivered (sent when the event has been received) and read (sent when the event has been observed by the end-user). The target_event_id should reference the m.room.message event being acknowledged.

Event type: Message event

Content

Name Type Description
target_event_id string Required: The event that this feedback is related to.
type enum Required: The type of feedback.

One of: [delivered read].

Examples

{
  "content": {
    "target_event_id": "$WEIGFHFW:localhost",
    "type": "delivered"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message.feedback",
  "unsigned": {
    "age": 1234
  }
}

Usage of this event is discouraged for several reasons:

m.room.name


A room has an opaque room ID which is not human-friendly to read. A room alias is human-friendly, but not all rooms have room aliases. The room name is a human-friendly string designed to be displayed to the end-user. The room name is not unique, as multiple rooms can have the same room name set.

A room with an m.room.name event with an absent, null, or empty name field should be treated the same as a room with no m.room.name event.

An event of this type is automatically created when creating a room using /createRoom with the name key.

Event type: State event
State key A zero-length string.

Content

Name Type Description
name string Required: The name of the room. This MUST NOT exceed 255 bytes.

Examples

{
  "content": {
    "name": "The room name"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.name",
  "unsigned": {
    "age": 1234
  }
}

m.room.topic


A topic is a short message detailing what is currently being discussed in the room. It can also be used as a way to display extra information about the room, which may not be suitable for the room name. The room topic can also be set when creating a room using /createRoom with the topic key.

Event type: State event
State key A zero-length string.

Content

Name Type Description
topic string Required: The topic text.

Examples

{
  "content": {
    "topic": "A room topic"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.topic",
  "unsigned": {
    "age": 1234
  }
}

m.room.avatar


A picture that is associated with the room. This can be displayed alongside the room information.

Event type: State event
State key A zero-length string.

Content

Name Type Description
info ImageInfo Metadata about the image referred to in url.
url string Required: The URL to the image.
ImageInfo
Name Type Description
h integer The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.
mimetype string The mimetype of the image, e.g. image/jpeg.
size integer Size of the image in bytes.
thumbnail_file EncryptedFile Information on the encrypted thumbnail file, as specified in End-to-End Encryption. Only present if the thumbnail is encrypted.
thumbnail_info ThumbnailInfo Metadata about the image referred to in thumbnail_url.
thumbnail_url string The URL (typically MXC URI) to a thumbnail of the image. Only present if the thumbnail is unencrypted.
w integer The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.
ThumbnailInfo
Name Type Description
h integer The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.
mimetype string The mimetype of the image, e.g. image/jpeg.
size integer Size of the image in bytes.
w integer The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "info": {
      "h": 398,
      "mimetype": "image/jpeg",
      "size": 31037,
      "w": 394
    },
    "url": "mxc://example.org/JWEIFJgwEIhweiWJE"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.avatar",
  "unsigned": {
    "age": 1234
  }
}

m.room.pinned_events


This event is used to “pin” particular events in a room for other participants to review later. The order of the pinned events is guaranteed and based upon the order supplied in the event. Clients should be aware that the current user may not be able to see some of the events pinned due to visibility settings in the room. Clients are responsible for determining if a particular event in the pinned list is displayable, and have the option to not display it if it cannot be pinned in the client.

Event type: State event
State key A zero-length string.

Content

Name Type Description
pinned [string] Required: An ordered list of event IDs to pin.

Examples

{
  "content": {
    "pinned": [
      "$someevent:example.org"
    ]
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.pinned_events",
  "unsigned": {
    "age": 1234
  }
}
m.room.message msgtypes

Each m.room.message MUST have a msgtype key which identifies the type of message being sent. Each type has their own required and optional keys, as outlined below. If a client cannot display the given msgtype then it SHOULD display the fallback plain text body key instead.

Some message types support HTML in the event content that clients should prefer to display if available. Currently m.text, m.emote, and m.notice support an additional format parameter of org.matrix.custom.html. When this field is present, a formatted_body with the HTML must be provided. The plain text version of the HTML should be provided in the body.

Clients should limit the HTML they render to avoid Cross-Site Scripting, HTML injection, and similar attacks. The strongly suggested set of HTML tags to permit, denying the use and rendering of anything else, is: font, del, h1, h2, h3, h4, h5, h6, blockquote, p, a, ul, ol, sup, sub, li, b, i, u, strong, em, strike, code, hr, br, div, table, thead, tbody, tr, th, td, caption, pre, span, img.

Not all attributes on those tags should be permitted as they may be avenues for other disruption attempts, such as adding onclick handlers or excessively large text. Clients should only permit the attributes listed for the tags below. Where data-mx-bg-color and data-mx-color are listed, clients should translate the value (a 6-character hex color code) to the appropriate CSS/attributes for the tag.

font
data-mx-bg-color, data-mx-color

span
data-mx-bg-color, data-mx-color

a
name, target, href (provided the value is not relative and has a scheme matching one of: https, http, ftp, mailto, magnet)

img
width, height, alt, title, src (provided it is a Matrix Content (MXC) URI)

ol
start

code
class (only classes which start with language- for syntax highlighting)

Additionally, web clients should ensure that all a tags get a rel="noopener" to prevent the target page from referencing the client’s tab/window.

Tags must not be nested more than 100 levels deep. Clients should only support the subset of tags they can render, falling back to other representations of the tags where possible. For example, a client may not be able to render tables correctly and instead could fall back to rendering tab-delimited text.

In addition to not rendering unsafe HTML, clients should not emit unsafe HTML in events. Likewise, clients should not generate HTML that is not needed, such as extra paragraph tags surrounding text due to Rich Text Editors. HTML included in events should otherwise be valid, such as having appropriate closing tags, appropriate attributes (considering the custom ones defined in this specification), and generally valid structure.

A special tag, mx-reply, may appear on rich replies (described below) and should be allowed if, and only if, the tag appears as the very first tag in the formatted_body. The tag cannot be nested and cannot be located after another tag in the tree. Because the tag contains HTML, an mx-reply is expected to have a partner closing tag and should be treated similar to a div. Clients that support rich replies will end up stripping the tag and its contents and therefore may wish to exclude the tag entirely.

m.text


This message is the most basic message and is used to represent text.

Event type: Message event

Content

Name Type Description
body string Required: The body of the message.
format string The format used in the formatted_body. Currently only org.matrix.custom.html is supported.
formatted_body string The formatted version of the body. This is required if format is specified.
msgtype enum Required:

One of: [m.text].

Examples

{
  "content": {
    "body": "This is an example text message",
    "format": "org.matrix.custom.html",
    "formatted_body": "\u003cb\u003eThis is an example text message\u003c/b\u003e",
    "msgtype": "m.text"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

m.emote


This message is similar to m.text except that the sender is ‘performing’ the action contained in the body key, similar to /me in IRC. This message should be prefixed by the name of the sender. This message could also be represented in a different colour to distinguish it from regular m.text messages.

Event type: Message event

Content

Name Type Description
body string Required: The emote action to perform.
format string The format used in the formatted_body. Currently only org.matrix.custom.html is supported.
formatted_body string The formatted version of the body. This is required if format is specified.
msgtype enum Required:

One of: [m.emote].

Examples

{
  "content": {
    "body": "thinks this is an example emote",
    "format": "org.matrix.custom.html",
    "formatted_body": "thinks \u003cb\u003ethis\u003c/b\u003e is an example emote",
    "msgtype": "m.emote"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

m.notice


The m.notice type is primarily intended for responses from automated clients. An m.notice message must be treated the same way as a regular m.text message with two exceptions. Firstly, clients should present m.notice messages to users in a distinct manner, and secondly, m.notice messages must never be automatically responded to. This helps to prevent infinite-loop situations where two automated clients continuously exchange messages.

Event type: Message event

Content

Name Type Description
body string Required: The notice text to send.
format string The format used in the formatted_body. Currently only org.matrix.custom.html is supported.
formatted_body string The formatted version of the body. This is required if format is specified.
msgtype enum Required:

One of: [m.notice].

Examples

{
  "content": {
    "body": "This is an example notice",
    "format": "org.matrix.custom.html",
    "formatted_body": "This is an \u003cstrong\u003eexample\u003c/strong\u003e notice",
    "msgtype": "m.notice"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

m.image


This message represents a single image and an optional thumbnail.

Event type: Message event

Content

Name Type Description
body string Required: A textual representation of the image. This could be the alt text of the image, the filename of the image, or some kind of content description for accessibility e.g. ‘image attachment’.
file EncryptedFile Required if the file is encrypted. Information on the encrypted file, as specified in End-to-End Encryption.
info ImageInfo Metadata about the image referred to in url.
msgtype enum Required:

One of: [m.image].

url string Required if the file is unencrypted. The URL (typically MXC URI) to the image.
ImageInfo
Name Type Description
h integer The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.
mimetype string The mimetype of the image, e.g. image/jpeg.
size integer Size of the image in bytes.
thumbnail_file EncryptedFile Information on the encrypted thumbnail file, as specified in End-to-End Encryption. Only present if the thumbnail is encrypted.
thumbnail_info ThumbnailInfo Metadata about the image referred to in thumbnail_url.
thumbnail_url string The URL (typically MXC URI) to a thumbnail of the image. Only present if the thumbnail is unencrypted.
w integer The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.
ThumbnailInfo
Name Type Description
h integer The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.
mimetype string The mimetype of the image, e.g. image/jpeg.
size integer Size of the image in bytes.
w integer The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "body": "filename.jpg",
    "info": {
      "h": 398,
      "mimetype": "image/jpeg",
      "size": 31037,
      "w": 394
    },
    "msgtype": "m.image",
    "url": "mxc://example.org/JWEIFJgwEIhweiWJE"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

m.file


This message represents a generic file.

Event type: Message event

Content

Name Type Description
body string Required: A human-readable description of the file. This is recommended to be the filename of the original upload.
file EncryptedFile Required if the file is encrypted. Information on the encrypted file, as specified in End-to-End Encryption.
filename string The original filename of the uploaded file.
info FileInfo Information about the file referred to in url.
msgtype enum Required:

One of: [m.file].

url string Required if the file is unencrypted. The URL (typically MXC URI) to the file.
FileInfo
Name Type Description
mimetype string The mimetype of the file e.g. application/msword.
size integer The size of the file in bytes.
thumbnail_file EncryptedFile Information on the encrypted thumbnail file, as specified in End-to-End Encryption. Only present if the thumbnail is encrypted.
thumbnail_info ThumbnailInfo Metadata about the image referred to in thumbnail_url.
thumbnail_url string The URL to the thumbnail of the file. Only present if the thumbnail is unencrypted.
ThumbnailInfo
Name Type Description
h integer The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.
mimetype string The mimetype of the image, e.g. image/jpeg.
size integer Size of the image in bytes.
w integer The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "body": "something-important.doc",
    "filename": "something-important.doc",
    "info": {
      "mimetype": "application/msword",
      "size": 46144
    },
    "msgtype": "m.file",
    "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

m.audio


This message represents a single audio clip.

Event type: Message event

Content

Name Type Description
body string Required: A description of the audio e.g. ‘Bee Gees - Stayin’ Alive', or some kind of content description for accessibility e.g. ‘audio attachment’.
file EncryptedFile Required if the file is encrypted. Information on the encrypted file, as specified in End-to-End Encryption.
info AudioInfo Metadata for the audio clip referred to in url.
msgtype enum Required:

One of: [m.audio].

url string Required if the file is unencrypted. The URL (typically MXC URI) to the audio clip.
AudioInfo
Name Type Description
duration integer The duration of the audio in milliseconds.
mimetype string The mimetype of the audio e.g. audio/aac.
size integer The size of the audio clip in bytes.

Examples

{
  "content": {
    "body": "Bee Gees - Stayin' Alive",
    "info": {
      "duration": 2140786,
      "mimetype": "audio/mpeg",
      "size": 1563685
    },
    "msgtype": "m.audio",
    "url": "mxc://example.org/ffed755USFFxlgbQYZGtryd"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

m.location


This message represents a real-world location.

Event type: Message event

Content

Name Type Description
body string Required: A description of the location e.g. ‘Big Ben, London, UK’, or some kind of content description for accessibility e.g. ‘location attachment’.
geo_uri string Required: A geo URI representing this location.
info LocationInfo
msgtype enum Required:

One of: [m.location].

LocationInfo
Name Type Description
thumbnail_file EncryptedFile Information on the encrypted thumbnail file, as specified in End-to-End Encryption. Only present if the thumbnail is encrypted.
thumbnail_info ThumbnailInfo Metadata about the image referred to in thumbnail_url.
thumbnail_url string The URL to the thumbnail of the file. Only present if the thumbnail is unencrypted.
ThumbnailInfo
Name Type Description
h integer The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.
mimetype string The mimetype of the image, e.g. image/jpeg.
size integer Size of the image in bytes.
w integer The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "body": "Big Ben, London, UK",
    "geo_uri": "geo:51.5008,0.1247",
    "info": {
      "thumbnail_info": {
        "h": 300,
        "mimetype": "image/jpeg",
        "size": 46144,
        "w": 300
      },
      "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
    },
    "msgtype": "m.location"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

m.video


This message represents a single video clip.

Event type: Message event

Content

Name Type Description
body string Required: A description of the video e.g. ‘Gangnam style’, or some kind of content description for accessibility e.g. ‘video attachment’.
file EncryptedFile Required if the file is encrypted. Information on the encrypted file, as specified in End-to-End Encryption.
info VideoInfo Metadata about the video clip referred to in url.
msgtype enum Required:

One of: [m.video].

url string Required if the file is unencrypted. The URL (typically MXC URI) to the video clip.
VideoInfo
Name Type Description
duration integer The duration of the video in milliseconds.
h integer The height of the video in pixels.
mimetype string The mimetype of the video e.g. video/mp4.
size integer The size of the video in bytes.
thumbnail_file EncryptedFile Information on the encrypted thumbnail file, as specified in End-to-End Encryption. Only present if the thumbnail is encrypted.
thumbnail_info ThumbnailInfo Metadata about the image referred to in thumbnail_url.
thumbnail_url string The URL (typically MXC URI) to an image thumbnail of the video clip. Only present if the thumbnail is unencrypted.
w integer The width of the video in pixels.
ThumbnailInfo
Name Type Description
h integer The intended display height of the image in pixels. This may differ from the intrinsic dimensions of the image file.
mimetype string The mimetype of the image, e.g. image/jpeg.
size integer Size of the image in bytes.
w integer The intended display width of the image in pixels. This may differ from the intrinsic dimensions of the image file.

Examples

{
  "content": {
    "body": "Gangnam Style",
    "info": {
      "duration": 2140786,
      "h": 320,
      "mimetype": "video/mp4",
      "size": 1563685,
      "thumbnail_info": {
        "h": 300,
        "mimetype": "image/jpeg",
        "size": 46144,
        "w": 300
      },
      "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
      "w": 480
    },
    "msgtype": "m.video",
    "url": "mxc://example.org/a526eYUSFFxlgbQYZmo442"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

Client behaviour

Clients SHOULD verify the structure of incoming events to ensure that the expected keys exist and that they are of the right type. Clients can discard malformed events or display a placeholder message to the user. Redacted m.room.message events MUST be removed from the client. This can either be replaced with placeholder text (e.g. “[REDACTED]") or the redacted message can be removed entirely from the messages view.

Events which have attachments (e.g. m.image, m.file) SHOULD be uploaded using the content repository module where available. The resulting mxc:// URI can then be used in the url key.

Clients MAY include a client generated thumbnail image for an attachment under a info.thumbnail_url key. The thumbnail SHOULD also be a mxc:// URI. Clients displaying events with attachments can either use the client generated thumbnail or ask its homeserver to generate a thumbnail from the original attachment using the content repository module.

Recommendations when sending messages

In the event of send failure, clients SHOULD retry requests using an exponential-backoff algorithm for a certain amount of time T. It is recommended that T is no longer than 5 minutes. After this time, the client should stop retrying and mark the message as “unsent”. Users should be able to manually resend unsent messages.

Users may type several messages at once and send them all in quick succession. Clients SHOULD preserve the order in which they were sent by the user. This means that clients should wait for the response to the previous request before sending the next request. This can lead to head-of-line blocking. In order to reduce the impact of head-of-line blocking, clients should use a queue per room rather than a global queue, as ordering is only relevant within a single room rather than between rooms.

Local echo

Messages SHOULD appear immediately in the message view when a user presses the “send” button. This should occur even if the message is still sending. This is referred to as “local echo”. Clients SHOULD implement “local echo” of messages. Clients MAY display messages in a different format to indicate that the server has not processed the message. This format should be removed when the server responds.

Clients need to be able to match the message they are sending with the same message which they receive from the event stream. The echo of the same message from the event stream is referred to as “remote echo”. Both echoes need to be identified as the same message in order to prevent duplicate messages being displayed. Ideally this pairing would occur transparently to the user: the UI would not flicker as it transitions from local to remote. Flickering can be reduced through clients making use of the transaction ID they used to send a particular event. The transaction ID used will be included in the event’s unsigned data as transaction_id when it arrives through the event stream.

Clients unable to make use of the transaction ID are likely to experience flickering when the remote echo arrives on the event stream before the request to send the message completes. In that case the event arrives before the client has obtained an event ID, making it impossible to identify it as a remote echo. This results in the client displaying the message twice for some time (depending on the server responsiveness) before the original request to send the message completes. Once it completes, the client can take remedial actions to remove the duplicate event by looking for duplicate event IDs.

Calculating the display name for a user

Clients may wish to show the human-readable display name of a room member as part of a membership list, or when they send a message. However, different members may have conflicting display names. Display names MUST be disambiguated before showing them to the user, in order to prevent spoofing of other users.

To ensure this is done consistently across clients, clients SHOULD use the following algorithm to calculate a disambiguated display name for a given user:

  1. Inspect the m.room.member state event for the relevant user id.
  2. If the m.room.member state event has no displayname field, or if that field has a null value, use the raw user id as the display name. Otherwise:
  3. If the m.room.member event has a displayname which is unique among members of the room with membership: join or membership: invite, use the given displayname as the user-visible display name. Otherwise:
  4. The m.room.member event has a non-unique displayname. This should be disambiguated using the user id, for example “display name (@id:homeserver.org)”.

Developers should take note of the following when implementing the above algorithm:

Displaying membership information with messages

Clients may wish to show the display name and avatar URL of the room member who sent a message. This can be achieved by inspecting the m.room.member state event for that user ID (see Calculating the display name for a user).

When a user paginates the message history, clients may wish to show the historical display name and avatar URL for a room member. This is possible because older m.room.member events are returned when paginating. This can be implemented efficiently by keeping two sets of room state: old and current. As new events arrive and/or the user paginates back in time, these two sets of state diverge from each other. New events update the current state and paginated events update the old state. When paginated events are processed sequentially, the old state represents the state of the room at the time the event was sent. This can then be used to set the historical display name and avatar URL.

Calculating the display name for a room

Clients may wish to show a human-readable name for a room. There are a number of possibilities for choosing a useful name. To ensure that rooms are named consistently across clients, clients SHOULD use the following algorithm to choose a name:

  1. If the room has an m.room.name state event with a non-empty name field, use the name given by that field.
  2. If the room has an m.room.canonical_alias state event with a valid alias field, use the alias given by that field as the name. Note that clients should avoid using alt_aliases when calculating the room name.
  3. If none of the above conditions are met, a name should be composed based on the members of the room. Clients should consider m.room.member events for users other than the logged-in user, as defined below.
    1. If the number of m.heroes for the room are greater or equal to m.joined_member_count + m.invited_member_count - 1, then use the membership events for the heroes to calculate display names for the users (disambiguating them if required) and concatenating them. For example, the client may choose to show “Alice, Bob, and Charlie (@charlie:example.org)” as the room name. The client may optionally limit the number of users it uses to generate a room name.
    2. If there are fewer heroes than m.joined_member_count + m.invited_member_count - 1, and m.joined_member_count + m.invited_member_count is greater than 1, the client should use the heroes to calculate display names for the users (disambiguating them if required) and concatenating them alongside a count of the remaining users. For example, “Alice, Bob, and 1234 others”.
    3. If m.joined_member_count + m.invited_member_count is less than or equal to 1 (indicating the member is alone), the client should use the rules above to indicate that the room was empty. For example, “Empty Room (was Alice)”, “Empty Room (was Alice and 1234 others)”, or “Empty Room” if there are no heroes.

Clients SHOULD internationalise the room name to the user’s language when using the m.heroes to calculate the name. Clients SHOULD use minimum 5 heroes to calculate room names where possible, but may use more or less to fit better with their user experience.

Forming relationships between events

In some cases, events may wish to reference other events. This could be to form a thread of messages for the user to follow along with, or to provide more context as to what a particular event is describing. Currently, the only kind of relation defined is a “rich reply” where a user may reference another message to create a thread-like conversation.

Relationships are defined under an m.relates_to key in the event’s content. If the event is of the type m.room.encrypted, the m.relates_to key MUST NOT be covered by the encryption and instead be put alongside the encryption information held in the content.

Rich replies

Users may wish to reference another message when forming their own message, and clients may wish to better embed the referenced message for the user to have a better context for the conversation being had. This sort of embedding another message in a message is known as a “rich reply”, or occasionally just a “reply”.

A rich reply is formed through use of an m.relates_to relation for m.in_reply_to where a single key, event_id, is used to reference the event being replied to. The referenced event ID SHOULD belong to the same room where the reply is being sent. Clients should be cautious of the event ID belonging to another room, or being invalid entirely. Rich replies can only be constructed in the form of m.room.message events with a msgtype of m.text or m.notice. Due to the fallback requirements, rich replies cannot be constructed for types of m.emote, m.file, etc. Rich replies may reference any other m.room.message event, however. Rich replies may reference another event which also has a rich reply, infinitely.

An m.in_reply_to relationship looks like the following:

{
  ...
  "type": "m.room.message",
  "content": {
    "msgtype": "m.text",
    "body": "<body including fallback>",
    "format": "org.matrix.custom.html",
    "formatted_body": "<HTML including fallback>",
    "m.relates_to": {
      "m.in_reply_to": {
        "event_id": "$another:event.com"
      }
    }
  }
}

####### Fallbacks and event representation

Some clients may not have support for rich replies and therefore need a fallback to use instead. Clients that do not support rich replies should render the event as if rich replies were not special.

Clients that do support rich replies MUST provide the fallback format on replies, and MUST strip the fallback before rendering the reply. Rich replies MUST have a format of org.matrix.custom.html and therefore a formatted_body alongside the body and appropriate msgtype. The specific fallback text is different for each msgtype, however the general format for the body is:

> <@alice:example.org> This is the original body

This is where the reply goes

The formatted_body should use the following template:

<mx-reply>
  <blockquote>
    <a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">In reply to</a>
    <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
    <br />
    <!-- This is where the related event's HTML would be. -->
  </blockquote>
</mx-reply>
This is where the reply goes.

If the related event does not have a formatted_body, the event’s body should be considered after encoding any HTML special characters. Note that the href in both of the anchors use a matrix.to URI.

######## Stripping the fallback

Clients which support rich replies MUST strip the fallback from the event before rendering the event. This is because the text provided in the fallback cannot be trusted to be an accurate representation of the event. After removing the fallback, clients are recommended to represent the event referenced by m.in_reply_to similar to the fallback’s representation, although clients do have creative freedom for their user interface. Clients should prefer the formatted_body over the body, just like with other m.room.message events.

To strip the fallback on the body, the client should iterate over each line of the string, removing any lines that start with the fallback prefix ("> “, including the space, without quotes) and stopping when a line is encountered without the prefix. This prefix is known as the “fallback prefix sequence”.

To strip the fallback on the formatted_body, the client should remove the entirety of the mx-reply tag.

######## Fallback for m.text, m.notice, and unrecognised message types

Using the prefix sequence, the first line of the related event’s body should be prefixed with the user’s ID, followed by each line being prefixed with the fallback prefix sequence. For example:

> <@alice:example.org> This is the first line
> This is the second line

This is the reply

The formatted_body uses the template defined earlier in this section.

######## Fallback for m.emote

Similar to the fallback for m.text, each line gets prefixed with the fallback prefix sequence. However an asterisk should be inserted before the user’s ID, like so:

> * <@alice:example.org> feels like today is going to be a great day

This is the reply

The formatted_body has a subtle difference for the template where the asterisk is also inserted ahead of the user’s ID:

<mx-reply>
  <blockquote>
    <a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">In reply to</a>
    * <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
    <br />
    <!-- This is where the related event's HTML would be. -->
  </blockquote>
</mx-reply>
This is where the reply goes.

######## Fallback for m.image, m.video, m.audio, and m.file

The related event’s body would be a file name, which may not be very descriptive. The related event should additionally not have a format or formatted_body in the content - if the event does have a format and/or formatted_body, those fields should be ignored. Because the filename alone may not be descriptive, the related event’s body should be considered to be "sent a file." such that the output looks similar to the following:

> <@alice:example.org> sent a file.

This is the reply

<mx-reply>
  <blockquote>
    <a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">In reply to</a>
    <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
    <br />
    sent a file.
  </blockquote>
</mx-reply>
This is where the reply goes.

For m.image, the text should be "sent an image.". For m.video, the text should be "sent a video.". For m.audio, the text should be "sent an audio file".

Server behaviour

Homeservers SHOULD reject m.room.message events which don’t have a msgtype key, or which don’t have a textual body key, with an HTTP status code of 400.

Security considerations

Messages sent using this module are not encrypted, although end to end encryption is in development (see E2E module).

Clients should sanitise all displayed keys for unsafe HTML to prevent Cross-Site Scripting (XSS) attacks. This includes room names and topics.