페이지 이동경로
  • Docs>
  • Kakao Story>
  • Android

Kakao Story

Android

This document describes how to integrate Kakao Story APIs into your service with the Kakao SDK for Android. (hereinafter referred to as 'Android SDK').

Tag used in this document
Tag Description
Login required The API marked with this tag requires Kakao Login. You must implement the Kakao Login function first, and then call the corresponding API by using the access token issued when a user logs in.
Consent required To use the API marked with this tag, you must enable a specific scope required for the corresponding API.
In addition, a user must also consent to the scope. Otherwise, an error occurs or empty value is returned. To check which scopes a user has consented to, you can call the Retrieving consent details API.

Before you begin

Register Android Platform

To use the Android SDK, you must register the Android platform in advance. Go to [My Application] > [Platform] and register the Android platform by specifying its package name and key hashes. If not, an error may occur.

Add modules

To use Kakao Story, you need to add the v2-story module that provides StoryApiClient for Kakao Story and the v2-user module for Kakao Login in the module-level build.gradle file. Refer to Add modules for more details.

Set Custom URL Scheme

To allow your app to launch the Kakao Story application, you must set a Custom URL Scheme in AndroidManifest.xml.

<activity 
    android:name=".${YOUR_ACTIVITY_NAME}"
    android:exported="true">

    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        
        <!-- Set a scheme to launch the Kakao Story app in "kakao${YOUR_NATIVE_APP_KEY}://kakaolink" format. -->
        <data android:host="kakaostory"
                android:scheme="kakao${YOUR_NATIVE_APP_KEY}" />
    </intent-filter>
</activity>

Validate Kakao Story user Login required

To check if the user who is currently logged in is using Kakao Story, call the isStoryUser() method in the StoryApiClient class.

Sample
Kotlin
RxKotlin
// Checking if user is using Kakao Story 
StoryApiClient.instance.isStoryUser { isStoryUser, error ->
    if (error != null) {
        Log.e(TAG, "Failed to validate Kakao Story user registration.", error)
    }
    else {
        Log.i(TAG, "Whether to use Kakao Story: $isStoryUser")
    }
}
var disposables = CompositeDisposable()

// Checking if user is using Kakao Story 
StoryApiClient.rx.isStoryUser()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ isStoryUser ->
        Log.i(TAG, "Whether to use Kakao Story: $isStoryUser")
    }, { error ->
        Log.e(TAG, "Failed to validate Kakao Story user registration.", error)
    })
    .addTo(disposables)
Return data

If true is returned, the user is using Kakao Story. If the user is not using Kakao Story, false is returned so that you can take action to prevent an error that occurs when calling Kakao Story APIs for the user.

Users can set their desired profile nicknames and images for Kakao Story, Kakao Talk, and Kakao Account respectively. Thus, profile information retrieved through this API is different from the ones obtained through the Retrieving user information or Retrieving Kakao Talk profile API.

Retrieve Kakao Story profile Login required Consent required

To retrieve the Kakao Story profile information of the user who is currently logged in, call the profile() method in the StoryApiClient class.

Sample
Kotlin
RxKotlin
// Retrieving Kakao Story profile
StoryApiClient.instance.profile { profile, error ->
    if (error != null) {
        Log.e(TAG, "Failed to retrieve Kakao Story profile.", error)
    }
    else if (profile != null) {
        Log.i(TAG, "Succeeded in retrieving Kakao Story profile." +
                "\nNickname: ${profile.nickname}" +
                "\nProfile Image: ${profile.thumbnailUrl}" +
                "\nBirthday: ${profile.birthday}")
    }
}
var disposables = CompositeDisposable()

// Retrieving Kakao Story profile
StoryApiClient.rx.profile()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ profile ->
        Log.i(TAG, "Succeeded in retrieving Kakao Story profile." +
                "\nNickname: ${profile.nickname}" +
                "\nProfile Image: ${profile.thumbnailUrl}" +
                "\nBirthday: ${profile.birthday}")
    }, { error ->
        Log.e(TAG, "Failed to retrieve Kakao Story profile.", error)
    })
    .addTo(disposables)
Return data

profile() returns Kakao Story profile information through the StoryProfile object.

The profile information retrieved through this API may be different from the profiles obtained through the Retrieving user information API or Retrieving Kakao Talk profile API because users can set their profile nicknames and images respectively for Kakao Story, Kakao Talk, and Kakao Account.

StoryProfile
Name Type Description Required
nickname String Kakao Story nickname.

