Skip to content

feat(audience): stamp consent level on Unity SDK messages#812

Open
JCSanPedro wants to merge 2 commits into
mainfrom
feat/unity-consent-level
Open

feat(audience): stamp consent level on Unity SDK messages#812
JCSanPedro wants to merge 2 commits into
mainfrom
feat/unity-consent-level

Conversation

@JCSanPedro

Copy link
Copy Markdown
Contributor

What

  • Stamps the current consent level onto every Unity SDK message in MessageBuilder.BuildBase() (threaded through Track/Identify/Alias), serialized as consentLevel (none/anonymous/full) to match the API.
  • On a Full → Anonymous downgrade, queued track messages now have consentLevel rewritten to anonymous alongside the existing userId strip — in both the in-memory EnqueueChecked transform and the on-disk DiskStore rewrite. The disk rewrite also normalises events persisted before consentLevel existed.

Why

Consent level is being plumbed end-to-end through the pipeline (SDK → audience ingest → attribution → postbacks) as part of SDK-449. Attribution currently infers consent from the presence of a userId, which cannot distinguish full-but-unidentified traffic from genuinely anonymous traffic. Sending the decided level explicitly lets the backend record provenance rather than guess.

This is the Unity half of SDK-565, mirroring the web/pixel SDK change (ts-immutable-sdk) and the audience-service ingest/derivation side (SDK-554, already landed and accepting the field as optional). Non-breaking, forward-compatible.

Notes:

  • Every build/enqueue path is consent-guarded (CanTrack/CanIdentify), so the stamped level is always a decided, sendable value (anonymous/full) — never none. Unity's ConsentLevel enum has no not_set (which the API rejects), so it can never be emitted.
  • The EnqueueChecked transform re-stamps under the drain lock so consentLevel reflects consent at enqueue time, closing the build→enqueue race the same way the existing userId strip does.

End-to-end validation (dev)

Ran the audience sample app against the dev environment and drove the consent flow (init full, identify, downgrade to anonymous). Confirmed in BigQuery (dev-im-cdp.cdp_raw.events) that every event emitted by this SDK carries consent_level, and can be identified as Unity traffic via surface = 'unity' (context.library = com.immutable.audience):

▶ bq query --project_id=dev-im-cdp --use_legacy_sql=false '
SELECT
  publish_time,
  JSON_VALUE(data, "$.type")                   AS type,
  JSON_VALUE(data, "$.eventName")              AS event_name,
  JSON_VALUE(data, "$.surface")                AS surface,
  JSON_VALUE(data, "$.context.library")        AS library,
  JSON_VALUE(data, "$.context.libraryVersion") AS library_version,
  JSON_VALUE(data, "$.anonymous_id")           AS anonymous_id,
  JSON_VALUE(data, "$.user_id")                AS user_id,
  JSON_VALUE(data, "$.consent_level")          AS consent_level,
  JSON_VALUE(data, "$.test")                   AS test
FROM `dev-im-cdp.cdp_raw.events`
WHERE JSON_VALUE(data, "$.anonymous_id") = "b2dca53a-9608-4e05-84b4-d35c13d8e76d"
ORDER BY publish_time DESC
LIMIT 100;'
Waiting on bqjob_r34ba1b3e1dd9c92_0000019f209c0245_1 ... (0s) Current status: DONE   
+---------------------+----------+------------+---------+------------------------+-----------------+--------------------------------------+---------+---------------+------+
|    publish_time     |   type   | event_name | surface |        library         | library_version |             anonymous_id             | user_id | consent_level | test |
+---------------------+----------+------------+---------+------------------------+-----------------+--------------------------------------+---------+---------------+------+
| 2026-07-02 02:13:44 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | anonymous     | true |
| 2026-07-02 02:13:44 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | anonymous     | true |
| 2026-07-02 02:13:43 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | anonymous     | true |
| 2026-07-02 02:13:43 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | anonymous     | true |
| 2026-07-02 02:13:08 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | john    | full          | true |
| 2026-07-02 02:13:08 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | john    | full          | true |
| 2026-07-02 02:12:08 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | john    | full          | true |
| 2026-07-02 02:12:07 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | john    | full          | true |
| 2026-07-02 02:12:07 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | john    | full          | true |
| 2026-07-02 02:12:07 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | john    | full          | true |
| 2026-07-02 02:12:07 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | john    | full          | true |
| 2026-07-02 02:11:52 | identify | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | john    | full          | true |
| 2026-07-02 02:11:27 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | full          | true |
| 2026-07-02 02:11:27 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | full          | true |
| 2026-07-02 02:11:27 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | full          | true |
| 2026-07-02 02:11:17 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | full          | true |
| 2026-07-02 02:11:12 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | full          | true |
| 2026-07-02 02:11:12 | track    | NULL       | unity   | com.immutable.audience | 0.5.0           | b2dca53a-9608-4e05-84b4-d35c13d8e76d | NULL    | full          | true |
+---------------------+----------+------------+---------+------------------------+-----------------+--------------------------------------+---------+---------------+------+

JCSanPedro and others added 2 commits July 2, 2026 13:49
Stamp the current consent level onto every message in MessageBuilder.BuildBase
(threaded through Track/Identify/Alias), so the backend records the explicit
level rather than inferring it from userId presence. Every build/enqueue path
is consent-guarded, so only decided levels (anonymous/full) are ever stamped.

On a Full -> Anonymous downgrade, queued track messages now have consentLevel
rewritten to anonymous alongside the existing userId strip — in the in-memory
EnqueueChecked transform and the on-disk DiskStore rewrite (which also
normalises events persisted before consentLevel existed).

Mirrors the web/pixel SDK change (SDK-565) and the audience-service ingest
side (SDK-554).

Co-authored-by: Cursor <cursoragent@cursor.com>
@JCSanPedro JCSanPedro requested review from a team as code owners July 2, 2026 02:32
@JCSanPedro JCSanPedro changed the title feat(audience): stamp consent level in unity sdk messages feat(audience): stamp consent level on Unity SDK messages Jul 2, 2026
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Audience SDK — Build Size

Platform SDK Size Change
Android 0.37 / 20.00 MB +0.00 MB
Windows 0.16 / 20.00 MB +0.00 MB
iOS 8.54 / 20.00 MB +0.02 MB
macOS 0.92 / 20.00 MB +0.02 MB

SDK Size = build minus empty app. Change = vs baseline. Fails if any platform exceeds its absolute size limit.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant