File Sharing
PubNub makes it easy to add file sharing alongside messages and signals.
Use file sharing to share images in social apps or send medical records in healthcare apps. You can easily upload and share videos, images, or documents up to 5 MB per file.
Turn on File Sharing to start sending files with your keyset.
Configuration
Enable and configure File Sharing for your app's keyset in the Admin Portal.
Public Admin Portal demo
Want to browse through the Admin Portal without creating an account? Explore it through the Public Demo that shows examples of most PubNub features for transport and logistics use case.
The Admin Portal prompts you to enable File Sharing when you create a keyset (unless you choose Choose later for Region).
Testing keysets default to the US East
region with 7‑day
retention. Retention is how long PubNub keeps files before deletion.
Option | Description |
---|---|
Bucket Region | The geographical region where PubNub stores and manages your files. Align file retention with your Message Persistence settings to keep messages and files for the same duration. |
Retention | The duration that PubNub keeps files. Free accounts support 1 or 7 days. Paid accounts support higher limits. |
Send files
To send a file, choose the channel and the file. You can add a text caption.
You can encrypt files using Advanced Encryption Standard (AES-256) (see Data Security). Set a cipher key in the client configuration or pass it per request. Clients that download the file must use the same key.
The following code sends the file cat_picture.jpg
of the custom type file-message
on the channel my_channel
.
Custom message types
Not all SDKs support sending messages with a custom message type. For details, see Message Types.
- JavaScript
- C#
- Go
- Objective-C
- Java
- Python
- PHP
- Swift
- Dart
// web
const input = document.querySelector('input[file]');
input.addEventListener('change', async () => {
const file = input.files[0];
const result = await pubnub.sendFile({
channel: 'my_channel',
file: file,
customMessageType: 'file-message'
});
});
// Node.js
import fs from 'fs';
show all 36 linesPNResult<PNFileUploadResult> fileUploadResponse = await pubnub.SendFile()
.Channel("my_channel")
.File("cat_picture.jpg") // checks the bin folder if no path is provided
.Message("Look at this photo!")
.ExecuteAsync();
PNFileUploadResult fileUploadResult = fileUploadResponse.Result;
PNStatus fileUploadStatus = fileUploadResponse.Status; // contains troubleshooting info
if (!fileUploadStatus.Error && fileUploadResult != null) // checks if successful
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileUploadResult));
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileUploadStatus));
}
file, err := os.Open("cat_picture.jpg")
defer file.Close()
if err != nil {
panic(err)
}
resSendFile, statusSendFile, errSendFile := pn.SendFile().
Channel("my_channel").
Message("Look at this photo!").
Name("cat_picture.jpg").
File(file).Execute()
fmt.Println(resSendFile, statusSendFile, errSendFile)
fmt.Println(resSendFile.Data.ID)
NSURL *localFileURL = ...;
PNSendFileRequest *request = [PNSendFileRequest requestWithChannel:@"my_channel"
fileURL:localFileURL];
request.customMessageType = @"file-message";
[self.client sendFileWithRequest:request completion:^(PNSendFileStatus *status) {
if (!status.isError) {
/**
* File upload successfully completed.
* Uploaded file information is available here:
* status.data.fileIdentifier is the unique file identifier
* status.data.fileName is the name used to store the file
*/
} else {
/**
show all 23 linespubnub.sendFile()
.channel("my_channel")
.fileName("cat_picture.jpg")
.customMessageType("file-message")
.inputStream(inputStream)
.message("Look at this photo!")
.async(result -> {
result.onSuccess(res -> {
System.out.println("send timetoken: " + res.getTimetoken());
System.out.println("send status: " + res.getStatus());
System.out.println("send fileId: " + res.getFile().getId());
System.out.println("send fileName: " + res.getFile().getName());
}).onFailure(exception -> {
exception.printStackTrace();
});
show all 16 lines# synchronous
with open("cat_picture.jpg", "rb") as fd:
envelope = pubnub.send_file() \
.channel("my_channel") \
.file_name("cat_picture.jpg") \
.message({"test_message": "test"}) \
.custom_message_type('file-message') \
.should_store(True) \
.ttl(222) \
.file_object(fd) \
.cipher_key("secret") \
.sync()
# multithreaded asynchronous
def callback(response, status):
show all 28 linespubnub.sendFile()
->message("Hey, this is the requested file.")
->channel("channel_1")
->fileId("p1n4ppl3p1zz4")
->fileName("pinapplePizza.jpg")
->customMessageType("file-message")
->sync();
pubnub.send(
.file(url: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("cat_picture.jpg")),
channel: "my_channel",
remoteFilename: "cat_picture.jpg",
publishRequest: .init(additionalMessage: ["text": "Look at this photo!"], customMessageType: "file-message")
) { (fileTask) in
print("The task \(fileTask.urlSessionTask.taskIdentifier) has started uploading; no need to call `resume()`")
print("If needed, the `URLSessionUploadTask` can be accessed with `fileTask.urlSessionTask`")
print("You can use `fileTask.progress` to populate a `UIProgressView`/`ProgressView` ")
} completion: { (result) in
switch result {
case let .success((task, file, publishedAt)):
print("The file with an ID of \(file.fileId) was uploaded at \(publishedAt) timetoken) ")
case let .failure(error):
print("An error occurred while uploading the file: \(error.localizedDescription)")
show all 17 linesimport 'dart:io';
import 'package:pubnub/pubnub.dart';
void main() async {
var pubnub = PubNub(
defaultKeyset: Keyset(
subscribeKey: 'sub-c-abc-123', // Replace with your subscribe key
publishKey: 'pub-c-def-456' // Replace with your publish key
),
);
var inputFile = File('cat_picture.jpg').readAsBytesSync();
try {
var result = await pubnub.files.sendFile(
show all 27 linesThe client uploads files, and the storage service stores and manages the files for each keyset.
After upload, channel subscribers receive a file message with a description, file name, and file ID. Use an SDK method to build a URL to view or download the file. For details, see Retrieve files.
Enable the feature
File Sharing is an optional feature that you must enable for your keys in the Admin Portal.
File operations
You can list files in a channel or delete uploaded files. If the keyset has Message Persistence, you can search historical file messages with the Message Persistence API. Use the results to display or download files.
Refer to the File Sharing section in the SDK documentation for details about file operations in each SDK.
Receive files
To receive a file, subscribe to the channel and listen for file events. No special subscription is required.
Retrieve files
Retrieving files takes two steps. Use the Message Persistence API and File Sharing SDK methods. To retrieve a file:
- Get the file message by using the Message Persistence API or the
listFiles
method. - Display or download the file by using dedicated SDK methods and the returned file information.
File URLs
The Message Persistence API and the listFiles
method return secure file metadata (such as file name and ID). Use SDK methods to generate file URLs for viewing or downloading.
When you fetch file messages with the Message Persistence API, the response includes the file ID, file name, and message type 4
(file message). Use this data to view or download the file.
Display and download files
Apart from the optional description, a file message contains the file ID and file name.
A file message has no URL. Use an SDK method to build the file URL to view or download the file.
The following code returns the URL of the cat_picture.jpg
file sent to the channel my_channel
:
- JavaScript
- C#
- Go
- Objective-C
- Java
- Python
- Swift
- Dart
const result = pubnub.getFileUrl({ channel: 'my_channel', id: 'd9515cb7-48a7-41a4-9284-f4bf331bc770', name: 'cat_picture.jpg' });
PNResult<PNFileUrlResult> getFileUrlResponse = await pubnub.GetFileUrl()
.Channel("my_channel")
.FileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.FileName("cat_picture.jpg")
.ExecuteAsync();
PNFileUrlResult getFileUrlResult = getFileUrlResponse.Result;
PNStatus getFileUrlStatus = getFileUrlResponse.Status;
if (getFileUrlResult != null)
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(getFileUrlResult));
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(getFileUrlStatus));
}
resGetFile, statusGetFile, errGetFile := pn.GetFileURL().
Channel("my_channel").
ID("d9515cb7-48a7-41a4-9284-f4bf331bc770").
Name("cat_picture.jpg").Execute()
fmt.Println(resGetFile, statusGetFile, errGetFile)
fmt.Println(resGetFile.URL)
NSURL *url = [self.client downloadURLForFileWithName:@"cat_picture.jpg"
identifier:@"<file-identifier>"
inChannel:@"my_channel"];
pubnub.getFileUrl()
.channel("my_channel")
.fileName("cat_picture.jpg")
.fileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.async(result -> {
result.onSuccess(res -> {
System.out.println("getUrl fileUrl: " + res.getUrl());
}).onFailure(exception -> {
exception.printStackTrace();
});
});
# Synchronous:
envelope = pubnub.get_file_url().
channel("my_channel").
file_id("fileID").
file_name("cat_picture.jpg").sync()
# Multithreaded asynchronous:
def callback(response, status):
pass
pubnub.get_file_url().
channel("my_channel").
file_id("fileID").
file_name("cat_picture.jpg").sync()
do {
let downloadURL = try pubnub.generateFileDownloadURL(channel: "my_channel", fileId: "fileID", filename: "cat_picture.jpg")
} catch {
print("An error occurred generating the URL: \(error.localizedDescription)")
}
import 'package:pubnub/pubnub.dart';
void main() async {
var pubnub = PubNub(
defaultKeyset: Keyset(
subscribeKey: 'sub-c-abc-123', // Replace with your subscribe key
publishKey: 'pub-c-def-456' // Replace with your publish key
),
);
var fileUrl = pubnub.files.getFileUrl(
'my_channel',
'd9515cb7-48a7-41a4-9284-f4bf331bc770',
'cat_picture.jpg'
);
show all 18 linesThe call returns a file URL. Use it to view the file in the browser.
Use the same file information to download the file. The following example downloads cat_picture.jpg
from my_channel
:
- JavaScript
- C#
- Go
- Objective-C
- Java
- Python
- Swift
- Dart
// web
const file = await pubnub.downloadFile({
channel: 'my_channel',
id: '...',
name: 'cat_picture.jpg',
});
const myImageTag = document.createElement('img');
myImageTag.src = URL.createObjectURL(await file.toFile());
document.body.appendChild(myImageTag);
// Node.js using streams
import fs from 'fs'
show all 38 linesPNResult<PNDownloadFileResult> fileDownloadResponse = await pubnub.DownloadFile()
.Channel("my_channel")
.FileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.FileName("cat_picture.jpg")
.ExecuteAsync();
PNDownloadFileResult fileDownloadResult = fileDownloadResponse.Result;
PNStatus fileDownloadStatus = fileDownloadResponse.Status;
if (fileDownloadResult != null)
{
fileDownloadResult.SaveFileToLocal(downloadUrlFileName); // saves to bin folder if no path is provided
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileDownloadResult.FileName));
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileDownloadStatus));
show all 16 linesresDLFile, statusDLFile, errDLFile := pn.DownloadFile().
Channel("my_channel").
ID("d9515cb7-48a7-41a4-9284-f4bf331bc770").
Name("cat_picture.jpg").Execute()
if resDLFile != nil {
filepathOutput := "cat_picture.jpg"
out, _ := os.Create(filepathOutput)
_, err := io.Copy(out, resDLFile.File)
if err != nil {
fmt.Println(err)
}
}
PNDownloadFileRequest *request = [PNDownloadFileRequest requestWithChannel:@"my_channel"
identifier:@"<file-identifier>"
name:@"cat_picture.jpg"];
request.targetURL = ...;
[self.client downloadFileWithRequest:request
completion:^(PNDownloadFileResult *result, PNErrorStatus *status) {
if (!status.isError) {
/**
* File successfully has been downloaded.
* status.data.location - location where downloaded file can be found
* status.data.temporary - whether file has been downloaded to temporary storage and
* will be removed on completion block return.
*/
} else {
show all 23 linespubnub.downloadFile()
.channel("my_channel")
.fileName("cat_picture.jpg")
.fileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.async(result -> {
result.onSuccess(res -> {
System.out.println("getFile fileName: " + res.getFileName());
System.out.println("getFile byteStream: " + res.getByteStream());
}).onFailure(exception -> {
exception.printStackTrace();
});
});
# synchronous:
download_envelope = pubnub.download_file().
channel("my_channel").
file_id("fileId").
file_name("cat_picture.jpg").sync()
# Multithreaded asynchronous:
def callback(response, status):
pass
pubnub.download_file().
channel("my_channel").
file_id("fileID").
file_name("cat_picture.jpg").pn_async(callback)
let requestFile = PubNubLocalFileBase(
fileURL: URL(fileURLWithPath: "cat_picture.jpg"),
channel: "my_channel",
fileId: "fileId",
remoteFilename: "cat_picture.jpg"
)
pubnub.download(
file: requestFile, toFileURL: requestFile.fileURL
) { (fileTask: HTTPFileDownloadTask) in
print("The task \(fileTask.taskIdentifier) has started downloading; no need to call `resume()`")
print("If needed, the `URLSessionUploadTask` can be accessed with `fileTask.urlSessionTask`")
print("You can use `fileTask.progress` to populate a `UIProgressView`/`ProgressView` ")
show all 25 linesimport 'dart:io';
import 'package:pubnub/pubnub.dart';
void main() async {
var pubnub = PubNub(
defaultKeyset: Keyset(
subscribeKey: 'sub-c-abc-123', // Replace with your subscribe key
publishKey: 'pub-c-def-456' // Replace with your publish key
),
);
try {
var result = await pubnub.files.downloadFile(
'my_channel',
'd9515cb7-48a7-41a4-9284-f4bf331bc770',
show all 25 linesList files
To list files (without file messages), request up to 100 files for a channel. If more files exist, the response includes more
for pagination.
The following example returns the name, ID, size, and created timestamp for up to 100 files sent to the channel my_channel
:
- JavaScript
- C#
- Go
- Objective-C
- Java
- Python
- Swift
- Dart
const result = await pubnub.listFiles({ channel: 'my_channel' });
PNResult<PNListFilesResult> listFilesResponse = await pubnub.ListFiles()
.Channel("my_channel")
.ExecuteAsync();
PNListFilesResult listFilesResult = listFilesResponse.Result;
PNStatus listFilesStatus = listFilesResponse.Status;
if (listFilesResult != null)
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(listFilesResult));
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(listFilesStatus));
}
resListFile, statusListFile, errListFile := pn.ListFiles().
Channel("my_channel").Execute()
fmt.Println(resListFile, statusListFile, errListFile)
if resListFile != nil {
for _, m := range resListFile.Data {
fmt.Println(m.ID, m.Created, m.Name, m.Size)
}
}
PNListFilesRequest *request = [PNListFilesRequest requestWithChannel:@"my_channel"];
request.limit = 100;
request.next = ...;
[self.client listFilesWithRequest:request
completion:^(PNListFilesResult *result, PNErrorStatus *status) {
if (!status.isError) {
/**
* Uploaded files list successfully fetched.
* result.data.files - List of uploaded files (information).
* result.data.next - Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off.
* result.data.count - Total number of files uploaded to channel.
*/
} else {
/**
show all 22 linespubnub.listFiles()
.channel("my_channel")
.async(result -> {
result.onSuccess(res -> {
System.out.println("files status: " + res.getStatus());
System.out.println("files status: " + res.getNext());
System.out.println("files status: " + res.getCount());
System.out.println("files status: " + res.getCount());
for (PNUploadedFile file : res.getData()) {
System.out.println("files fileId: " + file.getId());
System.out.println("files fileName: " + file.getName());
System.out.println("files fileSize: " + file.getSize());
System.out.println("files fileCreated: " + file.getCreated());
}
}).onFailure(exception -> {
show all 18 lines# synchronous
pubnub.list_files().channel("my_channel").sync()
# multithreaded asynchronous
def callback(response, status):
pass
pubnub.list_files().channel("my_channel").pn_async(callback)
pubnub.listFiles(
channel: "my_channel"
) { result in
case let .success(response):
print("There are \(response.files.count) file(s) found")
if let nextPage = response.next {
print("The next page used for pagination: \(nextPage)")
}
case let .failure(error):
print("An error occurred while fetching the file list: \(error.localizedDescription)")
}
import 'package:pubnub/pubnub.dart';
void main() async {
var pubnub = PubNub(
defaultKeyset: Keyset(
subscribeKey: 'sub-c-abc-123', // Replace with your subscribe key
publishKey: 'pub-c-def-456' // Replace with your publish key
),
);
try {
var files = await pubnub.files.listFiles('my_channel');
print('Number of files uploaded: ${files.count}');
for (var file in files.filesDetail) {
show all 21 lines