Skip to contentSkip to navigationSkip to topbar
On this page

Building with Chat Attachments (Webchat 2.0)


(information)

Info

This guide is for Flex UI 1.x.x and channels that use Programmable Chat and Proxy. If you are using Flex UI 2.x.x or you are starting out, we recommend that you build with Webchat 3.0.

Chat attachments allow agents and customers to send non-text content, like images, PDFs, and videos using Flex Webchat. While you can do a lot of cool stuff using chat attachments, you'll need to create rules and safeguards to keep agents safe, customers happy, and your business secure. Fortunately, chat attachments were built in a customizable way. In the following code samples, you can see some of the strategies the Twilio team has cooked up to implement some common scenarios.

(information)

Info

There are many other ways to solve these problems, and your problems will likely be more complex than the scenarios presented here. These code samples are meant to be a starting point to help familiarize you with some of the tools you have available - so definitely tweak these to fit your preferred tooling and patterns!


Use Programmable Chat and the Flex UI to delete messages

use-programmable-chat-and-the-flex-ui-to-delete-messages page anchor

Each chat attachment is associated with a Message in the Programmable Chat API. To delete a file which has been sent, you can therefore delete the message using the remove method provided by Programmable Chat SDK.

1
// Add a delete button. to every MessageListItem
2
3
const DeleteMessage = ({ message }) => (
4
// message is the default prop passed through by the MessageListItem
5
<button type="button" onClick={() => message.source.remove()}>
6
delete
7
</button>
8
);
9
10
Flex.MessageListItem.Content.add(<DeleteMessage key="delete-message" />, { sortOrder: -1 });

Replace Actions to upload files to personal storage

replace-actions-to-upload-files-to-personal-storage page anchor

By default, chat attachments uses Twilio Chat's Media Resource for file storage. To use your own storage for message attachments, you'll need to replace the SendMediaMessage action, which is triggered when a media file is sent.

You'll need to:

  1. Upload the file to our own private storage
  2. Pass on the unique identifier to the replaced sendMessage Action in messageAttributes
  3. Trigger a regular sendMessage action.
1
// Implement personal storage
2
3
const uploadFileToMyStorage = async (file) => {
4
const formData = new FormData();
5
formData.append("image", file);
6
7
// Upload the file to private storage
8
const res = await fetch("https://api.imgur.com/3/image", {
9
method: "POST",
10
headers: new Headers({
11
Authorization: "Client-ID 546c25a59c58ad7"
12
}),
13
body: formData
14
});
15
return res.json();
16
};
17
18
// Replace the action
19
Flex.Actions.replaceAction("SendMediaMessage", async (payload: Flex.ActionPayload) => {
20
const { file, messageAttributes, channelSid } = payload;
21
22
// Retrieve the uploaded file location
23
const res = await uploadFileToMyStorage(file);
24
25
// Include the new media file when sending the message
26
return Flex.Actions.invokeAction("SendMessage", {
27
messageAttributes: {
28
...messageAttributes,
29
media: {
30
url: res.data.link,
31
filename: file.name,
32
contentType: file.type,
33
size: file.size
34
}
35
},
36
body: file.name,
37
channelSid
38
});
39
});
40
41
// Now you need to render your uploaded file. First, delete the body of the MessageBubble. Then, add a new body, including appropriate HTML that points to your uploaded file (in this example, an image tag is sufficient for rendering the image. Don't forget your alt text!)
42
43
// Create new message bubble content
44
const PersonalStorageContent = ({ message }) => (
45
<div>
46
<img src={message.source.attributes.media.url) alt=”file uploaded from custom storage” style={{ width: "100%" }} />
47
</div>
48
);
49
50
Flex.MessageBubble.Content.remove("body", {
51
if: (props) => !!props.message.source.attributes.media
52
});
53
54
Flex.MessageBubble.Content.add(<PersonalStorageContent key="message-bubble-body" />, {
55
if: (props) => !!props.message.source.attributes.media
56
});

