# Extra Data

Extra Data is additional information that can be added to the default data of Stream. It is a dictionary of key-value pairs that can be attached to messages, users, channels, and most domain models in the SDK.

On Android, Extra Data is represented as `Map<String, Any>`. This allows you to store strings, numbers, booleans, lists, and nested maps.

## Adding Extra Data

You can add extra data when creating or updating messages, users, channels, and other models.

### Messages

Add extra data when creating a message:

```kotlin
val message: Message = Message(
    cid = "messaging:general",
    text = "Check out this product!",
    extraData = mapOf(
        "priority" to "high",
        "product_id" to "12345",
        "price" to 29.99,
    ),
)

channelClient.sendMessage(message).enqueue { result ->
    when (result) {
        is Result.Success -> { /* Message sent */ }
        is Result.Failure -> { /* Handle error */ }
    }
}
```

### Users

Add extra data when updating the current user:

```kotlin
val user: User = User(
    id = "user-id",
    name = "John Doe",
    extraData = mapOf(
        "email" to "john.doe@example.com",
        "phone" to "+1234567890",
        "preferences" to mapOf(
            "notifications" to true,
            "theme" to "dark",
        ),
    ),
)

chatClient.updateUser(user).enqueue { result ->
    when (result) {
        is Result.Success -> { /* User updated */ }
        is Result.Failure -> { /* Handle error */ }
    }
}
```

### Channels

Add extra data when creating a channel:

```kotlin
chatClient.createChannel(
    channelType = "messaging",
    channelId = "travel-group",
    memberIds = listOf("user-1", "user-2"),
    extraData = mapOf(
        "name" to "Travel Planning",
        "destination" to "Paris",
        "trip_date" to "2026-06-15",
    ),
).enqueue { result ->
    when (result) {
        is Result.Success -> { /* Channel created */ }
        is Result.Failure -> { /* Handle error */ }
    }
}
```

## Reading Extra Data

All domain models have an `extraData` property of type `Map<String, Any>`. You need to cast values to the expected type when reading:

```kotlin
// Reading simple values
val email: String? = user.extraData["email"] as? String
val priority: String? = message.extraData["priority"] as? String
val price: Double? = message.extraData["price"] as? Double
val productId: String? = message.extraData["product_id"] as? String

// Reading nested maps
val preferences: Map<String, Any>? = user.extraData["preferences"] as? Map<String, Any>
val theme: String? = preferences?.get("theme") as? String
val notificationsEnabled: Boolean? = preferences?.get("notifications") as? Boolean
```

## Type-Safe Extensions

For cleaner code, create extension properties on the models you use:

```kotlin
val User.email: String?
    get() = extraData["email"] as? String

val User.phone: String?
    get() = extraData["phone"] as? String

val Message.priority: String?
    get() = extraData["priority"] as? String

val Message.productId: String?
    get() = extraData["product_id"] as? String

val Channel.destination: String?
    get() = extraData["destination"] as? String
```

Then use them directly:

```kotlin
// Clean access via extensions
val email: String = user.email ?: ""
val priority: String = message.priority ?: "normal"
val destination: String = channel.destination ?: "Unknown"
```

## Advanced Example

For complex data structures, create data classes with conversion functions:

```kotlin
data class BookingInfo(
    val flightNumber: String,
    val departureDate: String,
    val price: Double,
    val passengers: List<Passenger>,
)

data class Passenger(
    val name: String,
    val age: Int,
)

// Convert to extraData map
fun BookingInfo.toExtraData(): Map<String, Any> = mapOf(
    "flight_number" to flightNumber,
    "departure_date" to departureDate,
    "price" to price,
    "passengers" to passengers.map { passenger ->
        mapOf(
            "name" to passenger.name,
            "age" to passenger.age,
        )
    },
)

// Parse from extraData map
fun Map<String, Any>.toBookingInfo(): BookingInfo? {
    val flightNumber: String = this["flight_number"] as? String ?: return null
    val departureDate: String = this["departure_date"] as? String ?: return null
    val price: Double = this["price"] as? Double ?: return null
    val passengersData: List<Map<String, Any>> =
        (this["passengers"] as? List<*>)?.filterIsInstance<Map<String, Any>>() ?: emptyList()

    val passengers: List<Passenger> = passengersData.mapNotNull { data ->
        val name: String = data["name"] as? String ?: return@mapNotNull null
        val age: Int = (data["age"] as? Number)?.toInt() ?: return@mapNotNull null
        Passenger(name, age)
    }

    return BookingInfo(flightNumber, departureDate, price, passengers)
}
```

Then extend the Message model:

```kotlin
val Message.bookingInfo: BookingInfo?
    get() = (extraData["booking"] as? Map<String, Any>)?.toBookingInfo()
```

Use it when sending and reading messages:

```kotlin
// Sending a message with booking info
val booking = BookingInfo(
    flightNumber = "AB123",
    departureDate = "2026-06-15",
    price = 450.00,
    passengers = listOf(
        Passenger("John Doe", 30),
        Passenger("Jane Doe", 28),
    ),
)

val message: Message = Message(
    cid = "messaging:travel",
    text = "Here are our flight details!",
    extraData = mapOf("booking" to booking.toExtraData()),
)

// Reading booking info from a message
val bookingInfo: BookingInfo? = message.bookingInfo
bookingInfo?.let {
    println("Flight: ${it.flightNumber}")
    println("Passengers: ${it.passengers.map { p -> p.name }}")
}
```


---

This page was last updated at 2026-04-21T07:55:26.900Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/android/v6/client/guides/extra-data/](https://getstream.io/chat/docs/sdk/android/v6/client/guides/extra-data/).