{"id":21762089,"url":"https://github.com/segment-integrations/analytics-kotlin-consent","last_synced_at":"2025-03-21T04:41:43.537Z","repository":{"id":199970198,"uuid":"684162339","full_name":"segment-integrations/analytics-kotlin-consent","owner":"segment-integrations","description":null,"archived":false,"fork":false,"pushed_at":"2024-07-09T17:13:16.000Z","size":306,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-26T01:20:04.780Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/segment-integrations.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-28T15:25:31.000Z","updated_at":"2024-07-05T19:45:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"e0546ff8-5712-4257-b94e-aa9b3f655e4f","html_url":"https://github.com/segment-integrations/analytics-kotlin-consent","commit_stats":null,"previous_names":["segment-integrations/analytics-kotlin-consent"],"tags_count":11,"template":false,"template_full_name":"segment-integrations/analytics-kotlin-destination-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/segment-integrations%2Fanalytics-kotlin-consent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/segment-integrations%2Fanalytics-kotlin-consent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/segment-integrations%2Fanalytics-kotlin-consent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/segment-integrations%2Fanalytics-kotlin-consent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/segment-integrations","download_url":"https://codeload.github.com/segment-integrations/analytics-kotlin-consent/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244739944,"owners_count":20501990,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-26T12:10:53.697Z","updated_at":"2025-03-21T04:41:43.512Z","avatar_url":"https://github.com/segment-integrations.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Twilio Consent Management \n\nThis plugin provides the framework to integration Consent Management Platform (CMP) SDKs like OneTrust to supply consent status and potential block events going to device mode destinations.\n\n\n## Getting Started\n\nAdd the consent denpendency (which has recently changed):\n\n```kotlin\n  implementation(\"com.segment.analytics.kotlin:consent:\u003cversion\u003e\")\n```\n\nThen add the ConsentManager Plugin to your analytics:\n\n```kotlin\n  import sovran.kotlin.SynchronousStore\n  import com.segment.analytics.kotlin.consent.ConsentManager\n\n  // ...\n\n  // Create the category Provider for your CMP\n  val consentCategoryProvider = MyCmpConsentCategoryProvider(myCmpInstance)\n  val store = SynchronousStore()\n\n  val consentPlugin = ConsentManager(store, consentCategoryProvider)\n\n  analytics.add(consentPlugin)\n\n  // Call this to start event flow.\n  // NOTE: You might want to wait until CMP is ready before you call start()\n  //       so that events are held until the CMP is ready to provide the\n  //       current consent status.\n  consentPlugin.start()\n```\n\n\n\n## Background\n\nConsent Management is the management of a user’s consent preferences related to privacy.  You might be familiar with the Privacy Pop-ups that have become mandated recently that ask the user if he or she consents to the use of certain category of cookies:\n\n![Sample CMP UI](imgs/cmp-sample.png?raw=true \"Sample CMP UI\")\n\n\nThe Privacy pop-up asks the user if he or she will consent to the use of cookies and allows the user to customize their consent by turning on/off different categories of cookies.\n\nAfter the user selects “Allow All” or “Save Preferences” a callback is fired and the owner of the website is notified as to the consent preferences of a given user. The website owner must then store that consent preference and abide by it. Any rejected cookies must not be set or read to avoid large fines that can be handed down by government authorities.\n\nAdditionally, besides the initial pop-up the website owner must give users a way to later change any preferences they originally selected. This is usually accomplished by providing a link to display the customization screen.\n\n\n## Segment managed CMP\n\nSegment provides a framework for users to integrate any CMP they choose and use the Segment web app to map consent categories to device mode destinations. This information is sent down the analytics-kotlin SDK and stored for later lookup.\n\nEvery event that flows through the library will be stamped with the current status according to whatever configured CMP is used. Event stamping is handled by the ConsentManagementPlugin. \n\nUsing consent status stamped on the events and the mappings sent down from the Segment web app each event is evaluated and action is taken. Currently the supported actions are:\n\n- Blocking - This action is implemented by the ConsentBlockingPlugin\n\n## Event Stamping\n\nEvent stamping is the process of adding the consent status information to an existing event. The information is added to the context object of every event. Below is a before and after example:\n\nBefore\n\n```json\n{\n    \"anonymousId\": \"23adfd82-aa0f-45a7-a756-24f2a7a4c895\",\n    \"type\": \"track\",\n    \"event\": \"MyEvent\",\n    \"userId\": \"u123\",\n    \"timestamp\": \"2023-01-01T00:00:00.000Z\",\n    \"context\": {\n        \"traits\": {\n            \"email\": \"peter@example.com\",\n            \"phone\": \"555-555-5555\"\n        },\n        \"device\": {\n            \"advertisingId\": \"7A3CBBA0-BDF5-11E4-8DFC-AA02A5B093DB\"\n        }\n    }\n}\n```\nAfter\n\n```json\n{\n    \"anonymousId\": \"23adfd82-aa0f-45a7-a756-24f2a7a4c895\",\n    \"type\": \"track\",\n    \"event\": \"MyEvent\",\n    \"userId\": \"u123\",\n    \"timestamp\": \"2023-01-01T00:00:00.000Z\",\n    \"context\": {\n        \"traits\": {\n            \"email\": \"peter@example.com\",\n            \"phone\": \"555-555-5555\"\n        },\n        \"device\": {\n            \"advertisingId\": \"7A3CBBA0-BDF5-11E4-8DFC-AA02A5B093DB\"\n        },\n        \"consent\": {\n            \"categoryPreferences\": {\n                \"Advertising\": true,\n                \"Analytics\": false,\n                \"Functional\": true,\n                \"DataSharing\": false\n            }\n        }\n    }\n}\n```\n\n## Segment Consent Preference Updated Event\n\nWhen notified by the CMP SDK that consent has changed, a track event with name “Segment Consent Preference Updated” will be emitted. Below is example of what that event will look like:\n\n```json\n{\n    \"anonymousId\": \"23adfd82-aa0f-45a7-a756-24f2a7a4c895\",\n    \"type\": \"track\",\n    \"event\": \"Segment Consent Preference Updated\",\n    \"userId\": \"u123\",\n    \"timestamp\": \"2023-01-01T00:00:00.000Z\",\n    \"context\": {\n        \"device\": {\n            \"advertisingId\": \"7A3CBEA0-BDF5-11E4-8DFC-AA07A5B093DB\"\n        },\n        \"consent\": {\n            \"categoryPreferences\": {\n                \"Advertising\": true,\n                \"Analytics\": false,\n                \"Functional\": true,\n                \"DataSharing\": false\n            }\n        }\n    }\n}\n```\n\n## Event Flow\n\n\n![Shows how an event is stamped and later checked for consent](imgs/main-flow-diagram.png?raw=true \"Event Flow Diagram\")\n\n1. An event is dropped onto the timeline by some tracking call.\n2. The ConsentManagementPlugin consumes the event, stamps it, and returns it.\n3. The event is now stamped with consent information from this point forward.\n4. The event is copied. The copy is consumed by a Destination Plugin and continues down its internal timeline. The original event is returned and continues down the main timeline.\n   a. The stamped event is now on the timeline of the destination plugin.\n   b. The event reaches the ConsentBlockingPlugin which makes a decision as to whether or not to let the event continue down the timeline.\n   c. If the event has met the consent requirements it continues down the timeline.\n5. The event continues down the timeline.\n\n\n\n\n## Getting Started\n\nTo get started add the dependency for consent management to your app's build.gradle file:\n\n```groovy\n    implementation 'com.segment.analytics.kotlin.destinations:consent:\u003cLATEST_VERSION\u003e'\n```\n\nNext pick from one of the prebuilt integration:\n\n- OneTrust: https://github.com/segment-integrations/analytics-kotlin-consent-onetrust\n\nOr build your own integration (see below)\n\nNext you'll need to write some setup/init code where you have your\nAnalytics setup:\n\n```kotlin\n// Setup Analytics\nanalytics = Analytics(SEGMENT_WRITE_KEY, applicationContext) {\n   this.collectDeviceId = true\n   this.trackApplicationLifecycleEvents = true\n   this.trackDeepLinks = true\n   this.flushPolicies = listOf(\n      CountBasedFlushPolicy(5), // Flush after 5 events\n      FrequencyFlushPolicy(5000) // Flush after 5 Seconds\n   )\n}\n\n// Add the myDestination plugin into the main timeline\nval myDestinationPlugin = myDestinationPlugin()\nanalytics.add(myDestinationPlugin)\n\n// Create the Consent Category Provider that will get the status of consent categories\nval consentCategoryProvider = MyConsentCategoryProvider(cmpSDK)\nval store = SynchronousStore() // Use only a Synchronous store here!\n\nval consentPlugin = ConsentManagementPlugin(store, consentCategoryProvider)\n\n// Add the Consent Plugin directly to analytics\nanalytics.add(consentPlugin)\n\n// Use the CMP SDK to get the list of consent categories.\nconsentCategoryProvider.setCategories(cmpSDK.getCategories())\n\n// Once the categories have been set we can start processing events by starting\n// the Consent Management plugin\nconsentPlugin.start()\n```\n\n## Building your own integration\n\nIn order to integrate a new CMP all you have down is provide to couple of integration points.\n\n### Consent Category Provider\n\nFirst you'll need to create a `ConsentCategoryProvider` that will provide a mapping of consent category to whether or not a given category has been consented by the user.\n\nExample:\n```Kotlin\nclass OneTrustConsentCategoryProvider(\n    val otPublishersHeadlessSDK: OTPublishersHeadlessSDK,\n    val categories: List\u003cString\u003e\n) : ConsentCategoryProvider {\n\n    override fun getCategories(): Map\u003cString, Boolean\u003e {\n        var categoryConsentMap = HashMap\u003cString, Boolean\u003e()\n\n        categories.forEach { category -\u003e\n            val consent = otPublishersHeadlessSDK.getConsentStatusForGroupId(category)\n            val consentValue = when (consent) {\n                1 -\u003e true\n                else -\u003e false\n            }\n\n            categoryConsentMap.put(category, consentValue)\n        }\n\n        return categoryConsentMap\n    }\n}\n```\n\nHere we show how OneTrust is integrated. As you can see it uses a passed in list of categories to query the OneTrust SDK and maps the OneTrust response (-1, 0, or 1) to true/false.\n\n### Consent Changed Notifier\nThe second and last integration point is a way to notify the ConsentManagementPlugin that consent has changed for the user.\n\nHere is an OneTrust example:\n```kotlin\npackage com.segment.analytics.kotlin.destinations.consent.onetrust\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport com.onetrust.otpublishers.headless.Public.Keys.OTBroadcastServiceKeys\nimport com.segment.analytics.kotlin.destinations.consent.ConsentManagementPlugin\nimport java.lang.ref.WeakReference\n\nclass OneTrustConsentChangedNotifier(\n    val contextReference: WeakReference\u003cContext\u003e,\n    val categories: List\u003cString\u003e,\n    val consentPlugin: ConsentManagementPlugin\n) {\n\n    private val consentChangedReceiver: BroadcastReceiver? = null\n\n    fun register() {\n        if (consentChangedReceiver != null) {\n            unregister()\n        }\n\n        val context = contextReference.get()\n        categories.forEach {\n\n            if (context != null) {\n                context.registerReceiver(\n                    OneTrustConsentChangedReceiver(consentPlugin),\n                    IntentFilter(OTBroadcastServiceKeys.OT_CONSENT_UPDATED)\n                )\n            }\n        }\n    }\n\n    fun unregister() {\n        val context = contextReference.get()\n        if (context != null) {\n            context.unregisterReceiver(consentChangedReceiver)\n        }\n    }\n}\n\nclass OneTrustConsentChangedReceiver(val consentPlugin: ConsentManagementPlugin) :\n    BroadcastReceiver() {\n    override fun onReceive(context: Context?, intent: Intent?) {\n        consentPlugin.notifyConsentChanged()\n    }\n}\n```\n\nHere we can see that the OneTrust SDK notifies us of consent change via an Android Intent with the action `OTBroadcastServiceKeys.OT_CONSENT_UPDATED` so our notifier must create a broadcast receiver and listen for this event. One the event is broadcast the reciever will then call `consentPlugin.notifyConsentChanged()` to let the ConsentManagmentPlugin to send the `Segment Consent Preference Updated` event.\n\n\n## License\n```\nMIT License\n\nCopyright (c) 2023 Segment\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsegment-integrations%2Fanalytics-kotlin-consent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsegment-integrations%2Fanalytics-kotlin-consent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsegment-integrations%2Fanalytics-kotlin-consent/lists"}