---
source_url: https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/channels/typing-indicator
title: Typing indicator
updated_at: 2026-06-16T12:48:52.950Z
---

> 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


# Typing indicator

Typing indicators show users when someone is composing a message. This feature:

* **Increases engagement** - Users see activity in group chats
* **Sets expectations** - Users know when to expect a response in 1:1 conversations

:::warning Not available for public chats
Typing indicator is disabled in [public chats](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/channels/create#create-public-channel). If you try implementing this feature in a public channel type, you'll get the `Typing indicators are not supported in Public chats` error.
:::

## Start typing

`startTyping()` activates the typing indicator on a channel.

The method uses a debounce mechanism: signals are sent at intervals rather than on every keystroke. The [default timeout](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/configuration#input-parameters) is 5000 ms (5 seconds), with a 1000 ms buffer to prevent rapid re-triggering.

:::tip Custom timeout
Set a custom timeout with the [typingTimeout parameter](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/configuration#typing-indicator-timeout) during initialization.
:::

### Method signature

This method has the following signature:

```swift
channel.startTyping() async throws -> Timetoken?
```

#### Input

This method doesn't take any parameters.

#### Output

| Parameter | Description |
| --- | --- |
| `Timetoken?` | A `Timetoken` value indicating the action timestamp, or `nil` if no signal was sent (e.g., a typing indicator was already active). |

### 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.
:::

Start a typing indicator on the `support` channel.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    try await channel.startTyping()
  } else {
    debugPrint("Channel not found")
  }
}
```

## Stop typing

`stopTyping()` deactivates a typing indicator on a given channel.

Use this method to disable the typing indicator immediately - for example, when a user deletes a previously drafted message - without waiting for the [typingTimeout](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/channels/typing-indicator#start-typing) to end.

### Method signature

This method has the following signature:

```swift
channel.stopTyping() async throws -> Timetoken?
```

#### Input

This method doesn't take any parameters.

#### Output

| Parameter | Description |
| --- | --- |
| `Timetoken?` | A `Timetoken` value indicating the action timestamp, or `nil` if no signal was sent (e.g., no typing indicator was active). |

### 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.
:::

Stop a typing indicator on the `support` channel.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    try await channel.stopTyping()
  } else {
    debugPrint("Channel not found")
  }
}
```

## Get typing events

`onTypingChanged()` listens for [typing signal events](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/custom-events#events-for-typing-indicator) on a channel via a closure. You can also use `channel.stream.typingChanges()` for an `AsyncStream`-based approach.

### Method signature

```swift
channel.onTypingChanged(
    callback: @escaping ([String]) -> Void
) -> AutoCloseable
```

#### Input

| Parameter | Description |
| --- | --- |
| `callback` *Type: `([String]) -> Void`Default: n/a | Closure called with an array of user IDs currently typing whenever someone starts or stops typing. |

#### 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.
:::

###### Closure

```swift
// Assumes a "ChannelImpl" reference named "channel"

// Important: Keep a strong reference to the returned "AutoCloseable" object as long as you want
// to receive 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 = channel.getTyping { typingUsers in
  debugPrint("Typing users: \(typingUsers)")
}
```

###### AsyncStream

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    for await typingUsers in channel.getTyping() {
      debugPrint("Typing users: \(typingUsers)")
    }
  } else {
    debugPrint("Channel not found")
  }
}
```