Use before Action hooks to filter content and check for viruses

use-before-action-hooks-to-filter-content-and-check-for-viruses page anchor

Depending on your use case, content filtering and virus checking can be done in different ways, but most implementations will involve the before action hooks. For example, you can use it to download the file after content filtering, or run the downloaded file against a set of guidelines before it gets sent as a message.

1
// Check file content
2
3
Flex.Actions.addListener("beforeDownloadMedia", async (payload, cancelAction) => {
4
5
const { message } = payload;
6
7
const url = await message.media.getContentUrl();
8
9
// Validate file before download (note that checkFileContent method needs to be written)
10
11
const result = await checkFileContent(url);
12
13
if (!result.pass) {
14
15
// Failed to validate content of the file
16
17
cancelAction();
18
19
}
20
21
});
22
23
Flex.Actions.addListener("beforeSendMediaMessage", async (payload, cancelAction) => {
24
const { file } = payload;
25
26
// Validate file before sending
27
const result = await checkFileContent(file);
28
29
if (!result.pass) {
30
// Failed to validate content of the file
31
cancelAction();
32
}
33
});
34
35
Flex.Actions.addListener("beforeAttachFile", async (payload, cancelAction) => {
36
37
const { file } = payload;
38
39
// Validate file before attaching
40
const result = await checkFileContent(file);
41
42
if (!result.pass) {
43
// Failed to validate content of the file
44
cancelAction();
45
}
46
});

Use Programmable Chat to change permissions of inappropriate users

use-programmable-chat-to-change-permissions-of-inappropriate-users page anchor

Sometimes a chat user can send inappropriate files or messages and as an agent you might want to block this user from sending messages or media messages. This can be done using programmable chat rest api.

All users in chat are associated with a Role and Permissions. To block users, you'll want to create a blockedUser Role. Based on your needs, remove the sendMessage and/or sendMediaMessage permissions from the new Role

In order to block somebody, you can update the Role of their Member Resource using a Twilio Function. Provide the new blockedUser SID as the roleSid parameter. Check out the guide on using Functions from your Plugin for additional support.

Twilio Function Code

1
exports.handler = function(context, event, callback) {
2
// Use context parameter to initialize Twilio client and retrieve stored environment variables
3
const twilioClient = context.getTwilioClient();
4
const chatServiceSid = context.CHAT_SERVICE_SID; // // Get Chat service sid from https://www.twilio.com/console/chat/dashboard
5
const blockedUserSid = context.BLOCKED_USER_SID
6
7
8
// Use the event parameter to retrieve dynamic information, like the current chat channel and the member to blockedUserSid
9
const {chatChannelSid, memberSid} = event
10
11
console.log(event)
12
13
twilioClient.chat.services(chatServiceSid)
14
.channels(chatChannelSid)
15
.members(memberSid)
16
.update({roleSid: blockedUserSid})
17
.then(member => callback(null, member.sid))
18
.catch(err => callback(err, null))
19
};

Plugin Code

1
// Create function to block user
2
const blockUser = (chatChannelSid, memberSid) => {
3
const body = { chatChannelSid, memberSid };
4
5
// Set up the HTTP options for your request
6
const options = {
7
method: 'POST',
8
body: new URLSearchParams(body),
9
headers: {
10
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
11
}
12
};
13
14
// Make the network request using the Fetch API
15
fetch('https://YOUR_DOMAIN.twil.io/block-user', options)
16
.then(resp => resp.json())
17
.then(data => console.log(data));
18
}
19
}
20
21
// Create a button component to block users
22
const BlockUserButton = (props) => (
23
<button type="button" onClick={() => blockUser(props.channelSid, props.member.source.sid)}>
24
block
25
</button>
26
);
27
28
// Insert Block User Button into the Flex UI
29
Flex.MessageBubble.Content.add(<BlockUserButton key="block-user" />, {
30
if: (props) => !props.message.isFromMe
31
});
32

Need some help?

Terms of service

Copyright © 2024 Twilio Inc.