
In-app user feedback SDK offering send, list (paged) and fetch-by-id APIs, with global or lifecycle-scoped instances, secure key guidance and ready demo UI components.
Volyum is a friendly feedback platform designed with Kotlin Multiplatform in mind. It helps developers easily gather valuable feedback from their users right within their app, using the Volyum SDK.
β οΈ Heads up: Volyum is still in active development. Thanks for checking it out early! Right now, the SDK requires private credentials, so it wonβt work out of the box (unless you somehow already have them π).
The Volyum SDK is available on Maven Central (the default store for Kotlin libraries), so installation is straightforward.
Add this dependency to your commonMain (for KMP) or your regular dependencies block:
dependencies {
implementation("io.github.donald-okara:volyum:$latest_version")
}Volyum supports two integration styles, depending on whether you want a global singleton or a scoped instance tied to a lifecycle.
If you want one global Volyum instance available throughout your app, initialize it once at startup.
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
val config = VolyumConfig(
projectId = "your_project_id",
apiKey = "your_api_key"
)
VolyumSdk.init(config)
}
}fun MainViewController() = ComposeUIViewController {
// remember ensures config is stable across recompositions
val config = remember {
VolyumConfig("your_project_id", "your_api_key")
}
// Initialize SDK once
LaunchedEffect(Unit) {
VolyumSdk.init(config)
}
App()
}fun main() {
val config = VolyumConfig("your_project_id", "your_api_key")
VolyumSdk.init(config)
App() // launch Compose for Desktop
}Access Volyum anywhere:
val volyum = VolyumSdk.get()If you want Volyum tied to a screen, feature, or DI scope, use VolyumFactory.
With Compose Multiplatform, you can rely on the multiplatform ViewModel.
import androidx.lifecycle.ViewModel
import ke.don.volyum.feedback.config.*
class FeedbackViewModel : ViewModel() {
private val config = VolyumConfig("your_project_id", "your_api_key")
val volyum: Volyum = VolyumFactory.create(config)
}@Composable
fun FeedbackScreen(viewModel: FeedbackViewModel = viewModel()) {
val volyum = viewModel.volyum
// Use volyum safely here
}π This works across all platforms supported by Compose Multiplatform.
You want one shared instance across your entire app.
You donβt need per-feature configuration.
Your feedback system should behave consistently everywhere.
Best for small to medium apps or when feedback is a core global feature.
You need separate instances for different screens/features.
You want to manage feedback lifecycles via DI or ViewModels.
You want to test with different configurations easily.
Best for large apps or when feedback should behave differently per module.
Security note
The Volyum API has 3 main methods.
This is the method the app calls to send the feedback from the user.
/**
* Sends feedback to the Volyum API.
*
* @param feedback The feedback to send.
* @return A [VolyumResult] containing the sent feedback or a [NetworkError] if an error occurred.
*/
suspend fun sendFeedback(
feedback: Feedback,
): VolyumResult<Feedback, NetworkError> =
apiClient.addFeedback(feedback = feedback)Sample usage
volyum.sendFeedback(
feedback = uiState.value.sendFeedback.copy(
userId = userData?.id,
targetType = uiState.value.targetType.label,
userMetadata = UserMetadata(
username = userData?.name,
profileUrl = userData?.profileUrl,
),
),
)This is the method that fetches the feedback list from the volyum api. Yes, it supports pagination by default
/**
* Retrieves a list of feedback entries based on the provided filter.
*
* This function makes an API call to fetch feedback. The results can be filtered * using the [GetFeedbackFilter] object. *
* @param filter The filter criteria to apply when fetching feedback.
* @return A [VolyumResult] which is either a [VolyumResult.Success] containing a list of [Feedback] objects * or a [VolyumResult.Error] containing a [NetworkError] if the request fails.
*/
suspend fun getFeedback(
filter: GetFeedbackFilter,
): VolyumResult<List<Feedback>, NetworkError> =
apiClient.getFeedback(filter)Sample usage
volyum.getFeedback(
GetFeedbackFilter(
userId = userId,
status = FeedbackStatus.OPEN,
limit = 20,
offset = 0
)This method fetches a specific feedback item by id
/**
* Retrieves a feedback item by its unique identifier.
*
* This function makes an API call to fetch a specific feedback item based on the provided ID.
*
* @param id The unique identifier of the feedback to retrieve.
* @return A [VolyumResult] which is either a [VolyumResult.Success] containing the [Feedback] object
* or a [VolyumResult.Error] containing a [NetworkError] if the request fails.
*/
suspend fun getFeedbackById(
id: String,
): VolyumResult<Feedback, NetworkError> =
apiClient.getFeedbackById(id = id)Sample usage
volyum.getFeedbackById(id)This is a demo of how Volyum works.
Desktop
Mobile
The demo project i.e how to best utilize volyum is in the ComposeApp module along with all components I built. Feel free to repurpose for your app
The module's documentation will be found here
The library is open source and we welcome contributors. All its documentation can be found here.
Volyum is a friendly feedback platform designed with Kotlin Multiplatform in mind. It helps developers easily gather valuable feedback from their users right within their app, using the Volyum SDK.
β οΈ Heads up: Volyum is still in active development. Thanks for checking it out early! Right now, the SDK requires private credentials, so it wonβt work out of the box (unless you somehow already have them π).
The Volyum SDK is available on Maven Central (the default store for Kotlin libraries), so installation is straightforward.
Add this dependency to your commonMain (for KMP) or your regular dependencies block:
dependencies {
implementation("io.github.donald-okara:volyum:$latest_version")
}Volyum supports two integration styles, depending on whether you want a global singleton or a scoped instance tied to a lifecycle.
If you want one global Volyum instance available throughout your app, initialize it once at startup.
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
val config = VolyumConfig(
projectId = "your_project_id",
apiKey = "your_api_key"
)
VolyumSdk.init(config)
}
}fun MainViewController() = ComposeUIViewController {
// remember ensures config is stable across recompositions
val config = remember {
VolyumConfig("your_project_id", "your_api_key")
}
// Initialize SDK once
LaunchedEffect(Unit) {
VolyumSdk.init(config)
}
App()
}fun main() {
val config = VolyumConfig("your_project_id", "your_api_key")
VolyumSdk.init(config)
App() // launch Compose for Desktop
}Access Volyum anywhere:
val volyum = VolyumSdk.get()If you want Volyum tied to a screen, feature, or DI scope, use VolyumFactory.
With Compose Multiplatform, you can rely on the multiplatform ViewModel.
import androidx.lifecycle.ViewModel
import ke.don.volyum.feedback.config.*
class FeedbackViewModel : ViewModel() {
private val config = VolyumConfig("your_project_id", "your_api_key")
val volyum: Volyum = VolyumFactory.create(config)
}@Composable
fun FeedbackScreen(viewModel: FeedbackViewModel = viewModel()) {
val volyum = viewModel.volyum
// Use volyum safely here
}π This works across all platforms supported by Compose Multiplatform.
You want one shared instance across your entire app.
You donβt need per-feature configuration.
Your feedback system should behave consistently everywhere.
Best for small to medium apps or when feedback is a core global feature.
You need separate instances for different screens/features.
You want to manage feedback lifecycles via DI or ViewModels.
You want to test with different configurations easily.
Best for large apps or when feedback should behave differently per module.
Security note
The Volyum API has 3 main methods.
This is the method the app calls to send the feedback from the user.
/**
* Sends feedback to the Volyum API.
*
* @param feedback The feedback to send.
* @return A [VolyumResult] containing the sent feedback or a [NetworkError] if an error occurred.
*/
suspend fun sendFeedback(
feedback: Feedback,
): VolyumResult<Feedback, NetworkError> =
apiClient.addFeedback(feedback = feedback)Sample usage
volyum.sendFeedback(
feedback = uiState.value.sendFeedback.copy(
userId = userData?.id,
targetType = uiState.value.targetType.label,
userMetadata = UserMetadata(
username = userData?.name,
profileUrl = userData?.profileUrl,
),
),
)This is the method that fetches the feedback list from the volyum api. Yes, it supports pagination by default
/**
* Retrieves a list of feedback entries based on the provided filter.
*
* This function makes an API call to fetch feedback. The results can be filtered * using the [GetFeedbackFilter] object. *
* @param filter The filter criteria to apply when fetching feedback.
* @return A [VolyumResult] which is either a [VolyumResult.Success] containing a list of [Feedback] objects * or a [VolyumResult.Error] containing a [NetworkError] if the request fails.
*/
suspend fun getFeedback(
filter: GetFeedbackFilter,
): VolyumResult<List<Feedback>, NetworkError> =
apiClient.getFeedback(filter)Sample usage
volyum.getFeedback(
GetFeedbackFilter(
userId = userId,
status = FeedbackStatus.OPEN,
limit = 20,
offset = 0
)This method fetches a specific feedback item by id
/**
* Retrieves a feedback item by its unique identifier.
*
* This function makes an API call to fetch a specific feedback item based on the provided ID.
*
* @param id The unique identifier of the feedback to retrieve.
* @return A [VolyumResult] which is either a [VolyumResult.Success] containing the [Feedback] object
* or a [VolyumResult.Error] containing a [NetworkError] if the request fails.
*/
suspend fun getFeedbackById(
id: String,
): VolyumResult<Feedback, NetworkError> =
apiClient.getFeedbackById(id = id)Sample usage
volyum.getFeedbackById(id)This is a demo of how Volyum works.
Desktop
Mobile
The demo project i.e how to best utilize volyum is in the ComposeApp module along with all components I built. Feel free to repurpose for your app
The module's documentation will be found here
The library is open source and we welcome contributors. All its documentation can be found here.