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
- TypeScript
- JavaScript
uploadFiles() accepts these arguments:
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 aMediaUploadListener 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.
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:- TypeScript
- JavaScript
Cancel, retry & clear
- TypeScript
- JavaScript
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 theirAttachments (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.
- TypeScript
- JavaScript
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:
- TypeScript
- JavaScript
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
onFileFailurewithERR_UPLOAD_STALLED. Retry it withretryFileUpload(). - 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
onFileFailurewithERR_S3_UPLOAD_FAILEDand, where available, the storage’s own message.
Error handling
Every error delivered toonFileError / 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