---
source_url: https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/users/updates
title: Manage user updates
updated_at: 2026-06-16T12:48:55.867Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Manage user updates

Update user details and receive real-time update events.

:::note Requires App Context
Enable [App Context](https://youtu.be/9UEoSlngpYI) in the [Admin Portal](https://admin.pubnub.com/) to store user data.
:::

## Update user details

Edit user metadata with `update()` or `updateUser()`.

* `update()` - call on a `User` object (no ID needed)
* `updateUser()` - call on a `Chat` object (requires user ID)

### Method signature

These methods take the following parameters:

* update() 1user.update(2 name: String? = nil,3 externalId: String? = nil,4 profileUrl: String? = nil,5 email: String? = nil,6 custom: [String: JSONCodableScalar]? = nil,7 status: String? = nil,8 type: String? = nil9) async throws -> UserImpl
* updateUser() 1chat.updateUser(2 id: String,3 name: String? = nil,4 externalId: String? = nil,5 profileUrl: String? = nil,6 email: String? = nil,7 custom: [String: JSONCodableScalar]? = nil,8 status: String? = nil,9 type: String? = nil10) async throws -> UserImpl

#### Input

| Parameter | Required in update() | Required in updateUser() | Description |
| --- | --- | --- | --- |
| id | String | Optional |  | No | Yes | [Unique user identifier](https://www.pubnub.com/docs/general/setup/users-and-devices#user-id-usage). |
| name | String | Optional |  | No | No | Display name for the user (must not be empty or consist only of whitespace characters). |
| externalId | String | Optional |  | No | No | User's identifier in an external system. You can use it to match `id` with a similar identifier from an external database. |
| profileUrl | String | Optional |  | No | No | URL of the user's profile picture. |
| email | String | Optional |  | No | No | User's email address. |
| custom | [String: | Optional |  | No | No | JSON providing custom data about the user. Values must be scalar only; arrays or objects are not supported. [Filtering App Context data](https://www.pubnub.com/docs/general/metadata/filtering) through the `custom` property is not recommended in SDKs. |
| status | String | Optional |  | No | No | Tag that lets you categorize your app users by their current state. The tag choice is entirely up to you and depends on your use case. For example, you can use `status` to mark users in your chat app as `invited`, `active`, or `archived`. |
| type | String | Optional |  | No | No | Tag that lets you categorize your app users by their functional roles. The tag choice is entirely up to you and depends on your use case. For example, you can use `type` to group users by their roles in your app, such as `moderator`, `player`, or `support-agent`. |

:::tip API limits
To learn about the maximum length of parameters used to set user metadata, refer to [REST API docs](https://www.pubnub.com/docs/sdks/rest-api/set-user-metadata).
:::

#### Output

| Parameter | Description |
| --- | --- |
| `UserImpl` | Returned object containing the updated user metadata. |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Change the link to the user's `support_agent_15` LinkedIn profile to `https://www.linkedin.com/mkelly_vp2`.

* update() // Assumes a "ChatImpl" reference named "chat" Task { if let user = try await chat.getUser(userId: "support_agent_15") { let updatedUser = try await user.update(profileUrl: "https://www.linkedin.com/mkelly_vp2") debugPrint("User profile updated on User object: \(updatedUser)") } else { debugPrint("User not found") } }
* updateUser() // Assumes a "ChatImpl" reference named "chat" Task { let updatedUser = try await chat.updateUser( id: "support_agent_15", profileUrl: "https://www.linkedin.com/mkelly_vp2" ) debugPrint("Updated user object: \(updatedUser)") }

## Get user updates

Receive real-time updates when a [User object](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/user) is edited with `onUpdated()`, or be notified when it is deleted with `onDeleted()`.

You can also use `user.stream.updates()` and `user.stream.deletions()` for `AsyncStream`-based equivalents.

For monitoring multiple users at once, `streamUpdatesOn()` remains available.

:::note Deprecation
`streamUpdates()` is deprecated. Use `onUpdated()` and `onDeleted()` (closure-based) or `user.stream.updates()` and `user.stream.deletions()` (AsyncStream-based) instead.
:::

### Method signature

* onUpdated() — closure called when the user metadata changes 1user.onUpdated(2 callback: @escaping (UserImpl) -> Void3) -> AutoCloseable
* onDeleted() — closure called when the user is deleted 1user.onDeleted(2 callback: @escaping () -> Void3) -> AutoCloseable
* streamUpdatesOn() (static) — monitors multiple users 1UserImpl.streamUpdatesOn(users: [UserImpl]) -> AsyncStream<[UserImpl]>

#### Input

| Parameter | Description |
| --- | --- |
| `callback` (in `onUpdated`) *Type: `(UserImpl) -> Void`Default: n/a | Closure called with the updated user whenever its metadata changes. |
| `callback` (in `onDeleted`) *Type: `() -> Void`Default: n/a | Closure called when the user is deleted. |
| `users` (in `streamUpdatesOn`) *Type: `[UserImpl]`Default: n/a | A collection of [UserImpl objects](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/user) for which you want to get updates. |

#### Output

| Parameter | Description |
| --- | --- |
| `AutoCloseable` | An object you must retain. When released or closed, the listener stops. |

### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Get updates on `support_agent_15`.

###### Closure

```swift
// Assumes a "UserImpl" reference named "support_agent_15" representing previously fetched user object with the `support_agent_15` identifier
  
// Important: Keep a strong reference to the returned "AutoCloseable" object as long as you want
// to receive new updates. If the "AutoCloseable" is deallocated, the stream will be cancelled,
// and no further items will be produced. You can also stop receiving updates manually
// by calling the "close()" method on the "AutoCloseable" object.
autoCloseable = support_agent_15.streamUpdates { updatedUser in
  // The closure receives the entire updated User object each time a change occurs.
  if let updatedUser = updatedUser {
    debugPrint("User updated: \(updatedUser)")
  } else {
    debugPrint("User was deleted")
  }
}
```

###### AsyncStream

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let user = try await chat.getUser(userId: "support_agent_15") {
    for await updatedUser in user.streamUpdates() {
      // The stream returns the entire updated User object each time a change occurs.
      if let updatedUser = updatedUser {
        debugPrint("Updated user object: \(updatedUser)")
      } else {
        debugPrint("User was deleted")
      }
    }
  } else {
    debugPrint("User not found")
  }
}
```

#### Watch multiple users

Get updates on multiple user objects at once.

##### Closure

```swift
// Assumes a "ChatImpl" reference named "chat"
// Assumes "UserImpl" references named "support_agent_15" and "support_manager"
  
// Important: Keep a strong reference to the returned "AutoCloseable" object as long as you want
// to receive new updates. If the "AutoCloseable" is deallocated, the stream will be cancelled,
// and no further items will be produced. You can also stop receiving updates manually
// by calling the "close()" method on the "AutoCloseable" object.
autoCloseable = UserImpl.streamUpdatesOn(users: [support_agent_15, support_manager]) { updatedUsers in
  // The closure receives the complete list of all users you're monitoring
  // each time any change occurs.
  debugPrint("Users updated: \(updatedUsers.map { $0.id })")
}
```

##### AsyncStream

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let firstUser = try await chat.getUser(userId: "support_agent_15"), let secondUser = try await chat.getUser(userId: "support_manager") {
    for await updatedUsers in UserImpl.streamUpdatesOn(users: [firstUser, secondUser]) {
      // The stream returns the complete list of all users you're monitoring
      // each time any change occurs.
      debugPrint("Updated users: \(String(describing: updatedUsers))")
    }
  } else {
    debugPrint("User not found")
  }
}
```