> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-platform-docs-release.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# User Experience Extensions

> Android SDK implementation examples for User Experience extensions including Bitly, Link Preview, Message Shortcuts, Pin Message, Rich Media Preview, Save Message, Thumbnail Generation, TinyURL, and Voice Transcription

This page contains Android SDK code examples for User Experience extensions. For feature documentation, setup instructions, and extension settings, see [User Experience Extensions](/fundamentals/extensions-user-experience).

## How to Use Extensions with SDK

<Steps>
  <Step title="Enable in Dashboard">
    Login to [CometChat Dashboard](https://app.cometchat.com/login), select your app, then go to **Chat & Messaging → Features** and enable the extension.
  </Step>

  <Step title="Configure settings (if required)">
    Some extensions require API keys or additional configuration. Open the extension settings in the Dashboard.
  </Step>

  <Step title="Implement SDK methods">
    Use the code examples below to call extension APIs and extract extension data from messages.
  </Step>

  <Step title="Build your UI">
    Create UI components to display extension data (e.g., link previews, pinned messages, saved messages).
  </Step>
</Steps>

***

## Bitly

Shorten long URLs in messages using Bitly.

### Shorten URL

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val url = "/v1/shorten"
    val body = JSONObject()
    body.put("text", "Your message with URL https://yourdomain.com/very/very/long/url")

    CometChat.callExtension("url-shortener-bitly", "POST", url, body,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(jsonObject: JSONObject) {
                // minifiedText from the extension
            }
            override fun onError(e: CometChatException) {
                // Some error occurred
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    String URL = "/v1/shorten";
    JSONObject body = new JSONObject();
    body.put("text", "Your message with URL https://yourdomain.com/very/very/long/url");

    CometChat.callExtension("url-shortener-bitly", "POST", URL, body,
    new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject jsonObject) {
            // minifiedText from the extension
        }
        @Override
        public void onError(CometChatException e) {
            // Some error occured
        }
    });
    ```
  </Tab>
</Tabs>

***

## Link Preview

Extract link preview metadata from messages.

### Extract Link Preview Data

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val metadata = message.metadata
    if (metadata != null) {
        val injectedObject = metadata.getJSONObject("@injected")
        if (injectedObject != null && injectedObject.has("extensions")) {
            val extensionsObject = injectedObject.getJSONObject("extensions")
            if (extensionsObject != null && extensionsObject.has("link-preview")) {
                val linkObject = extensionsObject.getJSONObject("link-preview")
                val linkArray = linkObject.getJSONArray("links")
                val linkPreviewObject = linkArray.getJSONObject(0)
                if (linkPreviewObject.has("description")) {
                    val description = linkPreviewObject.getString("description")
                }
                // ... other fields
            }
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject metadata = message.getMetadata();
    if (metadata != null) {
      JSONObject injectedObject = metadata.getJSONObject("@injected");
      if (injectedObject != null && injectedObject.has("extensions")) {
        JSONObject extensionsObject = injectedObject.getJSONObject("extensions");
        if (extensionsObject != null && extensionsObject.has("link-preview")){
          JSONObject linkObject = extensionsObject.getJSONObject("link-preview");
          JSONArray linkArray = linkObject.getJSONArray("links");
          JSONObject linkPreviewObject = linkArray.getJSONObject(0);
          if (linkPreviewObject.has("description"))
            String description = linkPreviewObject.getString("description");
          // ... other fields
        }
      }
    }
    ```
  </Tab>
</Tabs>

***

## Message Shortcuts

Send predefined messages using shortcuts (e.g., `!hb` expands to "Happy birthday!").

### Fetch All Shortcuts

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.callExtension("message-shortcuts", "GET", "/v1/fetch", null,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(responseObject: JSONObject) {
                // Shortcuts received here.
            }
            override fun onError(e: CometChatException) {
                // Some error occurred.
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    CometChat.callExtension("message-shortcuts", "GET", "/v1/fetch", null,
        new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject responseObject) {
            // Shortcuts received here.
        }
        @Override
        public void onError(CometChatException e) {
            // Some error occured.
        }
    });
    ```
  </Tab>
</Tabs>

### Modify Shortcuts

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val body = JSONObject()
    val shortcuts = JSONObject()
    shortcuts.put("!hbd", "Happy birthday! Have fun!")
    body.put("shortcuts", shortcuts)

    CometChat.callExtension("message-shortcuts", "POST", "/v1/update", body,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(responseObject: JSONObject) {
                // Shortcuts updated successfully
            }
            override fun onError(e: CometChatException) {
                // Some error occurred
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject body = new JSONObject();
    JSONObject shortcuts = new JSONObject();
    shortcuts.put("!hbd", "Happy birthday! Have fun!");
    body.put("shortcuts", shortcuts);

    CometChat.callExtension("message-shortcuts", "POST", "/v1/update", body,
        new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject responseObject) {
            // Shortcuts updated successfully
        }
        @Override
        public void onError(CometChatException e) {
            // Some error occured
        }
    });
    ```
  </Tab>
</Tabs>

***

## Pin Message

Pin important messages in conversations.

### Pin a Message

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val body = JSONObject()
    body.put("msgId", 280)

    CometChat.callExtension("pin-message", "POST", "/v1/pin", body,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(responseObject: JSONObject) {
                // { success: true }
            }
            override fun onError(e: CometChatException) {
                // Error occurred
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject body = new JSONObject();
    body.put("msgId", 280);

    CometChat.callExtension("pin-message", "POST", "/v1/pin", body,
        new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject responseObject) {
            // { success: true }
        }
        @Override
        public void onError(CometChatException e) {
            // Error occurred
        }
    });
    ```
  </Tab>
</Tabs>

### Unpin a Message

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val body = JSONObject()
    body.put("msgId", 111)
    body.put("receiverType", "group")
    body.put("receiver", "cometchat-guid-1")

    CometChat.callExtension("pin-message", "DELETE", "/v1/unpin", body,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(responseObject: JSONObject) {
                // { success: true }
            }
            override fun onError(e: CometChatException) {
                // Error occurred
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject body = new JSONObject();
    body.put("msgId", 111);
    body.put("receiverType", "group");
    body.put("receiver", "cometchat-guid-1");

    CometChat.callExtension("pin-message", "DELETE", "/v1/unpin", body,
        new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject responseObject) {
            // { success: true }
        }
        @Override
        public void onError(CometChatException e) {
            // Error occurred
        }
    });
    ```
  </Tab>
</Tabs>

### Fetch Pinned Messages

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val receiverType = "group"
    val receiver = "cometchat-guid-1"
    val url = "/v1/fetch?receiverType=$receiverType&receiver=$receiver"

    CometChat.callExtension("pin-message", "GET", url, null,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(responseObject: JSONObject) {
                // { pinnedMessages: [] }
            }
            override fun onError(e: CometChatException) {
                // Error occurred
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    String receiverType = "group";
    String receiver = "cometchat-guid-1";
    String URL = "/v1/fetch?receiverType=" + receiverType + "&receiver=" + receiver;

    CometChat.callExtension("pin-message", "GET", URL, null,
        new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject responseObject) {
            // { pinnedMessages: [] }
        }
        @Override
        public void onError(CometChatException e) {
            // Error occurred
        }
    });
    ```
  </Tab>
</Tabs>

***

## Rich Media Preview

Extract rich media preview metadata from messages using Iframely.

### Extract Rich Media Data

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val metadata = message.metadata
    if (metadata != null) {
        val injectedObject = metadata.getJSONObject("@injected")
        if (injectedObject != null && injectedObject.has("extensions")) {
            val extensionsObject = injectedObject.getJSONObject("extensions")
            if (extensionsObject != null && extensionsObject.has("rich-media")) {
                val richMediaObject = extensionsObject.getJSONObject("rich-media")
                // Use richMediaObject data
            }
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject metadata = message.getMetadata();
    if (metadata != null) {
        JSONObject injectedObject = metadata.getJSONObject("@injected");
        if (injectedObject != null && injectedObject.has("extensions")) {
            JSONObject extensionsObject = injectedObject.getJSONObject("extensions");
            if (extensionsObject != null && extensionsObject.has("rich-media")) {
                JSONObject richMediaObject = extensionsObject.getJSONObject("rich-media");
                // Use richMediaObject data
            }
        }
    }
    ```
  </Tab>
</Tabs>

***

## Save Message

Save important messages for later access.

### Save a Message

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val body = JSONObject()
    body.put("msgId", 111)

    CometChat.callExtension("save-message", "POST", "/v1/save", body,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(responseObject: JSONObject) {
                // { success: true }
            }
            override fun onError(e: CometChatException) {
                // Error occurred
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject body = new JSONObject();
    body.put("msgId", 111);

    CometChat.callExtension("save-message", "POST", "/v1/save", body,
        new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject responseObject) {
            // { success: true }
        }
        @Override
        public void onError(CometChatException e) {
            // Error occurred
        }
    });
    ```
  </Tab>
</Tabs>

### Unsave a Message

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val body = JSONObject()
    body.put("msgId", 111)

    CometChat.callExtension("save-message", "DELETE", "/v1/unsave", body,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(responseObject: JSONObject) {
                // { success: true }
            }
            override fun onError(e: CometChatException) {
                // Error occurred
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject body = new JSONObject();
    body.put("msgId", 111);

    CometChat.callExtension("save-message", "DELETE", "/v1/unsave", body,
        new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject responseObject) {
            // { success: true }
        }
        @Override
        public void onError(CometChatException e) {
            // Error occurred
        }
    });
    ```
  </Tab>
</Tabs>

### Fetch Saved Messages

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.callExtension("save-message", "GET", "/v1/fetch", null,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(responseObject: JSONObject) {
                // { savedMessages: [] }
            }
            override fun onError(e: CometChatException) {
                // Error occurred
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    CometChat.callExtension("save-message", "GET", "/v1/fetch", null,
        new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject responseObject) {
            // { savedMessages: [] }
        }
        @Override
        public void onError(CometChatException e) {
            // Error occurred
        }
    });
    ```
  </Tab>
</Tabs>

***

## Thumbnail Generation

Extract thumbnail URLs from image and video messages.

### Extract Thumbnail Data

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val metadata = message.metadata
    if (metadata != null) {
        val injectedObject = metadata.getJSONObject("@injected")
        if (injectedObject != null && injectedObject.has("extensions")) {
            val extensionsObject = injectedObject.getJSONObject("extensions")
            if (extensionsObject != null && extensionsObject.has("thumbnail-generation")) {
                val thumbnailObject = extensionsObject.getJSONObject("thumbnail-generation")
                val attachments = thumbnailObject.getJSONArray("attachments")
                for (i in 0 until attachments.length()) {
                    val attachment = attachments.getJSONObject(i)
                    if (!attachment.has("error")) {
                        val data = attachment.getJSONObject("data")
                        val thumbnails = data.getJSONObject("thumbnails")
                        val urlSmall = thumbnails.getString("url_small")
                        val urlMedium = thumbnails.getString("url_medium")
                        val urlLarge = thumbnails.getString("url_large")
                        // Use the URLs accordingly
                    }
                }
            }
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject metadata = message.getMetadata();
    if (metadata != null) {
        JSONObject injectedObject = metadata.getJSONObject("@injected");
        if (injectedObject != null && injectedObject.has("extensions")) {
            JSONObject extensionsObject = injectedObject.getJSONObject("extensions");
            if (extensionsObject != null && extensionsObject.has("thumbnail-generation")) {
                JSONObject thumbnailObject = extensionsObject.getJSONObject("thumbnail-generation");
                JSONArray attachments = thumbnailObject.getJSONArray("attachments");
                for (int i = 0; i < attachments.length(); i++) {
                    JSONObject attachment = attachments.getJSONObject(i);
                    if (!attachment.has("error")) {
                        JSONObject data = attachment.getJSONObject("data");
                        JSONObject thumbnails = data.getJSONObject("thumbnails");
                        String urlSmall = thumbnails.getString("url_small");
                        String urlMedium = thumbnails.getString("url_medium");
                        String urlLarge = thumbnails.getString("url_large");
                        // Use the URLs accordingly
                    }
                }
            }
        }
    }
    ```
  </Tab>
</Tabs>

***

## TinyURL

Shorten long URLs in messages using TinyURL.

### Shorten URL

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val body = JSONObject()
    body.put("text", "Your message with URL https://yourdomain.com/very/very/long/url")

    CometChat.callExtension("url-shortener-tinyurl", "POST", "/v1/shorten", body,
        object : CometChat.CallbackListener<JSONObject>() {
            override fun onSuccess(jsonObject: JSONObject) {
                // minifiedText from the extension
            }
            override fun onError(e: CometChatException) {
                // Some error occurred
            }
        }
    )
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject body = new JSONObject();
    body.put("text", "Your message with URL https://yourdomain.com/very/very/long/url");

    CometChat.callExtension("url-shortener-tinyurl", "POST", "/v1/shorten", body,
        new CometChat.CallbackListener<JSONObject>() {
        @Override
        public void onSuccess(JSONObject jsonObject) {
            // minifiedText from the extension
        }
        @Override
        public void onError(CometChatException e) {
            // Some error occured
        }
    });
    ```
  </Tab>
</Tabs>

***

## Voice Transcription

Extract transcribed text from audio messages.

### Extract Transcription Data

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val metadata = message.metadata
    if (metadata != null) {
        val injectedObject = metadata.getJSONObject("@injected")
        if (injectedObject != null && injectedObject.has("extensions")) {
            val extensionsObject = injectedObject.getJSONObject("extensions")
            if (extensionsObject != null && extensionsObject.has("voice-transcription")) {
                val voiceTranscriptionObject = extensionsObject.getJSONObject("voice-transcription")
                val transcribedMessage = voiceTranscriptionObject.getString("transcribed_message")
                // Use the transcribed message
            }
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    JSONObject metadata = message.getMetadata();
    if (metadata != null) {
        JSONObject injectedObject = metadata.getJSONObject("@injected");
        if (injectedObject != null && injectedObject.has("extensions")) {
            JSONObject extensionsObject = injectedObject.getJSONObject("extensions");
            if (extensionsObject != null && extensionsObject.has("voice-transcription")) {
                JSONObject voiceTranscriptionObject = extensionsObject.getJSONObject("voice-transcription");
                String transcribedMessage = voiceTranscriptionObject.getString("transcribed_message");
                // Use the transcribed message
            }
        }
    }
    ```
  </Tab>
</Tabs>
