Skip to content

feat: Support Braze 42 and recommended eCommerce events#728

Open
nickolas-dimitrakas wants to merge 5 commits into
workstation/6.0-Releasefrom
feat/braze-42-recommended-ecommerce
Open

feat: Support Braze 42 and recommended eCommerce events#728
nickolas-dimitrakas wants to merge 5 commits into
workstation/6.0-Releasefrom
feat/braze-42-recommended-ecommerce

Conversation

@nickolas-dimitrakas

Copy link
Copy Markdown

Background

Braze Android SDK 42.3.0+ introduces recommended eCommerce events (ecommerce.cart_updated, ecommerce.checkout_started, ecommerce.product_viewed, ecommerce.order_placed, ecommerce.order_refunded) as typed SDK APIs that unlock calculated profile fields, eCommerce reporting, and out-of-the-box Canvas templates. This mirrors the iOS work in mparticle-apple-sdk#793.

What changed

  • New braze-42 kit track targeting com.braze:android-sdk-ui:[42.3.0,43.0.0) (namespace appboy42, artifact com.mparticle:braze-42), copied from braze-41.

  • Braze 42 requires Kotlin 2.2.x, so the track is built standalone following the urbanairship-20 convention: excluded from settings-kits.gradle, its own Kotlin 2.2.20 buildscript, and dedicated CI steps in pull-request.yml / daily.yml. Documented in ONBOARDING.md.

  • New opt-in useEcommerceRecommendedEvents setting. When enabled, the six supported mParticle commerce actions map to Braze's recommended events via logEcommerceEvent (and logCustomEvent for ecommerce.order_refunded, which has no typed API):

    mParticle action Braze event
    add_to_cart / remove_from_cart ecommerce.cart_updated (action add/remove)
    checkout ecommerce.checkout_started
    view_detail ecommerce.product_viewed (one per product)
    purchase ecommerce.order_placed
    refund ecommerce.order_refunded
  • When the setting is off (default), commerce forwarding is unchanged. Unsupported actions and events without products fall back to legacy forwarding.

  • Attributes without a direct Braze field (cart_id, checkout_id, source, tax, shipping, product brand/category/coupon_code/position, etc.) are nested in event/product metadata per Braze's strict schema. source is "android".

Testing

  • ./gradlew -Pmparticle.kit.mparticleFromMavenLocalOnly=true -p kits/braze/braze-42 -PisRelease=true testReleaseall 45 unit tests pass (10 new recommended-eCommerce tests covering each mapped event + fallback paths, plus the inherited suite). ktlintCheck clean.
  • Compiles against the real Braze 42.3.1 AAR.

Notes

  • The braze-42 track requires Kotlin 2.2.x; per repo convention it is verified via the isolated standalone build (see ONBOARDING.md), not the multi-kit settings-kits.gradle build.

🤖 Generated with Claude Code

Add a new isolated braze-42 kit track targeting Braze Android SDK 42.x
(com.braze:android-sdk-ui:[42.3.0,43.0.0)). Because Braze 42 requires
Kotlin 2.2.x, the track is built standalone following the urbanairship-20
convention: excluded from settings-kits.gradle, with its own Kotlin 2.2.20
buildscript and dedicated CI steps.

Add an opt-in `useEcommerceRecommendedEvents` setting that forwards the six
supported mParticle commerce actions using Braze's recommended eCommerce
event schema (cart_updated, checkout_started, product_viewed, order_placed,
and order_refunded via logCustomEvent). Legacy commerce forwarding remains
the default; unsupported actions and events without products fall back to it.
Attributes without a direct Braze field are nested in event/product metadata
per Braze's strict schema; source is reported as "android".

Includes unit tests for each mapped event and the legacy fallback paths, and
wires the isolated track into the pull-request and daily CI workflows,
ONBOARDING.md, and CHANGELOG.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@nickolas-dimitrakas
nickolas-dimitrakas requested a review from a team as a code owner July 6, 2026 20:51
@cursor

cursor Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Opt-in commerce mapping changes what Braze receives when enabled; default legacy forwarding limits blast radius, but analytics/reporting parity should be validated for adopters.

