Realtime
Realtime allows you to listen to any events on the server-side in realtime using the subscribe method.
Instead of requesting new data via HTTP, the subscription will receive new data every time it changes, any connected client receives that update within milliseconds via a WebSocket connection.
This lets you build an interactive and responsive user experience by providing information from all of Appwrite's services in realtime. The example below shows subscribing to realtime events for file uploads.
-
Web
const sdk = new Appwrite(); sdk .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint .setProject('5df5acd0d48c2') // Your project ID ; // Subscribe to files channel sdk.subscribe('files', response => { if(response.event === 'storage.files.create') { // Log when a new file is uploaded console.log(response.payload); } });
-
Flutter
final client = Client(); client .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your Appwrite Endpoint .setProject('5e8cf4f46b5e8') // Your project ID ; final realtime = Realtime(client); // Subscribe to files channel final subscription = realtime.subscribe(['files']); subscription.stream.listen((response) { if(response.event == 'storage.files.create') { // Log when a new file is uploaded print(response.payload); } });
-
Android
val client = Client(context) client .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint .setProject("5df5acd0d48c2") // Your project ID val realtime = Realtime(client) // Subscribe to files channel realtime.subscribe("files", callback = { response -> if(response.event === "storage.files.create") { // Log when a new file is uploaded print(response.payload.toString()); } })
-
Apple
let client = Client() client .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint .setProject("5df5acd0d48c2") // Your project ID let realtime = Realtime(client: client) // Subscribe to files channel let subscription = realtime.subscribe(channels: ["files"]) { message in if(message.event == "storage.files.create") { // Log when a new file is uploaded print(String(describing: message.payload)) } }
To subscribe to updates from different resources, you need to specify one or more channels. The channels offer a wide and powerful selection that will allow you to listen to all possible resources. This allows you to receive updates not only from the database, but from all the services that Appwrite offers.
If you listen to all documents from a collection by subscribing to the collections.[ID].documents channel, you can use the event attribute in the callback to distinguish whether a new document was created or an existing one was updated.
All possible events can be found here.
Permissions
All subscriptions are secured by the permissions offered by Appwrite, meaning a user will only receive updates to resources to which he has read permission.
Using role:all on read permissions will allow any client to receive updates.
Examples
The examples below will show you how you can use Realtime in various ways.
Subscribe to a Channel
In this example we are subscribing to all updates related to our account by using the account channel. This will be triggered by any update related to the authenticated user, like updating the user's name or e-mail address.
-
Web
const sdk = new Appwrite(); sdk.subscribe('account', response => { // Callback will be executed on all account events. console.log(response); });
-
Flutter
final client = Client(); final realtime = Realtime(client); final subscription = realtime.subscribe(['account']); subscription.stream.listen((response) { // Callback will be executed on all account events. print(response); })
-
Android
val client = Client(context) val realtime = Realtime(client) realtime.subscribe("account", callback = { param -> // Callback will be executed on all account events. print(param.toString()) })
-
Apple
let client = Client() let realtime = Realtime(client) realtime.subscribe(channel: "account", callback: { param in // Callback will be executed on all account events. print(String(describing: param)) })
Subscribe to Multiple Channels
You can also listen to multiple channels at once by passing an array of channels. This will trigger the callback for any events for all channels passed.
In this example we are listening to the document A and all files by subscribing to the collections.A.documents.A and files channels.
-
Web
const sdk = new Appwrite(); sdk.subscribe(['collections.A.documents.A', 'files'], response => { // Callback will be executed on changes for documents A and all files. console.log(response); });
-
Flutter
final client = Client(); final realtime = Realtime(client); final subscription = realtime.subscribe(['collections.A.documents.A', 'files']); subscription.stream.listen((response) { // Callback will be executed on changes for documents A and all files. print(response); })
-
Android
val client = Client(context) val realtime = Realtime(client) realtime.subscribe("collections.A.documents.A", "files", callback = { param -> // Callback will be executed on changes for documents A and all files. print(param.toString()) })
-
Apple
let client = Client() let realtime = Realtime(client) realtime.subscribe(channels: ["collections.A.documents.A", "files"], callback: { param in // Callback will be executed on changes for documents A and all files. print(String(describing: param)) })
Unsubscribe
If you no longer want to receive updates from a subscription, you can unsubscribe so that your callbacks are no longer called.
-
Web
const sdk = new Appwrite(); const unsubscribe = sdk.subscribe('files', response => { // Callback will be executed on changes for all files. console.log(response); }); // Closes the subscription. unsubscribe();
-
Flutter
final client = Client(); final realtime = Realtime(client); final subscription = realtime.subscribe(['files']); subscription.stream.listen((response) { // Callback will be executed on changes for all files. print(response); }) // Closes the subscription. subscription.close();
-
Android
val client = Client(context) val realtime = Realtime(client) val subscription = realtime.subscribe("files", callback = { param -> // Callback will be executed on changes for all files. print(param.toString()) }) // Closes the subscription. subscription.close()
-
Apple
let client = Client() let realtime = Realtime(client) let subscription = realtime.subscribe(channel: "files", callback: { param in // Callback will be executed on changes for all files. print(param.toString()) }) // Closes the subscription. subscription.close()
Payload
The payload from the subscription will contain following properties:
Name | Type | Description |
event | string | The system event that triggered this update. |
channels | string[] | An array of channels that can receive this message. |
timestamp | integer | The UNIX timestamp from the server to ensure consistency across all client platforms and real-time technologies. |
payload | object | Payload contains the data equal to the response model. |
If you subscribe to the documents channel and a document the user is allowed to read is updated, you will receive an object containing information about the event and the updated document.
The response will look like this:
{
"event": "database.documents.update",
"channels": [
"documents",
"documents.[DOCUMENT_ID]",
"collections.[COLLECTION_ID].documents"
],
"timestamp": 1629719169,
"payload": {
"$id": "[DOCUMENT_ID]",
"$collection": "[COLLECTION_ID]",
"$permissions": [],
"attribute1": "lorem",
"attribute2": 2030
}
}
Channels
A list of all channels available you can subscribe to:
Channel | Description |
account | All account related events (session create, name update...) |
collections.[ID].documents | Any create/update/delete events to any document in a collection |
documents | Any create/update/delete events to any document |
collections.[ID].documents.[ID] | Any update/delete events to a given document |
files | Any create/update/delete events to any file |
buckets.[ID].files.[ID] | Any update/delete events to a given file of the given bucket |
buckets.[ID].files | Any update/delete events to any file of the given bucket |
teams | Any create/update/delete events to a any team |
teams.[ID] | Any update/delete events to a given team |
memberships | Any create/update/delete events to a any membership |
memberships.[ID] | Any update/delete events to a given membership |
executions | Any update to executions |
executions.[ID] | Any update to a given execution |
functions.[ID] | Any execution event to a given function |
Custom Endpoint
The SDK will guess the endpoint of the Realtime API when setting the endpoint of your Appwrite instance. If you are running Appwrite with a custom proxy and changed the route of the Realtime API, you can call the setEndpointRealtime method on the Client SDK and set your new endpoint value.
By default the endpoint is wss://[HOSTNAME_OR_IP]/v1/realtime.
-
Web
const sdk = new Appwrite(); sdk.setEndpointRealtime('[HOSTNAME_OR_IP]');
-
Flutter
final client = Client(); client.setEndpointRealtime('[HOSTNAME_OR_IP]');
-
Android
val client = Client(context) client.setEndpointRealtime("[HOSTNAME_OR_IP]")
-
Apple
let client = Client() client.setEndpointRealtime("[HOSTNAME_OR_IP]")
Known Limitations
Authentication with Existing Subscription
If you authenticate a user and have an already existing subscription, the subscription will not receive updates for the newly authenticated user. You would need to re-create the subscription so that it will work with the new user.
Rapid Subscriptions Changes
The SDK creates a single WebSocket connection for all subscribed channels. Each time a channel is added or unsubscribed - the SDK currently creates a completely new connection and terminates the old one. Therefore, subscriptions to channels should always be done in conjunction with state management so as not to be unnecessarily built up several times by multiple components' life cycles.
Nested Documents
Nested Documents will not trigger events related to their parent documents. Meaning, updates to a child document - will not trigger an event for the parent document. But it will trigger an event for the child document itself.
Server-Side?
We currently are not offering access to realtime with Server SDKs and an API key.