Required user consent: Profile Info(nickname/profile image) or Nickname
X
profileImageUrl String Kakao Story profile image URL.

Required user consent: Profile Info(nickname/profile image) or Profile image
X
thumbnailUrl String Kakao Story thumbnail profile image URL.

Required user consent: Profile Info(nickname/profile image) or Profile image
X
bgImageUrl String Kakao Story background image URL.

Required user consent: Profile Info(nickname/profile image) or Profile image
X
permalink String Kakao Story profile URL.

Required user consent: KakaoStory profile URL

NOTE: From June 1, 2021, only when a user consents to 'KakaoStory profile URL(story_permalink)', the Retrieving Kakao Story profile API returns 'permalink' in the response. For more details, see Notice.
X
birthday String Birthday registered in Kakao Story in MMdd format.

Required user consent: Birthday
X
birthdayType BirthdayType - SOLAR: Solar birthday.
- LUNAR: Lunar birthday.

Required user consent: Birthday
X

Post story Login required Consent required

To use this API,

  • You must enable the 'Publish posts in KakaoStory' scope in [My Application] > [Kakao Login] > [Consent items].
  • A user must consent to the scope. Otherwise, an error occurs.

To post a new story on Kakao Story of the user who is currently logged in, call one of the following methods depending on the story type — text, photo, or link. You also must pass arguments for the corresponding story type.

Story types

Type Description Method
Text Story with text only. postNote()
Photo Story with text and photos. postPhoto()
Link Story with text and the information obtained by scrapping a web page. postLink()

Posting text story

To post a text story without any photo or web page URL, call the postNote() method. You must also pass the content parameter that contains the text you want to input.

Parameter
Name Type Description Required
content String Text to be input in the story.
Up to 2048 characters are allowed.
O
permission Permission Audience for the story.
- PUBLIC: Open to all.
- FRIEND: Open to only friends.
- ONLY_ME: Open to only me (Private).
(Default: PUBLIC)
X
enableShare Boolean Whether to share the story when permission is set to FRIEND (Friends only).
(Default: false)
X
androidExecParam Map<String, String> Parameter to be added to the URL to execute an Android app when selecting the [View on app] button from Kakao Story. X
iosExecParam Map<String, String> Parameter to be added to the URL to execute an iOS app when selecting the [View on app] button from Kakao Story. X
androidMarketParam Map<String, String> Parameter to be added to the execution URL when redirecting to an open market from Kakao Story. X
iosMarketParam Map<String, String> Parameter to be added to the execution URL when redirecting to the App Store from Kakao Story. X
Sample
Kotlin
RxKotlin
// Posting text story
val content = "Posting note from Kakao SDK Sample."

StoryApiClient.instance.postNote(content) { storyPostResult, error ->
    if (error != null) {
        Log.e(TAG, "Failed to post a story.", error)
    }
    else if (storyPostResult != null) {
        Log.i(TAG, "Succeeded in posting a story. [${storyPostResult.id}]")
    }
}
var disposables = CompositeDisposable()

// Posting text story
val content = "Posting note from Kakao SDK Sample."

StoryApiClient.rx.postNote(content)
    .retryWhen(
        // Request additional consent for InsufficientScope.
        RxAuthOperations.instance.incrementalAuthorizationRequired(context)
    )
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ storyId ->
        Log.i(TAG, "Succeeded in posting a story. [${storyId}]")
    }, { error ->
        Log.e(TAG, "Failed to post a story.", error)
    })
    .addTo(disposables)

Posting photo story

To post a story with photos,

  1. To use the image files saved on a local device, you need to upload them to the Kakao server first. Call the upload() method by passing images with List<String> type to be posted in a story. upload() returns the list of the uploaded image URLs.
  2. Call the postPhoto() method by passing images that is obtained through upload().
Parameter
Name Type Description Required
images List<String> List of image URLs to be attached to a story. O
content String Text to be input in the story.
Up to 2048 characters are allowed.
X
permission Permission Audience for the story.
- PUBLIC: Open to all.
- FRIEND: Open to only friends.
- ONLY_ME: Open to only me (Private).
(Default: PUBLIC)
X
enableShare Boolean Whether to share the story when permission is set to FRIEND (Friends only).
(Default: false)
X
androidExecParam Map<String, String> Parameter to be added to the URL to execute an Android app when selecting the [View on app] button from Kakao Story. X
iosExecParam Map<String, String> Parameter to be added to the URL to execute an iOS app when selecting the [View on app] button from Kakao Story. X
androidMarketParam Map<String, String> Parameter to be added to the execution URL when redirecting to an open market from Kakao Story. X
iosMarketParam Map<String, String> Parameter to be added to the execution URL when redirecting to the App Store from Kakao Story. X
Sample

The following code snippet shows the algorithm for uploading images and posting a photo story with the uploaded images.

Kotlin
RxKotlin
// Posting photo story

// Image file to be uploaded
// This code snippet uses the image file added as a project resource. Use the imge files as your service needs.
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.sample1)
val file = File(context.cacheDir, "sample1.png")
val stream = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
stream.close()

// Uploading image
StoryApiClient.instance.upload(listOf(file)) { uploadedPaths, error ->
    if (error != null) {
        Log.e(TAG, "Failed to upload image.", error)
    } else {
        Log.d(TAG, "Succeeded in uploading image. $uploadedPaths")

        // Posting photo story
        val images = uploadedPaths!!
        val content = "Posting photo from Kakao SDK Sample."

        StoryApiClient.instance.postPhoto(images, content) { storyPostResult, error ->
            if (error != null) {
                Log.e(TAG, "Failed to post a story.", error)
            }
            else if (storyPostResult != null) {
                Log.i(TAG, "Succeeded in posting a story. [${storyPostResult.id}]")
            }
        }
    }
}
var disposables = CompositeDisposable()

// Posting photo story

// Image file to be uploaded
// This code snippet uses the image file added as a project resource. Use the imge files as your service needs.
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.sample1)
val file = File(context.cacheDir, "sample1.png")
val stream = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
stream.close()

// Uploading image
StoryApiClient.rx.upload(listOf(file))
    .flatMap {

        // Posting photo story
        val images = it
        val content = "Posting photo from Kakao SDK Sample."

        StoryApiClient.rx.postPhoto(images, content)
    }
    .retryWhen(
        // Request additional consent for InsufficientScope.
        RxAuthOperations.instance.incrementalAuthorizationRequired(context)
    )
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ storyId ->
        Log.i(TAG, "Succeeded in posting a story. [${storyId}]")
    }, { error ->
        Log.e(TAG, "Failed to post a story.", error)
    })
    .addTo(disposables)

Posting link story

To post a story with the information obtained by scrapping a web page,

  1. To obtain the web page information to be shared in a story, call the linkInfo() method by passing url with a string type. linkInfo() returns the LinkInfo object that contains the web page information scraped based on the Open Graph Protocol.
  2. Call the postLink() method by passing LinkInfo that is obtained through linkInfo().
Parameter
Name Type Description Required
linkInfo LinkInfo The web page information. O
content String Text to be input in the story.
Up to 2048 characters are allowed.
X
permission Permission Audience for the story.
- PUBLIC: Open to all.
- FRIEND: Open to only friends.
- ONLY_ME: Open to only me (Private).
(Default: PUBLIC)
X
enableShare Boolean Whether to share the story when permission is set to FRIEND (Friends only).
(Default: false)
X
androidExecParam Map<String, String> Parameter to be added to the URL to execute an Android app when selecting the [View on app] button from Kakao Story. X
iosExecParam Map<String, String> Parameter to be added to the URL to execute an iOS app when selecting the [View on app] button from Kakao Story. X
androidMarketParam Map<String, String> Parameter to be added to the execution URL when redirecting to an open market from Kakao Story. X
iosMarketParam Map<String, String> Parameter to be added to the execution URL when redirecting to the App Store from Kakao Story. X
LinkInfo
Name Type Description Required
url String URL of of the scrapped web page.
In the case of a shortened link, the resolved URL.
X
requestedUrl String Original URL of the scrapped web page.
In the case of a shortened link, the original URL before resolving it.
X
host String Site domain of the scrapped web page. X
title String Title of the scrapped web page. X
images List<String> List of representative images on the scrapped web page.
Up to three images are allowed.
X
description String Description of the scrapped web page. X
section String Section information of the scrapped web page. X
type String Content type of the scrapped web page such as video, music, book, article, profile, and website. X
Sample

The following code snippet shows the algorithm for scraping web page and posting a link story with the scrapped web page information.

Kotlin
RxKotlin
// Posting link story

// Create link info with the specified URL.
StoryApiClient.instance.linkInfo("https://www.kakaocorp.com") { linkInfoResult, error ->
    if (error != null) {
        Log.e(TAG, "Failed to create link info.", error)
    } else {
        Log.d(TAG, "Succeeded in creating link info. $linkInfoResult")

        // Posting link story
        val linkInfo = linkInfoResult!!
        val content = "Posting link from Kakao SDK Sample."

        StoryApiClient.instance.postLink(linkInfo, content) { storyPostResult, error ->
            if (error != null) {
                Log.e(TAG, "Failed to post a story.", error)
            }
            else if (storyPostResult != null) {
                Log.i(TAG, "Succeeded in posting a story. [${storyPostResult.id}]")
            }
        }
    }
}
var disposables = CompositeDisposable()

// Posting link story

// Create link info with the specified URL.
StoryApiClient.rx.linkInfo("https://www.kakaocorp.com")
    .flatMap {
        // Posting link story
        val linkInfo = it
        val content = "Posting link from Kakao SDK Sample."
        StoryApiClient.rx.postLink(linkInfo, content)
    }
    .retryWhen(
        // Request additional consent for InsufficientScope.
        RxAuthOperations.instance.incrementalAuthorizationRequired(context)
    )
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ storyId ->
        Log.i(TAG, "Succeeded in posting a story. [${storyId}]")
    }, { error ->
        Log.e(TAG, "Failed to post a story.", error)
    })
    .addTo(disposables)
Return data

The methods to post a story return the StoryPostResult object.

StoryPostResult
Name Type Description
id String ID of the uploaded story.

Retrieve my story Login requiredConsent required

To use this API,

  • You must enable the 'Read access to KakaoStory posts' scope in [My Application] > [Kakao Login] > [Consent items].
  • A user must consent to the 'Read access to KakaoStory posts' scope. Otherwise, an error occurs.

Retrieving multiple stories

To retrieve story information on Kakao Story of the user currently logged in, call the stories() method in the StoryApiClient class.

Sample
Kotlin
RxKotlin
// Retrieving multiple stories
StoryApiClient.instance.stories { stories, error ->
    if (error != null) {
        Log.e(TAG, "Failed to retrieve Kakao Story.", error)
    }
    else {
        Log.i(TAG, "Succeeded in retrieving Kakao Story.  \n$stories")
    }
}
var disposables = CompositeDisposable()

// Retrieving multiple stories
StoryApiClient.rx.stories()
    .retryWhen(
        // Request additional consent for InsufficientScope.
        RxAuthOperations.instance.incrementalAuthorizationRequired(context)
    )
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ stories ->
        Log.i(TAG, "Succeeded in retrieving Kakao Story. \n$stories")
    }, { error ->
        Log.e(TAG, "Failed to retrieve Kakao Story.", error)
    }).addTo(disposables)

Retrieving a specific story

To retrieve the detailed information of a specific story, call the story() method by passing id included in the Story object. Then, you can get detailed information including comments and reactions.

Parameter
Name Type Description Required
id String Story ID to be retrieved. O
Sample
Kotlin
RxKotlin
// Retrieving specified story

// This code snippet shows the algorithm for retrieving all stories of the user 
// to figure out story IDs and retrieving the first story by designating the story ID.
StoryApiClient.instance.stories { stories, error ->
    if (error != null) {
        Log.e(TAG, "Failed to retrieve Kakao Story.", error)
    }
    else if (stories != null) {
        if (stories.isEmpty()) {
            Log.e(TAG, "There is no story :(")
        }
        else {

            // Story ID to be retrieved. 
            val storyId = stories.first().id

            // Retrieving specified story
            StoryApiClient.instance.story(storyId) { story, error ->
                if (error != null) {
                    Log.e(TAG, "Failed to retrieve Kakao Story.", error)
                }
                else if (story != null) {
                    Log.i(TAG, "Succeeded in retrieving Kakao Story." +
                            "\nID: ${story.id}" +
                            "\nMedeia Type: ${story.mediaType}" +
                            "\nCreated at: ${story.createdAt}" +
                            "\nContent: ${story.content}")
                }
            }
        }
    }
var disposables = CompositeDisposable()

// Retrieving specified story

// This code snippet shows the algorithm for retrieving all stories of the user 
// to figure out story IDs and retrieving the first story by designating the story ID.
StoryApiClient.rx.stories()
    .retryWhen(
        // Request additional consent for InsufficientScope.
        RxAuthOperations.instance.incrementalAuthorizationRequired(context)
    )
    .flatMap { stories ->
        if (stories.isNotEmpty()) {

            // Story ID to be retrieved. 
            val storyId = stories.first().id

            StoryApiClient.rx.story(storyId)
        }
        else {
            Single.error(ClientError(ClientErrorCause.IllegalState, "No stories"))
        }
    }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ story ->
        Log.i(TAG, "Succeeded in retrieving Kakao Story." +
                "\nID: ${story.id}" +
                "\nMedeia Type: ${story.mediaType}" +
                "\nCreated at: ${story.createdAt}" +
                "\nContent: ${story.content}")
    }, { error ->
        Log.e(TAG, "Failed to retrieve Kakao Story.", error)
    }).addTo(disposables)
Return data

story() returns the Story object, and stories() returns a list of Story objects that contains each story information. stories() does not return comments and likes that are only returned through story().

Story
Name Type Description Required
id String Story ID. O
url String Story URL. O
content String Story content. O
createdAt Date The time when the story is posted in RFC3339 internet date/time format. O
mediaType String Story type.
One of photo (photo), note (text), notSupported (not supported).
X
media List<StoryImage> URLs by image size.
Only returned if mediaType is photo.
X
commentCount Int Number of comments. O
likeCount Int Number of moods that the user's friends left. O
permission Permission Audience for the story.
- PUBLIC: Open to all.
- friend: Open to only friends.
- onlyMe: Open to only me (Private).
(Default: PUBLIC)
X
comments List<StoryComment> List of comments consisting of text (content) and writer (the user who left the comment).
NOTE: Not returned if stories() is called.
X
likes List<StoryLike> List of moods consisting of emotion (mood emoji) and actor (the user who left the mood).
NOTE: Not returned if stories() is called.
X
StoryImage
Name Type Description Required
large String URL of the image with a size of 720x960 pixels. X
medium String URL of the image with a size of 240x320 pixels. X
original String URL of the original image. X
small String URL of the image with a size of 160x213 pixels. X
xlarge String URL of the image with a size of 1280x1706 pixels. X
StoryComments
Name Type Description Required
text String Comment content. O
writer StoryActor User who left a comment. O
StoryLike
Name Type Description Required
emotion Emotion Mood left in a story.
One of like, cool, happy, sad, cheerUp.
O
actor StoryActor User who left the mood. O
StoryActor
Name Type Description Required
displayName String User's Kakao Story nickname. O
profileThumbnailUrl String User's Kakao Story profile thumbnail URL. X

Delete story Login required

To delete a story on a user's Kakao Story, call the delete() method in the StoryApiClient class. You must pass id to specify the story ID you want to delete.

Parameter
Name Type Description Required
id String Story ID to be deleted.
If you do not know the story ID, call the Retrieving my story API.
O
Sample

The following code snippet shows the algorithm for retrieving all stories of the user and deleting the first story.

Kotlin
RxKotlin
// Deleting story

// This code snippet shows the algorithm for retrieving all stories of the user and deleting the first story.
StoryApiClient.instance.stories { stories, error ->
    if (error != null) {
        Log.e(TAG, "Failed to retrieve Kakao Story.", error)
    }
    else if (stories != null) {
        if (stories.isEmpty()) {
            Log.e(TAG, "There is no story :(")
        }
        else {

            // Story ID to be deleted. 
            val storyId = stories.first().id

            // Deleting story
            StoryApiClient.instance.delete(storyId) { error ->
                if (error != null) {
                    Log.e(TAG, "Failed to delete story.", error)
                } else {
                    Log.i(TAG, "Succeeded in deleting story.  [$storyId]")
                }
            }
        }
    }
}
var disposables = CompositeDisposable()

// Deleting story

// This code snippet shows the algorithm for retrieving all stories of the user and deleting the first story.
StoryApiClient.rx.stories()
    .retryWhen(
        // Request additional consent for InsufficientScope.
        RxAuthOperations.instance.incrementalAuthorizationRequired(context)
    )
    .flatMapCompletable { stories ->
        if (stories.isNotEmpty()) {

            // Story ID to be deleted. 
            val storyId = stories.first().id

            StoryApiClient.rx.delete(storyId)
        }
        else {
            Completable.error(ClientError(ClientErrorCause.IllegalState, "There is no story :("))
        }
    }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({
        Log.i(TAG, "Succeeded in deleting story.")
    }, { error ->
        Log.e(TAG, "Failed to delete story.", error)
    }).addTo(disposables)

See more

Legacy

To see how to integrate the features of Kakao Story using the Legacy Kakao SDK for Android, see Kakao Story guide for Legacy Android SDK.

It is highly recommended to migrate to the new version of Android SDK as soon as possible because the Legacy version may not be supported anymore.