Overview
Adds a new braze-42 mParticle kit track for Braze Android SDK 42.x, published as com.mparticle:braze-42 and built standalone on Kotlin 2.2.x (same pattern as other isolated kits). CI in pull-request.yml and daily.yml now lint, ktlint, and run testRelease for kits/braze/braze-42; ONBOARDING.md and CHANGELOG.md document the track.

The kit’s AppboyKit gains an opt-in connection setting useEcommerceRecommendedEvents. When enabled, supported mParticle commerce actions forward via Braze’s logEcommerceEvent schema (cart_updated, checkout_started, product_viewed, order_placed; refunds as ecommerce.order_refunded custom event). Extra fields land in metadata, with source set to android. When the setting is off or the action isn’t mapped, behavior stays on the legacy purchase/custom-event paths.

Includes README, example apps, ProGuard rules, and unit tests (including RecommendedEcommerceTests) with Braze test doubles.

Reviewed by Cursor Bugbot for commit 08563f2. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread kits/braze/braze-42/example/build.gradle Outdated
@nickolas-dimitrakas nickolas-dimitrakas self-assigned this Jul 6, 2026
The example app's applicationId had a duplicated prefix
(com.mparticle.com.mparticle.kits.braze.example) while the manifest package
and the MPReceiver FCM intent-filter category are com.mparticle.kits.braze.example.
Since the effective package equals the applicationId, the push category no
longer matched, so push registration/receipt in the sample app could fail.
Align the applicationId with the package and category.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2e99e2f. Configure here.

Comment thread kits/braze/braze-42/src/main/kotlin/com/mparticle/kits/AppboyKit.kt
Comment thread kits/braze/braze-42/src/main/kotlin/com/mparticle/kits/AppboyKit.kt
buildEventMetadataMap copied every commerce custom attribute into the event
metadata object, including cart_id, checkout_id, and total_discounts, which are
also promoted to typed recommended-event fields. Those values therefore appeared
twice on the outbound event (and total_discounts as an inconsistent string copy).
Exclude the promoted keys from metadata; genuinely custom attributes are
unaffected. Adds assertions covering the dedup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@nickolas-dimitrakas

Copy link
Copy Markdown
Author

Thanks @cursor — addressing both findings from the latest review:

1. "Mapped IDs duplicated in metadata" — fixed (d7a3b3d).
buildEventMetadataMap was copying every commerce custom attribute into metadata, including cart_id / checkout_id / total_discounts, which are also promoted to typed recommended-event fields — so they appeared twice (and total_discounts as an inconsistent string copy). Those promoted keys are now excluded from metadata; genuinely custom attributes are unaffected. Added assertions covering the dedup. The same fix has been applied to the Android appboy-kit and Web kit PRs for cross-platform consistency.

2. "SKU replacement flag ignored" — working as intended, no change.
The legacy replaceSkuWithProductName flag exists because Braze's legacy logPurchase(...) has only a single product-identifier argument, so customers with opaque SKUs flip it to surface the product name in that one slot. Braze's recommended schema instead carries two distinct fields — product_id (stable identifier) and product_name (display label) — so the kit sets product_id = sku and product_name = name unconditionally. Honoring the legacy flag here would write a display name into product_id, which contradicts the recommended-event schema and diverges from the iOS implementation (mparticle-apple-sdk#793), which also maps skuproduct_id and nameproduct_name unconditionally. The flag is a legacy single-field workaround that no longer applies once both fields are sent, so it is intentionally not consulted on the recommended path.

@BrandonStalnaker BrandonStalnaker left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Matches what was done on the iOS side as expected. AI recommended some cleanup that might be worth it but isn't necessary to merge

Comment thread kits/braze/braze-42/src/main/kotlin/com/mparticle/kits/AppboyKit.kt
…728-work

# Conflicts:
#	.github/workflows/daily.yml
#	.github/workflows/pull-request.yml
#	ONBOARDING.md
Explicitly declare android:exported on components with intent-filters
(MPReceiver, MainActivity) and android:usesCleartextTraffic="false" on both
example apps' <application> tags. Also flips the Kotlin example's
allowBackup to false to match the Java example and avoid disabling backup
review flags.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
25.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants