Android and JVM (Kotlin)

Two packages, for Kotlin or Java:

  • glancy-android for Android apps (API 21+): events, screen views, app lifecycle and an offline queue.
  • glancy-core, the same client for any JVM: Kotlin or Java backends, workers and command-line tools. No dependencies.

Install

The packages are published to GitHub Packages, which asks for a GitHub token even for reading. Create a personal access token with the read:packages scope and put it in ~/.gradle/gradle.properties (not in your project):

gpr.user=your-github-username
gpr.key=ghp_your_token

Then add the repository and the dependency:

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven("https://maven.pkg.github.com/caravela-labs/glancy") {
            credentials {
                username = providers.gradleProperty("gpr.user").orNull
                password = providers.gradleProperty("gpr.key").orNull
            }
        }
    }
}
// app/build.gradle.kts
dependencies {
    implementation("com.glancy:glancy-android:0.1.3") // or glancy-core on any JVM
}

Set up (Android)

Call setup in your Application class, with the write key from your bucket's Setup page:

class KitboxApp : Application() {
    override fun onCreate() {
        super.onCreate()
        Glancy.setup(this, writeKey = "YOUR_WRITE_KEY", host = "https://ingest.heyglancy.com")
    }
}

Remember to register the class in AndroidManifest.xml (<application android:name=".KitboxApp" …>). The library adds the INTERNET permission itself.

Events, screens and users

Glancy.track("Order Completed", mapOf("revenue" to 42, "currency" to "EUR"))

// after sign in
Glancy.identify(user.id, mapOf("name" to user.name, "email" to user.email))

// on sign out
Glancy.reset()

Send screen views with screen, for example from a Compose screen:

@Composable
fun CheckoutScreen() {
    LaunchedEffect(Unit) { Glancy.screen("Checkout") }
    // …
}

For apps built on Activities, Glancy.setup(this, writeKey, host, trackActivities = true) sends a screen view for every Activity instead, named after its class (without "Activity").

App lifecycle

On by default:

Event When
Application Installed The first launch
Application Updated The first launch after versionName or versionCode changed
Application Opened Each launch, and each return to the foreground (from_background: true)
Application Backgrounded The app goes to the background; the queue is sent right away

Every event also carries the manufacturer, model, Android version, screen size, locale, time zone and app version.

Options

Glancy.setup(this, writeKey = "YOUR_WRITE_KEY", host = "https://ingest.heyglancy.com") {
    flushAt = 20               // events per batch
    flushIntervalMs = 30_000   // time between batches
    maxQueueSize = 1000        // events kept while offline
    trackLifecycle = true
    debug = BuildConfig.DEBUG  // log every event
}

Events waiting to be sent are kept in the app's files (filesDir/glancy), so they survive restarts and time offline.

Any JVM (glancy-core)

On a server, create one client, give it a folder for its queue, and shut it down cleanly so queued events are sent:

val glancy = GlancyClient(
    GlancyConfig(writeKey = "YOUR_WRITE_KEY", host = "https://ingest.heyglancy.com"),
    FileStorage(File("/var/lib/myapp/glancy")),
)

glancy.identify("user_42")
glancy.track("Invoice Paid", mapOf("amount" to 120))

Runtime.getRuntime().addShutdownHook(Thread { glancy.shutdown() })

Use the same user ids as your apps, and server events land on the same people.