Skip to content

feat: add device-based consent to override MPID-scoped consent#726

Merged
denischilik merged 1 commit into
mainfrom
feat/device-based-consent
Jun 25, 2026
Merged

feat: add device-based consent to override MPID-scoped consent#726
denischilik merged 1 commit into
mainfrom
feat/device-based-consent

Conversation

@denischilik

@denischilik denischilik commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Add device-level consent state

Summary

Adds a device-level consent state that, when set, supersedes user/MPID-level consent everywhere consent is evaluated. Previously consent could only be recorded per-user (per-MPID), meaning consent decisions were lost across identity changes and couldn't represent a single device-wide choice. This adds an optional device-scoped consent that takes precedence over per-user consent.

When device consent is set, it overrides user/MPID-level consent for:

  • Kit enablement — consent forwarding rule evaluation (shouldIncludeFromConsentRules)
  • Consent forwarding to kitsonConsentStateUpdated forwarded calls
  • Uploads — the consent block included in batches, for all MPIDs

It is persisted device-wide (independent of the active MPID, stored in app-level SharedPreferences) and setting it triggers the same kit refresh as a user consent change. Set it to null to clear and revert to user/MPID-level consent.

MParticleOptions.deviceBasedConsentEnabled(true) additionally mirrors MParticleUser.setConsentState() into device storage, so existing consent-prompt code continues to work without changes when the MPID changes during checkout.

How it works

A new getEffectiveConsentState(mpid) on ConfigManager is the single resolution point: it returns the device consent if present, otherwise falls back to the per-MPID consent. All consent-evaluation call sites now route through it.

deviceBasedConsentEnabled is persisted across launches. When enabled, MParticleUserDelegate.setConsentState() writes to both MPID storage and device storage so consent collected on an anonymous profile is retained after identity changes.

Sample code

Enable device mirroring at startup (recommended for consent-before-login flows):

MParticleOptions options = MParticleOptions.builder(context)
        .credentials("KEY", "SECRET")
        .deviceBasedConsentEnabled(true)
        .build();

MParticle.start(options);
val options = MParticleOptions.builder(context)
    .credentials("KEY", "SECRET")
    .deviceBasedConsentEnabled(true)
    .build()

MParticle.start(options)

Set / update / clear at runtime:

// Set device-wide consent (supersedes any per-user consent)
ConsentState consent = ConsentState.builder()
        .addGDPRConsentState("data_sharing", GDPRConsent.builder(true)
                .document("privacy_policy_v3")
                .build())
        .build();
MParticle.getInstance().setDeviceConsentState(consent);

// Clear it — reverts to user/MPID-level consent
MParticle.getInstance().setDeviceConsentState(null);
// Set device-wide consent (supersedes any per-user consent)
val consent = ConsentState.builder()
    .addGDPRConsentState(
        "data_sharing",
        GDPRConsent.builder(true).document("privacy_policy_v3").build(),
    )
    .build()
MParticle.getInstance().setDeviceConsentState(consent)

// Clear it — reverts to user/MPID-level consent
MParticle.getInstance().setDeviceConsentState(null)

Testing

Added unit tests covering device-consent override precedence and flag persistence (ConfigManagerTest), and updated the public API surface count (ApiVisibilityTest).

Related iOS PR: mParticle/mparticle-apple-sdk#784

Enables Inspire-style flows where consent is collected before MPID changes at checkout, so kit forwarding rules and uploads keep the correct consent state.
@denischilik denischilik requested a review from a team as a code owner June 25, 2026 13:53
@cursor

cursor Bot commented Jun 25, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Changes how consent is resolved for event uploads and kit forwarding—privacy/compliance-critical paths—with new persisted override behavior that apps may enable via options.

Overview
Adds device-level consent that can override per-MPID consent for kit forwarding rules and upload batches—addressing cases where MPID changes (e.g. after identify) would otherwise drop consent set on an anonymous profile.

New public surface: MParticle.getDeviceConsentState() / setDeviceConsentState() (clear with null), isDeviceBasedConsentEnabled(), and MParticleOptions.Builder.deviceBasedConsentEnabled(). When that option is on, existing MParticleUser.setConsentState() also mirrors consent to device storage without extra app calls.

ConfigManager persists device consent and the enabled flag in SharedPreferences and exposes getEffectiveConsentState(mpid); reads/writes for user consent, batch uploads (MessageBatch), and kit updates now use the effective state. Unit tests cover override behavior and flag persistence; changelog documents the feature.

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

@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 1 potential issue.

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 2e277cd. Configure here.

return getDeviceConsentState();
}
return getConsentState(mpid);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale device consent without flag

Medium Severity

After deviceBasedConsentEnabled is off at startup, a device consent value previously written by mirrored setConsentState can remain in preferences. getEffectiveConsentState still prefers that stored device consent, but setConsentState no longer updates device storage, so MPID consent changes may not reach kit forwarding or uploads.

Additional Locations (1)
Fix in Cursor Fix in Web

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

@denischilik denischilik merged commit e92d352 into main Jun 25, 2026
15 checks passed
@denischilik denischilik deleted the feat/device-based-consent branch June 25, 2026 16:20
@sonarqubecloud

Copy link
Copy Markdown

mparticle-automation added a commit that referenced this pull request Jun 25, 2026
## [5.80.0](v5.79.2...v5.80.0) (2026-06-25)

### Features

* add device-based consent to override MPID-scoped consent ([#726](#726)) ([e92d352](e92d352))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants