Clickstream - A Modern, Fast, and Lightweight Android Library Ingestion Platform.

Overview

A Modern, Fast, and Lightweight Android Ingestion Library

Clickstream is an event agnostic, real-time data ingestion platform. Clickstream allows apps to maintain a long-running connection to send data in real-time.

The word “Clickstream” is a trail of digital breadcrumbs left by users as they click their way through a website or mobile app. It is loaded with valuable customer information for businesses and its analysis and usage has emerged as a powerful data source.

To know more about Clickstream, you can read our Medium post

Clickstream provides an end to end solution for event ingestion. For setting up the backend infrastructure please check out raccoon

Architecture

Clickstream Architecture

Mobile Library Architecture

Clickstream HLD

Key features

  • Simple and lightweight
  • Remotely Configurable
  • Support for real-time data
  • Multiple QoS support (QoS0 and QoS1)
  • Typesafe and reusable schemas
  • Efficient payloads
  • In-built data aggregation

Getting Started with Clickstream

  1. Add the maven repository URL to the root build.gradle of your project.
buildscript {
    repositories {
        mavenCentral()
    }
}
  1. Add the following dependencies to your module build.gradle
dependencies {
    val version = "x.y.z"
    implementation 'com.gojek.clickstream:clickstream-android:[latest_version]'
}
  1. Add the following rule in proguard.pro or dexguard-project.txt
-keep class * extends com.google.protobuf.GeneratedMessageLite { *; }

Once you’ve added the dependencies and synchronized your Gradle project, the next step is to initialize Clickstream.

Initialization

Initialization of the Clickstream can be done on the background thread or main-thread, Invocation should be done on the Application class. So that the initialization happens only once.

To create a Clickstream instance you can do the following setup:

class App : Application() {

    override fun onCreate() {
        initClickStream()
    }

    private fun initClickStream() {
        ClickStream.initialize(
            configuration = CSConfiguration.Builder(
                context = context,
                info = CSInfo(
                    appInfo = appInfo,
                    locationInfo = locationInfo,
                    deviceInfo = csDeviceInfo,
                    customerInfo = customerInfo,
                    sessionInfo = sessionInfo
                ),
                config = getBuildConfig(config)
            ).apply {
                setLogLevel(DEBUG)
                setCSSocketConnectionListener(connectionListener())
            }.build())
    }

    /**
    * @see [CSConnectionEvent] for more detail explanation
    */
    private fun onConnectionListener(): CSSocketConnectionListener {
        return object : CSSocketConnectionListener {
            override fun onEventChanged(event: CSConnectionEvent) {
                is OnConnectionConnecting -> {}
                is OnConnectionConnected -> {}
                is OnMessageReceived -> {}
                is OnConnectionClosing -> {}
                is OnConnectionClosed -> {}
                is OnConnectionFailed -> {}
 			}
    	}
    }
}

Configuration

CSEventSchedulerConfig

Holds the configurations for Clickstream. These constraints allow for fine-grained control over the library behaviour like duration between retries, flush events when app goes in background, etc.

Description Variable Type Default value
Number of events to combine in a single request eventsPerBatch Int 20
Delay between two requests (in millis) batchPeriod Long 10000
Flag for enabling forced flushing of events flushOnBackground Boolean false
Wait time after which socket gets disconnected connectionTerminationTimerWaitTimeInMillis Long 5000
Flag for enabling flushing of events by background task backgroundTaskEnabled Boolean false
Initial delay for background task (in hour) workRequestDelayInHr Long 1

CSNetworkConfig

Holds the configuration for network related. e.g configure timeouts for network channel.

Description Variable Type Default value
Endpoint for web socket server endPoint String No Default Value
Connect timeout to be used by okhttp (in seconds) connectTimeout Long 10
Read timeout to be used by okhttp (in seconds) readTimeout Long 10
Write timeout to be used by okhttp (in seconds) writeTimeout Long 10
Interval between pings initiated by client (in seconds) pingInterval Long 1
Initial retry duration to be used for retry backoff strategy (in milliseconds) initialRetryDurationInMs Long 1000
Maximum retry duration for retry backoff strategy (in milliseconds) maxConnectionRetryDurationInMs Long 6000
Maximum retries per batch request maxRetriesPerBatch Long 20
Maximum timeout for a request to receive Ack (in milliseconds) maxRequestAckTimeout Long 10000
OkHttpClient instance that passed from client okHttpClient OkHttpClient No Default Value

CSEventClassification

Holds the class name to be classify into InstantEvent (QoS) or RealtimeEvent (QoS1).

Description Variable Type Default value
Holds all the eventTypes eventTypes EventClassifier [EventClassifier(identifier: "realTime", eventNames: []), EventClassifier(identifier: "instant", eventNames: [])]

Cleanup

Destroy instance of Clickstream, for example can be called when user logs out of the app.

   ClickStream.release()

Push an Event

Using Explicit Builder

As Clickstream use a proto definition on the client-side, you can build a MessageLite and send it directly through ClickstreamSDK.

For instance, you’ve defined a proto definition called Rating.java which has the following properties

rating: Float
reason: String

Thus we can build the rating object just by using a Builder Pattern.

val event = Rating.newBuilder()
    .setRating(4.5)
    .setReason("nice!")
    .build()

// wrap event in CSEvent
val csEvent = CSEvent(
    guid = UUID.randomUUID().toString(),
    timestamp = Timestamp.getDefaultInstance(),
    message = event
)

// track the event
ClickStream.getInstance().trackEvent(csEvent)

Congratulations! You’re done!.

Running Sample App

In order to running the sample app, please follow this instruction

  1. git clone [email protected]:gojekfarm/clickstream-android.git
  2. cd clickstream-android
  3. ./gradlew :app:installDebug or via play button in the Android Studio
Figure 1 Figure 2

License

Copyright 2022 GOJEK

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • [Bug] : Asking for ACTION_MANAGE_OVERLAY_PERMISSION for Event visualiser

    [Bug] : Asking for ACTION_MANAGE_OVERLAY_PERMISSION for Event visualiser

    Description Since event visualiser is a floating window, we need to explicitly grant permission to draw over other apps.

    Changes Check and grant the required permission before launching the event visualiser.

    opened by kshitij6325 1
  • [Enhancement] : Changing public api to add event listeners

    [Enhancement] : Changing public api to add event listeners

    Changes

    • Currently, event listeners can only be added while initialising the clickstream. Changes in this PR will allow to add event listeners directly through clickstream instance, anywhere in the code.

    • Redirecting to Display over other apps settings page if the app does not already have it enabled.

    opened by kshitij6325 1
  • [Enhancement] Renaming EventInterceptor to EventListener

    [Enhancement] Renaming EventInterceptor to EventListener

    Refactored following :

    clickstream-event-interceptor module -> clickstream-event-listener moduleCSEventInterceptor -> CSEventListenerCSInterceptedEvent -> CSEventModel

    enhancement 
    opened by kshitij6325 1
  • [Feature] : Implement Event visualiser UI

    [Feature] : Implement Event visualiser UI

    Event Visualiser is a UI tool to view and debug clickstream events on android. Following modules were added for this -

    • clickstream-event-interceptor -> Contains CSEventListener which observes clickstream events as CSEventModel
    • clickstream-event-visualiser -> Core module for event visualiser.
    • clickstream-event-visualiser-ui -> UI module for event visualiser.
    • clickstream-event-visualiser-noop -> light weight, no operation module for clickstream-event-visualiser
    • clickstream-event-visualiser-ui-noop -> light weight, no operation module for clickstream-event-visualiser-ui
    enhancement 
    opened by kshitij6325 1
  • [Feature] : Update Health Metrics Event Name

    [Feature] : Update Health Metrics Event Name

    Abstract

    Health Metrics is the way we organized the performance of the Clickstream where we push events to the backend. Health Metrics has been serving us @ Gojek for the last 1,5 years and it performs very well. However, as we open source the clickstream, we also want the communities to get the power of the health metrics; this is needed as the first version of Health Metrics is coupled with the Gojek environment.

    Please see the detail of RFC over here https://github.com/gojek/clickstream-android/discussions/18

    opened by radityagumay 0
  • [Feature] : Event visualiser enchancements

    [Feature] : Event visualiser enchancements

    This PR contains following enhancements to event visualiser -

    • Showing clickstream connection status.
    • Add a toggle on event properties screen to toggle between compact mode (only show properties that are set) and normal mode (show all properties).
    • Fix click on Event visualiser window

    Toggle for compact mode

    Toggle for compact model

    Connection state change

    Connection state change

    opened by kshitij6325 0
  • Duplicate class com.google.protobuf.AbstractMessageLite

    Duplicate class com.google.protobuf.AbstractMessageLite

    During integration with the Clickstream, if you experience a compilation error like the below, do consider to substitute the protobuf-java to protobuf-lite. see our example here. https://github.com/gojek/clickstream-android/blob/main/app/build.gradle.kts#L69

    * What went wrong:
    Execution failed for task ':app:checkDebugDuplicateClasses'.
    > A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
       > Duplicate class com.google.protobuf.AbstractMessageLite found in modules protobuf-java-3.11.0 (com.google.protobuf:protobuf-java:3.11.0) and protobuf-javalite-3.11.0 (com.google.protobuf:protobuf-javalite:3.11.0)
         Duplicate class com.google.protobuf.AbstractMessageLite$Builder found in modules protobuf-java-3.11.0 (com.google.protobuf:protobuf-java:3.11.0) and protobuf-javalite-3.11.0 (com.google.protobuf:protobuf-javalite:3.11.0)
         Duplicate class com.google.protobuf.AbstractMessageLite$Builder$LimitedInputStream found in modules protobuf-java-3.11.0 (com.google.protobuf:protobuf-java:3.11.0) and protobuf-javalite-3.11.0 (com.google.protobuf:protobuf-javalite:3.11.0)
         Duplicate class com.google.protobuf.AbstractMessageLite$InternalOneOfEnum found in modules protobuf-java-3.11.0 (com.google.protobuf:protobuf-java:3.11.0) and protobuf-javalite-3.11.0 (com.google.protobuf:protobuf-javalite:3.11.0)
         Duplicate class com.google.protobuf.AbstractParser found in modules protobuf-java-3.11.0 (com.google.protobuf:protobuf-java:3.11.0) and protobuf-javalite-3.11.0 (com.google.protobuf:protobuf-javalite:3.11.0)
         Duplicate class com.google.protobuf.AbstractProtobufList found in modules protobuf-java-3.11.0 (com.google.protobuf:protobuf-java:3.11.0) and protobuf-javalite-3.11.0 (com.google.protobuf:protobuf-javalite:3.11.0)
         Duplicate class com.google.protobuf.AllocatedBuffer found in modules protobuf-java-3.11.0 (com.google.protobuf:protobuf-java:3.11.0) and protobuf-javalite-3.11.0 (com.google.protobuf:protobuf-javalite:3.11.0)
         Duplicate class com.google.protobuf.AllocatedBuffer$1 found in modules protobuf-java-3.11.0 (com.google.protobuf:protobuf-java:3.11.0) and protobuf-javalite-3.11.0 (com.google.protobuf:protobuf-javalite:3.11.0)
         Duplicate class com.google.protobuf.AllocatedBuffer$2 found in modules protobuf-java-3.11.0 (com.google.protobuf:protobuf-java:3.11.0) and protobuf-javalite-3.11.0 (com.google.protobuf:protobuf-javalite:3.11.0)
    
    opened by radityagumay 0
Releases(1.0.0-alpha-11)
Owner
Gojek
SuperApp from Southeast Asia
Gojek
[Android Library] Get easy access to device information super fast, real quick

DeviceInfo-Sample Simple, single class wrapper to get device information from an android device. This library provides an easy way to access all the d

Anitaa Murthy 193 Nov 20, 2022
Koin Annotations - help declare Koin definition in a very fast and intuitive way, and generate all underlying Koin DSL for you

The goal of Koin Annotations project is to help declare Koin definition in a very fast and intuitive way, and generate all underlying Koin DSL for you. The goal is to help developer experience to scale and go fast ?? , thanks to Kotlin Compilers.

insert-koin.io 68 Jan 6, 2023
Feature flags solution that is fast, lean, and open-source.

FFS Feature flags solution that is fast, lean, and open-source. Documentation Full documentation available at https://doist.github.io/ffs/. Project FF

Doist 84 Oct 31, 2022
Simple, fast, efficient logging facade for Android apps

µlog Simple, fast, and efficient logging facade for Android apps. Inspired by Timber and Logcat. Features Lazy message evaluation Pluggable backends (

Danny Lin 9 Oct 21, 2022
Fast Seek for ExoPlayer

FastExoPlayerSeeker Introduction Adds fast seeking for exoplayer. (Note: it also depends on the amount of video encoding, mainly IDR Frames) How to in

Jan Rabe 40 Dec 27, 2022
A fast-prototyping command line system

Kotlin-er CLI A different take on making command line programs, emphasizing development speed over customization Status Auto-deployed to Maven Central

Lightning Kite 22 Jan 22, 2022
A Bluetooth kotlin multiplatform "Cross-Platform" library for iOS and Android

Blue-Falcon A Bluetooth "Cross Platform" Kotlin Multiplatform library for iOS, Android, MacOS, Raspberry Pi and Javascript. Bluetooth in general has t

Andrew Reed 220 Dec 28, 2022
Lightweight data loading and caching library for android

ColdStorage A lightweight data loading and caching library for android Quicklinks Feature requests: Got a new requirement? Request it here and it will

Cryptic Minds 41 Oct 17, 2022
A lightweight and simple Kotlin library for deep link handling on Android 🔗.

A lightweight and simple Kotlin library for deep link handling on Android ??.

Jeziel Lago 101 Aug 14, 2022
A lightweight, simple, smart and powerful Android routing library.

RxRouter Read this in other languages: 中文, English A lightweight, simple, smart and powerful Android routing library. Getting started Setting up the d

Season 323 Nov 10, 2022
🚟 Lightweight, and simple scheduling library made for Kotlin (JVM)

Haru ?? Lightweight, and simple scheduling library made for Kotlin (JVM) Why did you build this? I built this library as a personal usage library to h

Noel 13 Dec 16, 2022
Lightweight compiler plugin intended for Kotlin/JVM library development and symbol visibility control.

Restrikt A Kotlin/JVM compiler plugin to restrict symbols access, from external project sources. This plugin offers two ways to hide symbols: An autom

Lorris Creantor 18 Nov 24, 2022
A android platform i.e, App that helps marriage/party halls and individuals to connect to the nearest places where this food could feed those in need and food wastage is minimised

(Muskan- The joy of giving by nature) , a android platform i.e, App that helps marriage/party halls and individuals to connect to the nearest places where this food could feed those in need and food wastage is minimised.

OxVidhi 15 Nov 26, 2022
Delish, a Food Recipes App in Jetpack Compose and Hilt based on modern Android tech-stacks and MVVM clean architecture.

Delish Screens Tech stack & Open-source libraries 100% Kotlin based + Coroutines + Flow for asynchronous. Dagger Hilt 2.37 Accompanist JetPack Jetpack

Mohamed Elbehiry 305 Dec 12, 2022
A Lightweight PDF Viewer Android library which only occupies around 125kb while most of the Pdf viewer occupies up to 16MB space.

Pdf Viewer For Android A Simple PDF Viewer library which only occupies around 125kb while most of the Pdf viewer occupies upto 16MB space. How to inte

Rajat 362 Dec 29, 2022
Easy lightweight SharedPreferences library for Android in Kotlin using delegated properties

Easy lightweight SharedPreferences library for Android in Kotlin using delegated properties Idea Delegated properties in Kotlin allow you to execute a

null 25 Dec 27, 2022
Koi, a lightweight kotlin library for Android Development.

Koi - A lightweight Kotlin library for Android Koi include many useful extensions and functions, they can help reducing the boilerplate code in Androi

Hello World 514 Nov 29, 2022
A lightweight cache library written in Kotlin

[NEW] Released to Maven Central: 'com.github.yundom:kache:1.x.x' Kache A runtime in-memory cache. Installation Put this in your build.gradle implemen

Dennis 22 Nov 19, 2022
Lightweight Kotlin DSL dependency injection library

Warehouse DSL Warehouse is a lightweight Kotlin DSL dependency injection library this library has an extremely faster learning curve and more human fr

Osama Raddad 18 Jul 17, 2022