Share media
Share media such as images, videos and files with users in a chat room.
Upload the media to your own storage service, such as AWS S3, and then use the metadata
field to reference the location of the media when a user sends a message. On the receiving end, display the media to subscribers that received the message.
Access control
Ensure that you add a layer of authentication server-side if the media shouldn't be publicly available.
Do not add signed URLs to the message metadata
because everyone who receives the message will have access to it. Additionally, signed URLs typically have expiration dates and chat messages may be stored for longer.
If you serve the media directly from a service, such as AWS S3, consider saving a file name in the metadata
of the message. Then use a mechanism for the user to request a signed URL to the file.
Upload media
Users need to be able to choose which media to attach to their message in your app. Write an upload function and make it available in the chat app context.
You can use either a unique identifier for the media, or a URL to its location. Ensure that any identifier is unique and that URLs are validated when they are received.
The following is an example of an upload function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
async function uploadMedia() {
// ask the user to choose their media
// upload the media to your storage service
// return a unique identifier for the media
// mock implementation:
let mediaId = 'abcd123abcd';
// Some media metadata, useful for displaying the media in the UI
let title = 'A beautiful image';
let width = 1024;
let height = 768;
// Return the object
return { id: mediaId, title, width, height };
}
Use the uploadMedia()
flow to save the resulting object. In your UI, the mediaToAttach
array should be displayed so that users can see which which media will be attached to their message. It also enables users to add or remove selected media.
1
2
3
4
5
let mediaToAttach = [];
async function onMediaAttach() {
const mediaData = await uploadMedia();
mediaToAttach.push(mediaData);
}
Send a message
Once a user has 'attached' their media to the message, use the metadata
field of the message to store its reference. metadata
is a key-value object that can also be used to associate additional information such as its title and dimensions.
1
2
3
4
5
6
7
8
9
10
11
async function send(text) {
let metadata = {};
if (mediaToAttach.length > 0) {
metadata["media"] = mediaToAttach;
mediaToAttach = [];
}
await room.messages.send({
text: text,
metadata: metadata
});
}
Be aware that message metadata
is not validated by the server. Always treat it as untrusted user input.
Display media to subscribers
When a message is received that contains media, you need to display it in your app.
Firstly, make sure that you validate the metadata
. If you are using IDs then ensure they are in the correct format, or if using URLs then validate the schema, domain, path and query parameters are as expected.
Define a function to get the valid media from a message:
1
2
3
4
5
6
7
8
9
// assume IDs are 10-15 characters long and alphanumeric
const mediaIdRegex = /^[a-z0-9]{10,15}$/;
function getValidMedia(message) {
if (message.metadata.media && message.metadata.media.length > 0) {
return message.metadata.media.filter(mediaData => mediaIdRegex.test(mediaData.id));
}
return [];
}
Use a function or component to display the message and its media:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function createMessageDOM(message) {
const container = document.createElement("div");
container.setAttribute('data-message-serial', message.serial)
container.setAttribute('data-message-version', message.version)
const text = document.createElement("div");
text.innerText = message.text;
container.appendChild(text);
const validMedia = getValidMedia(message);
if (validMedia.length > 0) {
const mediaContainer = document.createElement("div");
for (let mediaData of validMedia) {
const img = document.createElement("img");
img.src = "https://example.com/images/"+mediaData.id;
img.alt = mediaData.title;
img.width = mediaData.width;
img.height = mediaData.height;
mediaContainer.appendChild(img);
}
container.appendChild(mediaContainer);
}
return container;
}
Add media to an existing message
You can also add media to an existing message by editing its metadata
:
1
2
3
4
5
6
7
8
9
10
let mediaId = 'abcd123abcd'; // assume this is the media we want to add
let message = ...; // assume this is the message we want to edit
const newMetadata = structuredClone(message.metadata);
if (!newMetadata.media) {
newMetadata.media = [];
}
newMetadata.media.push(mediaId);
room.messages.update(message.serial, message.copy({metadata: newMetadata}))
Remove media from an existing message
You can remove media from an existing message by updating its metadata
:
1
2
3
4
5
6
7
8
9
10
11
let mediaId = 'abcd123abcd'; // assume this is the media we want to remove
let message = ...; // assume this is the message we want to edit
if (!message.metadata.media || message.metadata.media.length === 0) {
//do nothing if there is no media
return;
}
const newMetadata = structuredClone(message.metadata);
newMetadata.media = newMetadata.media.filter(id => mediaId !== id);
room.messages.update(message.serial, message.copy({metadata: newMetadata}))
Media moderation
Ably moderation feature is currently limited to text moderation. To add automatic or human moderation for media, you'll need to implement moderation server-side.
An example flow for this would be:
- Upload the media to your storage service.
- Asynchronously start the moderation process on the server.
- Send a message with the
metadata
containing information about the media; either an ID or URL. - When a user requests the media from your server, check the moderation status and serve it or return an error.
This means you don't need to update the metadata
field of the message to reflect its moderation status.