02 · POST_CONSENT — Onay Kayıt Sözleşmesi
Görev: Kullanıcının onay ekranındaki seçimini (
Tümünü Kabul Et/Zorunlu Olanlar/Tercihleri Düzenle) sunucuya iletir. Sunucu karşılığında onay kaydını oluşturur/günceller, etkinleşen onay kararlarını döndürür ve yeni cihaz durumunu (localState) verir.Ne zaman çalışır: Kullanıcı onay ekranında bir seçim yaptığında (AUTH → config → ekran → burada).
Bu dosya iki şeyi kapsar: (A) sözleşme (istek/yanıt, doğrulama, hata) ve (B) onayın etiketlere (GA4/GTM) dağıtımı + iOS ATT katmanı.
1. Genel Bakış
POST_CONSENT, açılış döngüsünün son halkasıdır ve döngüyü kapatır: kullanıcının seçimi kaydedilir, sunucu otoriter son durumu döndürür, SDK bu durumu etiketlerine uygular ve yeni localState'ı önbelleğe yazar — bir sonraki açılışta AUTH'a geri beslenir.
Tasarım felsefesi: Onay, grubun kimliği (groupId) seviyesinde verilir. Bir grup onaylanınca, config'deki o grubun consentKeys listesindeki etiketlerin tümü birlikte açılır; grup kapalıysa tümü birlikte kapanır. Item/teknoloji seviyesinde ayrı onay durumu yoktur. Sunucu yalnız grubun kimliği + son durumu ({ [groupId]: state }) taşır; bu haritanın etiketlere çevrilmesi SDK/entegrasyon tarafında yapılır.
AUTH (00) GET /config (01) POST_CONSENT (BU)
kimlik + localState ▶ token ─▶ tam config ────▶ onay kaydı
│ token │ parse → ekrandaki seçim │ request: actionType + consent map
└── decision.updateRequired ┘ (aynı token) │
│
bir sonraki AUTH ◀─────────── response: consentRecordId + consent + localState
2. Endpoint & Güvenlik
2.1 Endpoint
| Özellik | Değer |
|---|---|
| Method | POST |
| Path | /v2/consent/{consentId}/consent |
| Base URL | {{SDK_BASE_URL}} |
| Gövde formatı | application/json (UTF-8) |
| Timeout | 15 sn |
| Idempotent | Evet — aynı eventId/onay eylemi tekrar gönderilirse aynı kaydı günceller, mükerrer kayıt üretmez. |
2.2 Güvenlik (imza + token)
POST_CONSENT bir YAZMA işlemidir (durumu değiştirir) → bu yüzden hem AUTH'tan alınan token hem HMAC imza birlikte kullanılır:
| Header | Değer / Formül |
|---|---|
Content-Type | application/json |
X-Consent-Token | AUTH yanıtındaki token (imzalı, oturum bazlı). Bu yazma çağrısıyla oturum kapanır/tüketilir (bkz. 01 §6). |
X-Consent-Signature | HMAC-SHA256(token, consentId + actionType + requestTimestamp + nonce) — hex kodlanmış |
X-Request-Timestamp | epoch milliseconds |
X-Nonce | Tek kullanımlık rastgele string |
- Algoritma:
HMAC-SHA256(anahtar = AUTH token'ı) - İmza girdisi (canonical):
consentId + actionType + requestTimestamp + nonce - Replay penceresi:
±300 sn; dışında kalan istek →401 REPLAY_DETECTED. - Token geçersiz/süresi dolmuşsa →
401 INVALID_TOKEN(SDK yeniden AUTH yapar).
Neden token + imza birlikte? Token, kimliği (hangi consent oturumu) taşır; HMAC imzası ise bu yazma isteğinin o token sahibi tarafından, taze ve tam olarak üretildiğini kanıtlar — sahte/mükerrer yazma karşı koruma sağlar.
3. İstek (request)
Kullanıcı onay eylemini temsil eden gövde. camelCase zorunludur.
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
consentId | string | Evet | Onay kaydı kimliği (örn. ck_mobildev_0001). Hangi consent setine yazılacağını belirtir; path'tekine birebir eşit olmalıdır. |
actionType | enum accept_all | reject_all | modify | Evet | Basılan buton / onay tipi. Config'deki buton id'leriyle (banner.buttons.list, manager.footer.actions) birebir örtüşür. |
consent | object | Evet | GRUBUN kimliği seviyesinde onay haritası: { [groupId]: state } düz map (aşağıda detay). |
freshUser | boolean | Evet | Bu cihaz/kullanıcı için ilk onay mı? Telemetri + raporlama (ilk-onay oranı). |
contentVersion | string | Evet | Onayın verildiği config içerik sürümü (config.meta.contentVersion). Bir sonraki AUTH'ta remote contentVersion'la karşılaştırılıp reprompt kararı üretilir. |
locale | string (BCP-47) | Hayır | Onayın verildiği kullanıcı dili (örn. tr-TR). Audit/çeviri referansı. |
sdkVersion | string (semver) | Hayır | SDK sürümü. Audit + uyumluluk korelasyonu. |
deviceTime | string (ISO 8601 UTC) | Hayır | Cihaz saati. Drift/manipülasyon kontrolü. |
attention | object | null | Hayır | iOS ATT durumu. Android'de null (uygulanmaz). iOS'ta ve promptATTdialog: true iken dolu olur (§7). |
3.1 consent Map Yapısı
consent, düz bir haritadır: anahtar = groupId, değer = state (örn. {"essential":"granted","targeting":"denied"}).
| Bileşen | Tip | Açıklama |
|---|---|---|
Anahtar (groupId) | string | config.manager.groups[].id (örn. essential, functionality, targeting, tracking). Hangi grubun durumunun iletildiğini belirtir. |
Değer (state) | enum granted | denied | Grubun son durumu (yalnız bu iki değer). granted → grubun tüm consentKeys'i etkinleşir; denied → tümü kapatılır (çeviri SDK tarafında, §6). |
Neden item-seviye state yok? GTM/etiket API'leri key bazlı çalışır; eski item-bazlı
{title, state}yapısı bu modelle çelişiyordu. Bu sözleşmede onay durumu yalnızca grup (groupId) seviyesinde düz bir map olarak taşınır; item'lar (teknoloji/vendor) config tarafında yalnız bilgilendirme amaçlıdır ve grupla birlikte açılıp kapanır.
3.2 Örnek İstek (modify + karma durum)
{
"consentId": "ck_mobildev_0001",
"actionType": "modify",
"freshUser": true,
"contentVersion": "2",
"locale": "tr-TR",
"sdkVersion": "1.4.0",
"deviceTime": "2026-09-20T11:33:29Z",
"attention": null,
"consent": {
"essential": "granted",
"functionality": "granted",
"targeting": "denied",
"tracking": "denied"
}
}
Ayrıca header'da:
X-Consent-Token+X-Consent-Signature+X-Nonce+X-Request-Timestamp(§2.2).attentionörnektenullçünkü platform Android. iOS'ta ATT'ye tabi bir grup onaylanacaksa dolu gönderilir (§7). Bu örneğin aynısı ayrıca[02-postconsent.request.json](./02-postconsent.request.json)dosyasında yer alır.
4. Yanıt (response)
4.1 Gövde Alanları (200)
| Alan | Tip | Açıklama |
|---|---|---|
success | boolean | Onay eyleminin başarılı işlendiği. |
code | string | Durum kodu (başarıda OK). |
consentRecordId | string | Oluşturulmuş/güncellenmiş onay kaydının benzersiz kimliği. Telemetri/raporlama + audit korelasyonunun anahtarıdır. |
storedAt | string (ISO 8601 UTC) | Kaydın işlendiği sunucu zamanı. |
actionType | string | Çözülen onay tipi (eko; audit). |
consent | object | Otoriter onay haritası: { [groupId]: granted | denied } — sunucunun doğruladığı son sonuç. SDK bunu §6'daki eşlemeyle etiket key'lerine yayarak uygular. |
localState | object | Yeni cihaz durumu. SDK bunu önbelleğe yazar; bir sonraki AUTH istek girdisi olarak geri besler (retrigger zinciri). |
4.2 localState Alt Alanları
localState, 00 · AUTH isteğindeki localState ile birebir aynı yapıdadır — döngünün geri beslemesidir:
| Alan | Tip | Açıklama |
|---|---|---|
hasConsent | boolean | Artık true (bu cihazda onay saklı). |
installedUiVersion | string | Cihaza yazılan UI versiyonu. |
installedLegalVersion | string | Cihaza yazılan legal/metin versiyonu. |
installedContentVersion | string | Onayın verildiği içerik versiyonu (request.contentVersion). |
lastShownAt | string (ISO 8601) | Onay ekranının gösterildiği/saklandığı an (interval retrigger için). |
consent | object | Gövdedeki consent haritasının aynısı (groupId → state); bir sonraki AUTH'ın localState.consent'i. |
İki
consentalanı neden var? Gövdedekiconsent, SDK'ın etiketlere uygulayacağı sonuç;localState.consent, depolanacak geri besleme. İkisi de{ [groupId]: state }haritasıdır ve içerik aynıdır; ayrım, "uygula" ile "hatırla" amaçlarının farklı olmasındandır.
4.3 Örnek Yanıt (200)
{
"success": true,
"code": "OK",
"consentRecordId": "cr_9f2e6a4b8c1d",
"storedAt": "2026-09-20T11:33:31Z",
"actionType": "modify",
"consent": {
"essential": "granted",
"functionality": "granted",
"targeting": "denied",
"tracking": "denied"
},
"localState": {
"hasConsent": true,
"installedUiVersion": "2.4",
"installedLegalVersion": "1.0",
"installedContentVersion": "2",
"lastShownAt": "2026-09-20T11:33:31Z",
"consent": {
"essential": "granted",
"functionality": "granted",
"targeting": "denied",
"tracking": "denied"
}
}
}
Bu örneğin aynısı ayrıca
[02-postconsent.response.json](./02-postconsent.response.json)dosyasında yer alır.
5. actionType → Karar Matrisi
actionType, grup durumlarını belirler. modify dışında durumlar implicittir (buton mantığı); modify explicittir (kullanıcının grup bazlı toggle'ları). essential her durumda granted'tir (kilitli, §6).
actionType | essential | functionality | targeting | tracking | consent map |
|---|---|---|---|---|---|
accept_all | granted | granted | granted | granted | implicit (hepsi granted) |
reject_all | granted | denied | denied | denied | implicit (yalnız essential granted) |
modify | granted* | kullanıcı | kullanıcı | kullanıcı | explicit (kullanıcının state'leri) |
* essential içindeki security_storage asla denied yapılamaz — kilitlidir.
Config buton eşlemesi:
banner.buttons.list→accept_all/reject_all/modify;manager.footer.actions→accept_all/save(save ≡ modify);detail.actions→save(≡ modify). Yani üç davranış: hepsi, yalnız zorunlu, düzenle.
6. Onay → Etiket (GA4 / GTM) Dağıtımı
Bu bölüm, onayın gerçek etkisini tanımlar: kullanıcının grup bazlı tercihinin, uygulamanızdaki etiketlere granted/denied olarak nasıl yansıtılacağı. Dağıtımın sorumluluğu SDK/entegrasyon tarafındadır; sunucu yalnız { [groupId]: state } döndürür.
6.1 Config'deki grup → etiket key eşleşmesi
Config'deki her grup, bir consentKeys[] listesi taşır. Tipik dört grup ve karşılık gelen etiket key'leri:
Config group.id | Kategori | consentKeys[] (etiket key'leri) | Varsayılan |
|---|---|---|---|
essential | Zorunlu | security_storage | granted (kilitli) |
functionality | İşlevsellik | personalization_storage, functionality_storage | denied |
targeting | Hedefleme / reklam | ad_storage, ad_user_data, ad_personalization | denied |
tracking | İzleme / performans | analytics_storage | denied |
7 key'in tamamı, GTM Consent Mode v2'de built-in'dir.
ad_user_datavead_personalization, v2'de zorunludur (default state'leridenied). Bu 7 key için ek "custom" Consent Setting tanımlamak gerekmez — yalnızca §6.4'teki Consent Command + tetikleyici trigger'ları kurmanız yeterlidir.İsim farkına dikkat:
personalization_storage(içerik/deneyim kişiselleştirme, reklam dışı) ≠ad_personalization(reklam kişiselleştirme/yeniden pazarlama). İkisi farklı key'lerdir; isim benzerliğine düşmeyin.
6.2 Dağıtım mantığı (SDK tarafında)
SDK, response consent haritasındaki her groupId'yi, yerel config'deki o grubun consentKeys[] kümesine yayarak etiketlere uygular:
// groupId → GTM consentKeys dağıtımı (SDK / entegrasyon tarafı)
function applyConsentToGTM(config, consentMap) {
const consent = {};
for (const group of config.manager.groups) {
const state = consentMap[group.id]; // "granted" | "denied"
const effective = group.lockState === true ? "granted" : (state || "denied");
for (const key of group.consentKeys) {
consent[key] = effective; // grup state'i → o grubun tüm key'lerine
}
}
// security_storage (lock) her zaman granted; diğerleri kullanıcı tercihine göre
// Config'de yer almayan bir key için varsayılan "denied" (güvenli taraf)
window.dataLayer.push({ event: 'consent_update', ...consent });
}
Kural seti:
- Grup onaylı (
granted) → o grubunconsentKeys'indeki tüm key'lergranted. - Grup kapalı (
denied) → o gruptaki tüm key'lerdenied. essential(→security_storage) → her zamangranted(kilitli;lockState: true). Kullanıcı kapatamaz.- Config'de yer almayan key → varsayılan
denied(güvenli taraf). - Önemli ayrım: Onay durumu grupta tutulur; item'lar etiket key taşımaz. Dağıtım her zaman
group.consentKeys[]üzerinden yapılır.
6.3 Durum değerleri & gönderim
Her key yalnız granted veya denied değerini alır — ara durum yoktur. Gönderim, projenize göre iki eşdeğer yoldan biridir:
| Yol | Komut | Not |
|---|---|---|
| GA4 gtag.js | gtag('consent', 'default' | 'update', <states>) | wait_for_update yalnız default komutundadır. |
| GTM dataLayer | window.dataLayer.push({ 'event': 'default_consent' | 'consent_update', ...flat keys }) | Eşdeğer; GTM tag/trigger'ları consent state'lerine bakar. |
<states> objesi iki yolda da aynıdır: 7 key'in tamamı + her birinin granted/denied değeri.
Komutlar:
default(ilk yükleme): Varsayılan state'leri set eder. Non-essential key'lerdenied,security_storagegranted.wait_for_update(ms) eklenirse etiketler, gerçek tercih gelene dek bu süre kadar bekletilir → rızasız veri işlemesi önlenir, config gecikmesine karşı denge kurulur (pratik başlangıç 300–1000 ms).update(kullanıcı tercihini verince veya iznini geri çekince): State'leri günceller. Opt-out (izin geri çekme) daupdate+ ilgili key'lerideniedyapılır.removediye bir komut yoktur.
Örnek state gövdeleri:
// default: ilk yükleme (kullanıcı tercih bildirmedi)
{ ad_storage:'denied', analytics_storage:'denied', ad_user_data:'denied',
ad_personalization:'denied', functionality_storage:'denied',
personalization_storage:'denied', security_storage:'granted' }
// update · "Tümünü Kabul Et": hepsi granted
{ ad_storage:'granted', analytics_storage:'granted', ad_user_data:'granted',
ad_personalization:'granted', functionality_storage:'granted',
personalization_storage:'granted', security_storage:'granted' }
// update · "Zorunlu Olanlar": yalnız security_storage granted, diğerleri denied
{ ad_storage:'denied', analytics_storage:'denied', ad_user_data:'denied',
ad_personalization:'denied', functionality_storage:'denied',
personalization_storage:'denied', security_storage:'granted' }
Çerez silme uyarısı: Bir key'i
deniedyapmak, Google etiketlerinin o andan itibaren çerez okuma/yazmasını durdurur; tarayıcıda daha önce oluşturulmuş çerezleri ise silmez. Çerezleri tamamen temizlemek gerekiyorsa bu, SDK tarafındadocument.cookieüzerinden manuel yapılır — Consent Mode bunu yapmaz.
6.4 GTM Console'da kurulacaklar (özet)
- 7 key built-in → ek custom Consent Setting gerekmez.
- dataLayer yolunu seçtiyseniz: Console'da
default_consent→ Default veconsent_update→ Update Consent Command'larını ve bunları dinleyen trigger'ları tanımlayın. Event ↔ Command eşleşmesi kurulmazsa dataLayer push'ı sonuçsuz gider. (GA4 gtag yolunu kullanıyorsanız bu gerekmez —gtag('consent', …)doğrudan çalışır.) - Key adları birebir aynı olmalı (küçük harf):
ad_storage,analytics_storage,ad_user_data,ad_personalization,functionality_storage,personalization_storage,security_storage. Büyük harf veya eski/farklı ad kullanmayın.
7. Doğrulama (Sunucu tarafında)
Sunucu kaydı işlemekten önce aşağıdaki kontrolleri yapar; ihlalde ilgili hata kodu döner:
| # | Kural | İhlal → Hata |
|---|---|---|
| V1 | essential'in state ≠ denied (kilit) | ESSENTIAL_LOCKED (sunucu granted'e zorlar + uyarı) |
| V2 | Her consent anahtarı (= groupId), config groups[].id içinde olmalı | UNKNOWN_GROUP |
| V3 | state ∈ denied | INVALID_STATE |
| V4 | actionType === "modify" ise consent haritası non-empty olmalı | MISSING_CUSTOM_STATES |
| V5 | actionType ∈ {accept_all, reject_all} + explicit grup state'leri aksi yönde ise tutarsız | ACTION_STATE_MISMATCH |
| V6 | iOS + promptATTdialog === true + onay ≥1 ATT'ye tabi gruba granted + attention.status == notDetermined → kayıt REDDEDİLİR (SDK önce ATT'yi çözmeli). denied/restricted reddedilmez (terminal/kullanıcı tercihi) → ATT'ye tabi gruplar GTM'de AND gate ile denied (§7.4) | ATT_REQUIRED |
contentVersion kontrolü:
request.contentVersion, config'in mevcutcontentVersion'ından farklı (daha eski) bir sürümse kayıt tutulur, ancak çıktı reprompt gerektirebileceğini işaret eder (kullanıcı eski içeriğe onay verdi, içerik değişti → bir sonraki açılışta tekrar sor).
8. Hata Kodları
Hatalarda ortak gövde döner: { success:false, code, message, retryable, requestId }. message teşhis metnidir; UI'da gösterilmez (kullanıcıya gösterilecek metin config localization'ından gelir).
code | HTTP | retryable | Açıklama / SDK müdahalesi |
|---|---|---|---|
OK | 200 | — | Onay eylemi başarılı işlendi. |
INVALID_TOKEN | 401 | Evet | token geçersiz/süresi dolmuş → yeniden AUTH. |
SIGNATURE_MISMATCH | 401 | Hayır | HMAC imza doğrulanamadı → imza girdisi/token kontrolü. |
REPLAY_DETECTED | 401 | Hayır | Nonce tekrar/timestamp replay penceresi dışı → cihaz saati + nonce. |
CONSENT_NOT_FOUND | 404 | Hayır | consentId kaydı yok. |
ESSENTIAL_LOCKED | 400 | Hayır | essential denied olarak gönderildi → sunucu granted'e zorlar. |
UNKNOWN_GROUP | 400 | Hayır | Geçersiz groupId → config groups[].id'lerle karşılaştır. |
INVALID_STATE | 400 | Hayır | state granted/denied dışı. |
MISSING_CUSTOM_STATES | 400 | Hayır | modify gönderildi ama consent haritası boş → SDK grup durumlarını üretmeli. |
ACTION_STATE_MISMATCH | 400 | Hayır | actionType ile explicit group state'leri tutarsız. |
ATT_REQUIRED | 400 | Evet | iOS + ATT'ye tabi grup onaylanıyor + attention.status == notDetermined. → SDK ATT'yi çöz (requestTrackingAuthorization) ve yeniden post. denied/restricted bu kodu üretmez (§7.3/§7.4). |
RATE_LIMITED | 429 | Evet | Hız sınırı → Retry-After kadar bekle. |
SERVER_ERROR | 500 | Evet | Sunucu iç hata → onay önbellekte bekletilir, arka planda yeniden denenebilir. |
Önemli (KRİTİK): Onay eylemi başarısız olursa (500/429/ağ), SDK onay kararını yalnızca cihazda (
localState) saklar ve bağlantı gelince yeniden post eder — kullanıcının onayı kaybolmaz. Sunucu 500 dönerse mükerrer kayıt riskieventId-tabanlı idempotency ile önlenir.
9. iOS ATT Katmanı (kısa)
iOS'ta reklam/hedefleme takibi, cookie consent yanında işletim sisteminin ATT (App Tracking Transparency) iznini de gerektirir. Bu bölüm, ana akışın iOS özel yan dallarını özetler.
Android'de ATT karşılığı yoktur →
attention: null, bu bölüm devre dışıdır (no-op). ATT bir HTTP endpoint'i değil, iOS sistem iznidir. Sunucuyla tek temas noktası, isteğeattentionalanı eklemektir; sistem prompt'u SDK tarafındanAppTrackingTransparency(ATTrackingManager) ile atılır.
9.1 İki ayrı izin katmanı
| Katman | Ne izler | Kim yönetir |
|---|---|---|
| Cookie consent (bu SDK) | Depolama + teknoloji kullanımı | SDK / CMP |
| ATT (iOS sistemi) | IDFA ile çapraz-uygulama reklam takibi | İşletim sistemi |
Kullanıcı consent'te targeting'i onaylasa bile ATT verilmediyse reklam sağlayıcıları IDFA'yı okuyamaz → takip fiilen yapılamaz. Bu yüzden onay akışıyla ATT uyumlu çalıştırılır ve sonuç GTM'e doğru yansıtılır.
9.2 Durum modeli (4 durum)
SDK, ham ATT sonucunu 4 duruma haritalar. İstekteki attention.status:
status | Anlam | Onaya etkisi |
|---|---|---|
notDetermined | Henüz sorulmadı | ATT'ye tabi grup onaylanacaksa sistem prompt atılmalıdır; çözülmeden takip onayı kaydolunmaz (V6). |
authorized | Kullanıcı takibi izinledi | ATT'ye tabi gruplar onaylanabilir → takip çalışır. |
denied | Kullanıcı takibi reddetti | Kayıt engelLENMEZ; ATT'ye tabi gruplar GTM'de denied (§9.4) + danışma mesajı. |
restricted | Ebeveyn/MDM sistemi takibi engelledi | Kullanıcı kendi başına değiştiremez; kayıt engelLENMEZ; ATT'ye tabi gruplar GTM'de denied + bilgilendirme. |
9.3 Ne zaman sistem prompt atılır? (just-in-time)
Sistem dialog'u açılışta herkese değil, gerektiği anda atılır (çift-sorma yorgunluğunu önler). Prompt atılır yalnızca aşağıdakilerin tümü sağlanırsa:
platform === "iOS"VEbehavior.promptATTdialog === trueVEattention.status === "notDetermined"VE- Kullanıcının onayı ≥1 ATT'ye tabi grubu
grantedyapıyor (§9.5'teki ATT'ye tabi key setiyle kesişimi var).
Bu koşullar sağlanmıyorsa (örn. reject_all, ya da targeting kapalı modify) prompt atılmaz; ATT notDetermined kalır ve bu sorun değildir (takip istenmedi, V6 tetiklenmez).
9.4 AND gate (onay ↔ ATT birleşimi)
ATT'ye tabi bir grubun GTM'de fiilen geçerli olması için kullanıcının tercihi VE sistem ATT izni birlikte granted olmalıdır:
effective(grup) = granted → user_choice(grup)==granted VE attention.status==authorized
effective(grup) = denied → yukarıdaki koşul sağlanmazsa
(ATT'ye tabi olmayan gruplar: effective = user_choice; ATT'den etkilenmez)
Kullanıcı (targeting) | attention.status | GTM'de etkili | Kullanıcıya gösterilen |
|---|---|---|---|
denied | herhangi | denied | (normal) |
granted | authorized | granted | (normal) |
granted | denied | denied | Danışma: "Ayarlar'da takibi kapattınız; tercih kaydınızda ama takip sistemi gereği devre dışı." + Settings kısayolu |
granted | restricted | denied | Bilgi: "Takip, ebeveyn/sistem ayarı nedeniyle engelleniyor." |
Böylece kullanıcı "Tümünü Kabul Et" dese bile ATT verilmediyse reklam key'leri GTM'de denied kalır → izinsiz takip gerçekleşmez. Tercihi kaydetmek (audit) ile takibi fiilen bloklamak (ATT) ayrı halledilir; displayATTStatus: true ise bunu kullanıcıya şeffafça gösterir.
9.5 ATT'ye tabi key'ler (kod tarafı)
ATT yalnız IDFA/çapraz-uygulama reklam takibini kapsar:
const ATT_GATED_KEYS = new Set(["ad_storage", "ad_user_data", "ad_personalization"]);
function isATTGated(group) {
return group.consentKeys.some(k => ATT_GATED_KEYS.has(k));
}
Kural: "ATT'ye tabi grup" =
consentKeys ∩ {ad_storage, ad_user_data, ad_personalization} ≠ ∅olan gruptur (tipik olaraktargeting).tracking(analitik),functionalityveessentialATT'den bağımsızdır — kullanıcı analitiği onaylasa bile ATT reddetse analitik çalışır. Bu ayrım, ATT prompt'unu yalnızca gerçekten reklam takibi gerektiğinde atmak için kritiktir.
9.6 iOS kurulum notları
@import/import AppTrackingTransparency; durumATTrackingManager.trackingAuthorizationStatus, promptATTrackingManager.requestTrackingAuthorization(completion:).NSTrackingUsageDescription(Info.plist) ZORUNLUDUR — yoksarequestTrackingAuthorization()uygulama crash'er. Kullanıcıya "neden soruyoruz" metnidir.- Apple once-only kuralı: sistem dialog'u yalnız bir kez (durum
notDeterminediken) gösterilir. Kullanıcı reddettiyse dialog yeniden açılmaz; bu durumda SDK kendi yeniden-soru UI'ı + Settings derin bağlantısı ile kullanıcıyı yönlendirir. restrictedtüretimi:restrictedbir Apple enum'ı değildir; ebeveyn/MDM engeli ham.denied'i verir. SDK bu durumu yardımcı sinyalle ayırarakrestrictedolarak modeler (kullanıcı geri alamaz → kayıt bloklamaz).- ATT durumunu cihazda kalıcı saklayın; sonraki her POST_CONSENT'te
attention.status'u taşıyın (audit + V6 doğruluğu + retrigger tutarlılığı).
10. Developer Notları
- Onay, grubun kimliğinde (groupId) taşınır — istekte ve yanıttan aynı düz map formatı:
{ [groupId]: state }. Item/teknoloji bazında ayrı state YOKTUR. Etiketlere çevirimi SDK tarafında yapar (6.2). stateyalnızgranted/denied. Ara durumlar desteklenmez.essentialkilitli.security_storageher zamangranted; kullanıcı kapatamaz. Sunucu gerekirsegranted'e zorlar (V1).- Kimlik = token + HMAC. Her onay post'unda ayrı API key taşımak yerine, açılışta alınan tek token kullanılır (§2.2).
- Geri besleme döngüsü: Yanıt
localState, bir sonraki AUTH'ın girdisidir.installedContentVersion ≠ remote contentVersionise reprompt tetiklenir. Bu zincir "onay ver → içerik değişsin → yeniden sor" davranışının omurgasıdır. - Idempotency: Aynı onay eylemi (ağ tekrarında)
eventId/nonce ile tek kayıt olarak işlenir; mükerrer consent record üretilmez.consentRecordIdraporlama/audit akışına akar. groupId → consentKeysçevirimi SDK sorumluluğudur: HergroupId'yi yerel config'dekigroups[].consentKeyskümesine yayın. BirgroupIdyerel config'de karşılık bulamazsa (config/içerik sürüm farkı) o key'i uygulayamazsınız → güvenli yığın/uyarı üretin; kullanıcının onayılocalStatesayesinde kaybolmaz.- IOS'ta ATT'yi çöz, sonra post:
ATT_REQUIREDalırsanızrequestTrackingAuthorizationile ATT'yi çözün (notDetermined→authorized/denied) ve yeniden post edin.denied/restrictedkaydı bloklamaz; yalnızca AND gate (9.4) reklam key'lerini kapatır.