Skip to main content
CometChat.uploadFiles() uploads one or more files directly to storage and reports per-file progress, success, and failure through a listener. It is decoupled from sending: uploading returns you an Attachment (carrying a hosted url) for each file, which you then attach to a MediaMessage and send with sendMediaMessage(). This is the recommended way to build a multi-attachment composer: upload a batch of files, show a progress bar per file, let the user cancel or retry individual files, and once they’re ready, send them as a single media message with multiple attachments (or split across several messages).
Why upload separately instead of passing files to sendMediaMessage()?The classic path (passing a file, or FileList, straight to the MediaMessage constructor) uploads and sends in one blocking call — you get no progress, no per-file cancel, and no per-file retry. uploadFiles() moves the upload out of the send call so you can drive a rich composer UI, then send instantly because the files are already hosted.

The upload-then-send flow

1

Collect files

Get platform-native file objects (e.g. File/Blob from an <input type="file"> on web).
2

Upload

Call CometChat.uploadFiles(files, receiverId, receiverType, listener). The recipient (receiverId + receiverType) is required — the server uses it to apply role- and scope-based access control before issuing upload URLs. It returns synchronously with a batchId and a fileId per file (in input order) so you can map callbacks back to your UI rows.
3

Track progress & handle failures

Your MediaUploadListener receives onProgress for each file, then onFileUploaded (success), onFileError (rejected — not retryable), or onFileFailure (failed — retryable). Use cancelFileUpload() / retryFileUpload() as the user acts.
4

Collect attachments

Each onFileUploaded (and the final onComplete) hands you an Attachment with a hosted url. Gather the ones you want to send.
5

Build & send the message

Put the attachments on a MediaMessage with setAttachments([...]) and call sendMediaMessage(). Because the attachments already have URLs, the message is sent as JSON — no re-upload.
6

Clean up

Call clearUploadGroup(batchId) after a successful send (or to abandon the composer) to release the batch from memory.

Upload files

uploadFiles() accepts these arguments:
The recipient must match the message you’ll eventually send. receiverId / receiverType are sent to the upload-authorization (presign) endpoint, which enforces the sender’s role- and scope-based access control for that conversation before any bytes transfer. If the sender isn’t allowed to send media to that user or group, each file is rejected via onFileError with ERR_PERMISSION_DENIED (not retryable). Pass the same recipient you’ll set on the MediaMessage at send time — uploading against one recipient and sending to another can pass the upload check but is not the intended usage.
It returns synchronously:
Validation, presigning, and the actual byte transfer all run asynchronously after the method returns. Use the fileIds to line each file up with its UI row, then update that row as the listener fires.

The MediaUploadListener

Pass a MediaUploadListener with only the callbacks you need — all are optional. Unlike MessageListener or CallListener, it is not registered globally with a string id; it lives for the duration of the upload batch.
Rejected vs. failed — the key distinction. onFileError (rejected) means the request itself is unacceptable — invalid file object, over the size limit, or the sender isn’t permitted to upload to this recipient (ERR_PERMISSION_DENIED). Retrying won’t help; the user must swap the file or you must fix the recipient/permissions. onFileFailure (failed) means a transient transport problem — network drop, an expired presigned URL, or a stalled upload. These can be retried with retryFileUpload().

UploadResult

onComplete receives the group’s settled state. onComplete fires each time the group drains — including after a retry adds new work and it drains again.

Upload options

Pass an optional third argument to tune the batch:

Cancel, retry & clear

All active upload groups are also cleared automatically on CometChat.logout().

Send the uploaded files as a media message

Once your files are uploaded, collect their Attachments (from onFileUploaded or from result.successful in onComplete), set them on a MediaMessage, and send. One upload batch can go out as a single multi-attachment message, or you can split the attachments across several messages.
sendMediaMessage() enforces the maximum attachments per message (see Limits). If a batch has more successful uploads than the limit allows, split them across multiple MediaMessages. See Multiple Attachments in a Media Message.

Limits

Two independent checks guard the flow, each using a limit read from your app settings (with a built-in fallback): Read the current attachment-count limit at runtime with getMaxAttachmentCount() — useful for disabling the “add file” button in your composer once the user hits the cap:
The per-file size limit is checked in uploadFiles() (before the byte transfer), while the attachment count limit is checked in sendMediaMessage() (when you send). A batch can therefore succeed at upload time but still be rejected at send time if it exceeds the count limit — plan your composer around both.

Reliability behavior

The SDK handles a few transport edge cases for you:
  • Stalled uploads — if a file makes no progress for 30 seconds, its upload is aborted and reported through onFileFailure with ERR_UPLOAD_STALLED. Retry it with retryFileUpload().
  • Expired upload URLs — the pre-signed upload URL for each file is valid for 15 minutes. retryFileUpload() automatically requests a fresh URL if the original has expired, so retries keep working even after a long delay.
  • Storage errors — if storage rejects the upload, the failure surfaces through onFileFailure with ERR_S3_UPLOAD_FAILED and, where available, the storage’s own message.

Error handling

Every error delivered to onFileError / onFileFailure (and rejections from sendMediaMessage()) is a CometChatException. The upload-specific codes: ERR_PERMISSION_DENIED is returned by the server’s access-control check, so its exact code and message come from your backend. See the full list on the Error Codes page.

Next Steps

Send A Message

Send text, media, and custom messages

Multiple Attachments

Send several attachments in one media message

Error Codes

Media upload error reference

Receive Messages

Listen for incoming messages in real-time