Dijji Dijji Intelligence·Engagement·Defense
Install → Android

Dijji for Android.

Kotlin SDK for analytics, behavior targeting, crash capture, install attribution, push, and in-app messages — from one init() call. One dependency. Universal across View and Compose apps.

Live v1.0.0-alpha AAR · 54 KB Apache 2.0 · open source
Contents

01Quickstart — 2 lines.

One dependency in Gradle. One initialize call in your Application. Everything else is opt-in.

1.1 · Add the dependency

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}
// app/build.gradle.kts
dependencies {
    implementation("com.dijji:dijji-core:1.0.0")

    // Optional — pull only what you use
    implementation("com.dijji:dijji-messages:1.0.0")  // in-app UI
    implementation("com.dijji:dijji-push:1.0.0")      // FCM glue
}

1.2 · Initialize

// YourApp.kt
class YourApp : Application() {
    override fun onCreate() {
        super.onCreate()
        Dijji.init(this, siteKey = "ws_abc123")
    }
}

That’s it. Rebuild, launch. Your first app_open and screen_view events will land on your dashboard within 30 seconds.

Get your site key — sign up at dijji.com/register, create a workspace, and your Android app’s ws_* key appears in Site Settings → Mobile. Free during alpha.

02What auto-captures.

These fire without a single extra line of code. Turn any of them off via the config block on Dijji.init.

EventWhen it fires
app_installFirst launch on this device — Play Install Referrer resolves UTM / source
app_openProcess foreground (cold + warm starts)
app_backgroundLast activity backgrounds — queue flushes here
session_startFirst event after ≥30 min idle — configurable
session_endIdle timeout or background, whichever fires first
screen_viewActivity onResume — name = class simple name
app_crashUncaught exception caught before the process dies — breadcrumbs attached
$identifyYour Dijji.identify() call

03Public API.

Eleven methods. No builders, no config trees, no overloaded patterns to learn. Ruthlessly small on purpose.

MethodPurpose
Dijji.init(ctx, siteKey)Required once — typically in Application.onCreate
Dijji.identify(userId, traits)Tie subsequent events to a user. Traits merge into the user profile.
Dijji.track(name, props)Custom event. Properties are free-form key/value.
Dijji.screen(name, props)Manual screen — only when auto-capture name is wrong
Dijji.setUserProperty(k, v)Persistent property attached to every future event
Dijji.setUserProperties(map)Bulk form of setUserProperty
Dijji.unsetUserProperty(k)Remove a previously-set super-property
Dijji.reset()Logout — rotates visitor_id, flushes queue first
Dijji.flush()Force queue send (before known app exit)
Dijji.setEnabled(bool)Per-user privacy kill — survives restarts
Dijji.visitorId()The opaque per-install UUID for server-side correlation

Example · a full login flow

fun onLoginSuccess(user: User) {
    Dijji.identify(
        userId = user.id,
        traits = mapOf(
            "email" to user.email,
            "plan" to user.plan,
            "signup_date" to user.createdAt
        )
    )
    Dijji.setUserProperty("role", user.role)
    Dijji.track("login_completed", mapOf("method" to "phone_otp"))
}

04Rich user data, first-class.

Every event batch the SDK sends carries a full snapshot of device + user + network + power context. The server UPSERTs one row per install with the freshest values — so you segment against one well-indexed table, not scans over millions of events.

User identity
  • visitor_id (stable per install)
  • user_id (post-identify)
  • Merged trait bag — email, plan, MRR, signup_date, any custom key
  • Super-properties that persist across sessions
