SDKsAndroid

Changelog

Version history and release notes for the Android SDK.

Version 1.0.0 (September 15, 2026)

1.0.0 is now stable and no longer in beta. Update your dependency to the stable release. Upgrading from 0.x? Follow the migration guide.

Version 1.0.0-beta.1 (August 25, 2026)

First release of the 1.0 line — the 1.0 API is frozen, published as a beta on Maven Central; pin the exact version. The full 0.x → 1.0 upgrade path is in the migration guide.

Highlights

  • One unified request surface. The legacy query-string ad path is gone — every fetch now goes through requestAd / prefetchAd / cancelPrefetchAd with a KoahAdContext, completing the migration the 0.x line deprecated.
  • Correct device classification. Every request now sends a real User-Agent (the device's WebView agent plus a Koah/<version> product token), so requests are attributed to the right OS and device type — which can improve targeting and fill.
  • Viewability counts foreground time only. The KoahEvent.AdViewed dwell timer resets when the host app is backgrounded (home button, screen off, or a covering activity) — after resume the ad needs a fresh continuous second on screen — so viewed events fire only for time the ad actually spent in the foreground. Impression tracking is unchanged.
  • Under-13 ages are rejected. setAge / setAgeRange ignore under-13 values with a warning, and a previously persisted under-13 value is discarded on upgrade.

Breaking changes

  • Removed Koah.prefetch, Koah.resolveAd, and Koah.cancelPrefetch — use prefetchAd / requestAd / cancelPrefetchAd with a KoahAdContext and cacheKey.
  • Removed the legacy KoahCard / KoahAd overloads taking query / queryResponse / messageId / conversationId, and the deprecated overloads taking modifier / overrideMaxWidth / overrideMaxHeight — use the adContext overloads with width / height: KoahAxisSize and padding.
  • Renamed the messageId parameter to cacheKey on the cache-reading KoahCard overload and the sample-ad KoahCard / KoahAd overloads — binary-compatible, but source-breaking for callers passing the argument by name.

Version 0.3.0 (August 13, 2026)

Highlights

  • Per-axis slot sizing. KoahCard / KoahAd gain width and height parameters of the new KoahAxisSize type — each axis can be unbounded (wrap), range(min, max), fixed(dp), or fill(). The SDK offers the server only the format variants that fit the resolved bounds, sends a text-length budget for card_text_md so copy is sized to the slot, and an ad that can't fit a bounded axis derenders (KoahEvent.SlotTooSmall) instead of clipping. The old overrideMaxWidth/overrideMaxHeight overloads still work but are deprecated.
  • requestAd now returns a sealed KoahAdResult — Filled / NoFill / Error — so callers can branch over success, no-fill, and failure, which were previously indistinguishable.
  • Koah's servers can now pick which small image-card treatment a fill renders: today's image-leading control, a labelled action button, a trailing square image, or a content-first layout with a full-height 1.91:1 creative, inline advertiser identity, one headline, and the existing chevron. The selection arrives with the ad; anything this SDK doesn't recognise renders the control. Every fill keeps rendering today's image-leading control until the selection is turned on server-side, so this release changes nothing on its own. Your integration is unchanged: no new format names appear in the ad's format, no new content fields were added, and the SDK gains no new dependency, configuration, or setup step.
  • Demographic targeting: gender and household income. Call Koah.instance.setGender(KoahGender.FEMALE) and Koah.instance.setIncomeBracket(KoahIncomeBracket.INCOME_50K_TO_100K) (brackets are annual household income in thousands of USD). Values are persisted locally and uploaded for ad targeting. Pass UNKNOWN to stop this device storing and re-sending a value — a local clear only; it does not delete a value already sent to Koah. This completes the demographic set alongside setAge / setAgeRange.

Breaking changes

  • minSdk is now 23 (Android 6.0), up from 21. Apps with minSdk 21/22 must raise it to consume 0.3.0.
  • The SDK's HTTP stack moved to OkHttp 5 (5.4.0) and the library is built with Kotlin 2.4. No integration change for most apps, but projects pinning OkHttp 4.x transitively will resolve 5.x alongside this SDK.
  • Logging is configured with logLevel: KoahLogLevel (NONE/ERROR/WARNING/INFO/DEBUG) — the boolean debug flag is gone.
  • The t-shirt size API is gone. The server returns an opaque format; slot bounds (via KoahAxisSize) narrow what is offered. KoahAdSize, KoahAdOptions, and size-taking overloads are removed.
  • Preview requests are spelled requestPreviewAd(previewFormat, cacheKey) — the requestAd(previewFormat) overload is removed.
  • The raw ad-content model is no longer public. The supported path returns KoahAdResult and renders via KoahCard / KoahAd; use the new public KoahSampleAd family for previews and fixtures.
  • Internalized: KoahEnvironment / KoahEnvironmentManager (set baseUrl directly), KoahAdSizeConstraints, and other leaked internals; the unused KoahEvent.InlineProductNameClicked case is removed.

Improvements

  • Impressions are gated on real visibility. Impressions fire when the card first becomes visible in the viewport (and exactly once per served ad), not on composition — scrolled-off-screen fills no longer count.
  • Network hardening. Ad requests and attribute uploads get a uniform retry policy (retry on 500/502/503/504, max 3 attempts, 15s overall deadline, jittered backoff, Retry-After honored when ≤ 2s) plus per-attempt timeouts; tracking calls stay single-attempt. Every failure degrades silently — ads just don't show — and a plain-http baseUrl now logs a security warning.
  • Expandable ads are never bricked. The expanded body prefetches on fill, a failed fetch retries once on tap, and if it still fails the card falls back to its CTA. The expanded body also fades at the bottom edge until fully scrolled.
  • Small card layout: advertiser identity leads and the ad image trails on the text variant, and card_image_sm stays the image-leading control.
  • A blank/whitespace publisherId now fails fast at first init (IllegalArgumentException) instead of silently disabling ads; duplicate init calls still warn and no-op.

API changes

⚠️ Removed

  • Ad-content model, fixture overloads, and internal primitives leave the public surface — the server-decoded ad-content model is no longer public; the supported path returns KoahAdResult/state and renders via KoahCard/components. Breaking.
  • Remove unused KoahEvent.InlineProductNameClicked — the case was never emitted, so a consumer's onEvent handler had a dead when branch. Breaking.
  • Internalize KoahAdSizeConstraints — the medium card's render-envelope bounds are enforced internally. Breaking.
  • Internalize KoahEnvironment / KoahEnvironmentManager — set baseUrl directly. Breaking.
  • Internalize leaked-public internals — symbols public on Android but internal on the other SDKs are hidden, shrinking the surface to the intended contract. Breaking.
  • Remove deprecated legacy ad-state/query APIs — the hooks and query-based entry points superseded by KoahAdContext are removed (hard, no shim). Breaking.
  • Withdraw unreleased Category Rail and Photo Stack formats — removed before their first stable release; no released consumer loses API.

⚠️ Changed

  • Sizeless opaque format ladder; drop the size/capability API — the server returns an opaque format name and slot bounds narrow the offer; KoahAdSize, KoahAdOptions, and size-taking overloads are gone. Breaking.
  • Per-axis slot sizing (KoahAxisSize) — KoahCard/KoahAd gain width/height axis parameters replacing the max-only overrideMaxWidth/overrideMaxHeight knobs (now deprecated shims). The axis-sizing overloads also drop the raw modifier: Modifier parameter in favor of a dedicated padding: move Modifier.padding(…) to padding = …, express width and height through width/height, and wrap the card in your own composable for anything else you were applying (alignment, semantics). Breaking.
  • Sealed/discriminated KoahAdResult (Filled / NoFill / Error) — requestAd returns a closed three-case set instead of a filled flag; the result's format field is gone. Breaking.
  • Logging config is a real KoahLogLevel enum — NONE/ERROR/WARNING/INFO/DEBUG replaces the boolean debug knob. Breaking.
  • Rename the preview ad request to requestPreviewAd — previously folded into a requestAd(previewFormat:) overload. Breaking.
  • Raise Android minSdk to 23. Breaking.

Added

  • Public KoahSampleAd family for fixture / preview rendering — a hand-constructable mirror of the internal ad-content model for previews, demo galleries, and snapshot fixtures.
  • card_text_md text-length budget + clip-driven derender — the client sends a per-slot text budget and derenders (SlotTooSmall) instead of clipping.
  • Gender and household-income targeting — setGender / setIncomeBracket upload as their own attribute dimensions alongside age.

Version 0.2.1 (June 23, 2026)

Highlights

  • Ad disclaimers. When an ad carries disclaimer text, KoahCard now shows an info (ⓘ) affordance after the "Sponsored" label that opens a disclaimer bottom sheet. Surfaced on the model as the new nullable KoahAd.disclaimer; the affordance renders automatically with no integration changes.

Improvements

  • Advertiser icons render more gracefully. Icons now show a grey skeleton while loading and fall back to a bundled default advertiser mark when there's no icon URL or the image fails to load, instead of rendering an empty space.
  • /client/info uploads are debounced. Device info is now uploaded only when it changes since the last successful send (via a new internal client-info manager), instead of on every launch — fewer redundant network calls.

Version 0.2.0 (June 5, 2026)

Highlights

  • AdMob mediation plumbing is finalized. This release lands the core internals the new koah-android-admob companion adapter links against, so the adapter can ship for the first time. (0.1.0 introduced the public AdMob mediation story; the adapter itself depends on the request-path changes in this release.)

Improvements

  • Reworked the internal ad-request path used by AdMob mediation: ad-context extras are now encoded/decoded through KoahAdRequestPayload, and Koah.fetchAdMobAd takes a single request value.

Version 0.1.0 (June 4, 2026)

Highlights

  • Pixel-precise ad sizing with KoahDimensions. requestAd / prefetchAd and the card composables now take explicit slot constraints — pass overrideMaxWidth / overrideMaxHeight (in dp) on KoahCard / KoahAd, or a KoahDimensions(maxWidth, maxHeight) value on the request, to bound an ad to your layout. Each axis is independent; omit both for an unbounded slot. Replaces the coarse t-shirt-size buckets with exact dimensions.
  • AdMob mediation via the new koah-android-admob companion library. A separate com.koahlabs:koah-android-admob artifact renders Koah creatives inside Google AdMob native ad slots, so publishers already on AdMob can serve Koah ads through their existing mediation stack.

Improvements

  • size deprecated in favor of dimensions. The KoahAdSize t-shirt-bucket parameter on requestAd / prefetchAd / the card composables, and KoahAdOptions.size, now emit a deprecation warning. Existing call sites keep compiling — migrate to overrideMaxWidth / overrideMaxHeight (or omit for unbounded). size will be removed in a future release.
  • Unified impression & visibility tracking. Internal visibility bookkeeping now follows the same gating semantics as iOS, Flutter, and React Native, so impression and viewed-event timing for partially-occluded or de-rendered cards is consistent across all SDKs.

Version 0.0.17 (May 29, 2026)

Highlights

  • Ad report flow. Tapping the new ellipsis in the medium ad-card header opens an M3 ModalBottomSheet (About this ad → Report this ad with five radio reasons + Submit) that posts to POST /k/report. No new public API surface and no opt-in — the affordance ships on every standard KoahCard. Sheet auto-adapts to system light/dark via the ambient KoahTheme.
  • Optional slot parameter. Koah.instance.requestAd(adContext, size, cacheKey, slot) and prefetchAd(...) now accept an optional slot: String? that surfaces in matching and reporting. Lets a single page tag multiple distinct ad placements without colliding on the cache key or muddying analytics.
  • previewFormat for publisher format previews. New Koah.instance.previewFormat(...) returns a deterministic sample creative for a given format (SMALL / MEDIUM / EXPANDABLE / POLL), so publishers can wire their preview UIs without depending on live fill.
  • Optional experimentTag. New experimentTag: String? parameter on requestAd / prefetchAd is forwarded with every ad request, letting publishers split-test creatives or surface variants without piggy-backing on the cache key.
  • Small card trailing chevron. Compact small-card variant now renders a trailing › chevron, reinforcing that the whole card is one tap target and matching the web SDK.
  • Poll CTA with animated reveal. Clickable poll CTA reveals the post-vote state with a word-by-word blur-reveal animation gated on 50% visibility, matching the expandable format's reveal pattern.

Improvements

  • adText removed from publisher-facing fill events. Tracking events no longer leak ad copy to the publisher's analytics surface.

Version 0.0.16 (May 12, 2026)

Highlights

  • Unified requestAd API. New Koah.requestAd(adContext, size, cacheKey), Koah.prefetchAd(adContext, size, cacheKey), and Koah.cancelPrefetchAd(cacheKey), plus a discriminated KoahAdContext (Conversation / Article / Feed / Static) and a KoahAdResult(filled, fromCache, format) return type. New KoahCard(adContext = ..., cacheKey = ...) and KoahAd(adContext = ..., cacheKey = ...) overloads route through the same path. Migration: the pre-0.0.16 Koah.fetchAd / prefetch / resolveAd / cancelPrefetch entry points and the v1 KoahCard / KoahAd overloads still work but emit deprecation warnings; new code should adopt the unified API.
  • KoahTheme styling API (breaking). Replaces the previous 13-knob KoahCardStyle with a tight 4-knob KoahTheme applied via ProvideKoahTheme. Knobs: colorScheme (LIGHT / DARK / AUTO), accentColor (defaults to #0D0D0D; on-accent text is auto-contrasted via WCAG luminance), fontFamily (null inherits from the host app), and cornerRadius (default 19.dp). ProvideKoahTheme calls nest, so subtree overrides work naturally.
  • Borderless KoahAd composable. New chrome-less variant that renders inline in a chat row, comment cell, or any host surface that already provides framing. Same props and event behavior as KoahCard.
  • Expandable and Poll ad formats. Expandable renders a clipped preview that blur-reveals word-by-word into the full body on tap (gated on 50% visibility). Poll renders an interactive multi-choice prompt with server-tracked option events. Both are returned by the existing requestAd call when the server picks them — no client-side opt-in.
  • Compact small card. New KoahAdSize.SMALL spec: 14dp padding, ~19dp corners, thin outline, whole-card tap target.
  • Post-click survey. When the server attaches on_click_actions: [{ type: "survey" }] to an ad, tapping the CTA shows a survey card (question + pill options + countdown auto-navigate) that crossfades in-place before opening the ad link. Forward-compatible: unknown action types silently no-op.

Improvements

  • Strict size matching. KoahAdOptions.size is enforced as a hard match against the server's ad.size. The SDK also declares the formats it can render on every request, so the server stops returning formats this client can't draw.
  • Production-key debug warning. When debug = true but the configured publisherId looks like a production key, the SDK logs a clear warning on no-fill so integrators don't silently think their staging setup is broken.
  • Cross-platform /client/info parity. Android now sends the same device-info superset as iOS, Flutter, and React Native, so backend personalization decisions are consistent across platforms.

About versions 0.0.10–0.0.15

These versions were published to Maven Central without curated changelog entries. The 0.0.16 entry above is the consolidated changelog covering everything that landed since 0.0.9.

Version 0.0.9 (September 11, 2025)

  • Added browser warmup for improved speed when opening ad links in the in-app browser
  • Added optional conversationID parameter for enhanced tracking and analytics

Version 0.0.8 (September 5, 2025)

  • Added new email form fill ad format for lead capture directly within ads
  • Introduced Koah.identify() and Koah.reset() methods for user identification and improved ad targeting
  • Email auto-fill support for identified users to increase conversion rates
  • Added 7 new event types for email lead forms:
    • EmailLeadFormOpened, EmailLeadCaptured, EmailLeadFormPrematurelyDismissed, EmailLeadValidationFailed
    • EmailAutocompleteLeadFormOpened, EmailAutocompleteLeadCaptured, EmailAutocompleteFormPrematurelyDismissed
  • Added formFieldBorderColor styling option for customizing form input field borders

Version 0.0.7 (July 17, 2025)

  • Updated KoahEvent.AdServed from object to data class with adText property for accessing served ad content
  • Added new KoahEvent.AdClicked event to track user interactions with ads
  • Improved event handling examples to demonstrate all four event types

Version 0.0.6 (June 19, 2025)

  • Breaking Change: Deprecated onImpression callback in favor of new onEvent system
  • Added KoahEvent sealed class with four event types:
    • NoAdFill: Emitted when no ad is available to fill the request
    • AdServed: Emitted when an ad is successfully served and ready to display
    • ImpressionTracked: Emitted when an ad impression has been tracked
  • Enhanced event tracking capabilities for better analytics integration
  • Backward compatibility maintained for existing onImpression implementations
Was this helpful?