Lifecycle
  • sessions_count, events_count
  • first_seen_at, last_seen_at
  • days_since_install
  • session_sequence (is this session #5 or #500?)
Device + app
  • os_version, device_model, device_mfr
  • app_version (latest seen)
  • install_source (play_store / amazon / sideload)
  • sdk_version
Display + a11y
  • screen_width_px, screen_height_px, screen_density
  • orientation (portrait / landscape)
  • dark_mode (target light / dark audiences)
  • font_scale (accessibility signal)
Network + geo
  • network_type (wifi / cellular / none)
  • carrier (Jio / Airtel / Verizon / …)
  • locale, timezone
  • country, city — resolved server-side
System health
  • battery_level (0–100), battery_charging
  • memory_total_mb, memory_free_mb
  • disk_free_mb
  • Crash-free rate per app_version

Targeting a low-memory user on 3G at 15% battery becomes a one-line segment query — because every signal is a first-class column, not buried in events.

05Super properties.

Set once, and every future event for this install carries the value. Your dashboard segments filter on these without the app ever re-sending.

// After a successful subscription
Dijji.setUserProperty("plan", "pro")
Dijji.setUserProperty("mrr_inr", 499)

// Now every subsequent track() and screen() carries plan=pro + mrr_inr=499.

06Targeting for marketers, not data engineers.

Type your intent in plain English. Dijji compiles it into a structured rule you can review and refine. No flowcharts, no JSON, no rule builder to master.

How a marketer experiences it: paste intent into the trigger composer, watch it compile, confirm. Edit any field at any time. The dev never sees it.

Examples that compile to real triggers

“When a user opens the app 3 times but hasn’t started a course, send a push: let’s find your first course
WHEN session_count = 3 AND NOT event_fired("course_started") THEN action=push, copy=ai_generated(intent="first course recommend")
“When a pro user hits the paywall a second time, show a bottom sheet explaining the upgrade”
WHEN screen_view("PaywallScreen") AND event_count("paywall_view") ≥ 2 AND trait("plan") != "pro" THEN action=in_app_bottom_sheet
“When battery < 20% and not charging, pause all non-critical messages until next session”
WHEN context.battery_level < 20 AND NOT context.battery_charging THEN action=silent, pause_non_critical=true
“When a user crashes, send an apology notification next time they open the app”
WHEN crash_recent_session AND event="app_open" THEN action=in_app_banner, copy=ai_generated(intent="apology fix incoming"), once_per_user
Inactive 7+ days, on the Pro plan — re-engage with what’s new”
WHEN days_since_last_seen ≥ 7 AND trait("plan") = "pro" THEN action=push, copy=ai_generated(intent="winback pro user"), per_user_rate=1/30d

What you get, out of the box

CapabilityHow it works
Authoring UINatural-language composer + structured view — no flowcharts to master
Web + mobile in one ruleSame rule engine across platforms; actions adapt to where the user is
AI copy generationClaude-written, per-user context, A/B across variants automatically
Autonomous segment discoveryWeekly surfacing of “here’s a cohort worth targeting”
PricingBundled per workspace — no enterprise sales call

07Trigger + action catalog.

The engine evaluates these against every incoming event and profile snapshot. Mix any matcher with any action.

Matchers · the WHEN

MatcherFires when
screen_viewUser lands on a named screen
screen_sequenceUser hits A → B → C within window
event_firedA named custom event fires
event_count ≥User has fired event ≥ N times ever / in window
session_startFirst event of a new session
session_countUser’s Nth session overall
inactive_daysHasn’t opened in N days
install_referrer_matchCame from specific campaign
push_openedJust tapped a push — chain actions
deep_link_openedCame via a specific deep link
crash_recentCrashed in last session
device_matchManufacturer / model / OS ≤ X
app_version_matchOn version < X (upgrade nudge)
geo_matchCountry / city match
trait_matchtrait.plan = "pro", MRR > 999, etc.
context_matchbattery < X, on_wifi, dark_mode on, low_memory

Actions · the THEN

ActionWhat happens
pushFCM notification (optionally Claude-written per user context)
in_app_bannerTop / bottom strip inside active session, non-blocking. image_url renders 40dp thumb.
in_app_bottom_sheetMaterial bottom sheet with optional 16:9 hero image, cards + buttons
in_app_modalFull-screen overlay for critical prompts, optional 16:9 image
in_app_hero v1.2Full-bleed takeover dialog — 4:3 image, gradient veil, primary + secondary CTA
in_app_nps v1.20–10 colour-graded score sheet, fires __dijji_nps_submitted with score
in_app_reactions v1.2Emoji feedback bar (2–5 emojis), fires __dijji_reaction_submitted
in_app_countdown v1.2Live ticker urgency modal, ISO/relative deadline, optional ended_text
in_app_chatGhost Bot opens as a chat sheet
deep_linkNavigate the app to a specific screen
silentLog outcome only — ghost arm for A/B learning

08Kill switch + phased rollout.

Production-safe from day one. You don’t need an app update to disable Dijji — flip mobile_enabled in site settings and every SDK instance silently stops within 30 seconds. The server enforces the same toggle as a backstop.

Phased rollout: ship with rollout_pct = 1, let a few installs warm things up, ramp 5 → 25 → 50 → 100 as crash-free rate holds. SDK hashes visitor_id mod 100 so the same device stays on the same side of the gate across restarts.

// Overrides, all optional — sensible defaults baked in
Dijji.init(this, siteKey = "ws_abc123") {
    autoCaptureScreens = true         // default on
    sessionTimeout = 30.minutes      // industry norm
    flushInterval = 30.seconds       // how often queue sends
    maxQueueSize = 500               // offline cap
    captureCrashes = true
    captureInstallReferrer = true
    debugLogging = false             // turn on for development
}

09Push + in-app messages.

Both are driven by the same trigger engine — no second product, no second dashboard.

Push · FCM

In-app messages

10Privacy.

11Troubleshooting.

Events aren’t landing on the dashboard

Crash-free rate seems wrong

The app size jumped

12Roadmap.

MilestoneETAWhat ships
v1.0 (alpha)LiveCore ingestion, rich user data, auto-capture, install referrer, kill switch
v1.12 weeksUniversal in-app renderers, FCM push dispatcher, ProGuard mapping upload
v1.24 weeksAI trigger composer (natural-language → rule), visual rule builder, Ghost Bot mobile chat
v1.36 weeksNDK crash handler, Room-backed offline queue, Navigation screen naming
v1.48 weeksiOS SDK parity, Flutter + React Native wrappers, Unity evaluation
v2.0TBDThe Brain — realtime autonomous decisioning, weekly outcome learning loop