@blakfy/cookie 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,480 @@
1
+ # Blakfy Cookie Widget
2
+
3
+ > ![v2.1.0](https://img.shields.io/badge/version-2.1.0-3E5C3A) ![MIT](https://img.shields.io/badge/license-MIT-blue) ![size](https://img.shields.io/badge/size-%E2%89%A430KB-success) ![langs](https://img.shields.io/badge/languages-23-orange) ![presets](https://img.shields.io/badge/presets-18-purple)
4
+ >
5
+ > Tek script ile **KVKK + GDPR + CCPA + Google CMv2 + Microsoft UET + Yandex Metrica + IAB TCF v2.2** uyumlu cookie consent (çerez onayı) widget. **23 dil**, **18 hazır preset** (üçüncü parti araç entegrasyonu), **3 renk teması**, **3-tab tercihler modalı** (Kategoriler / Hizmetler / Hakkında), **tag-gating** (script engelleme/serbest bırakma) dahil.
6
+
7
+ **Versiyon:** 2.1.0 • **Lisans:** MIT • **CDN:** `cdn.jsdelivr.net/gh/tariktunc/blakfy-cookie@v2` • **npm:** `@blakfy/cookie-next@2`
8
+
9
+ ---
10
+
11
+ ## Quick Start (3 adım)
12
+
13
+ ### 1. Bootstrap (head içine, ilk script olarak)
14
+
15
+ `<head>` bloğuna **en üst sıraya** koy. GTM/GA4/Pixel'den **önce** yüklenmeli — onların default `denied` durumunda başlamasını sağlar (Google Consent Mode v2 + Microsoft UET).
16
+
17
+ ```html
18
+ <!-- Bootstrap: Tüm consent sinyallerini 'denied' olarak başlatır -->
19
+ <script src="https://cdn.jsdelivr.net/gh/tariktunc/blakfy-cookie@v2/dist/cookie-defaults.min.js"></script>
20
+ ```
21
+
22
+ ### 2. Site içerik script'lerin (GTM/GA4/Pixel/Clarity vb.)
23
+
24
+ Bunlar olduğu gibi kalır. Bootstrap zaten consent default'larını `denied` olarak set etti, dolayısıyla bu tag'ler kullanıcı onay verene kadar cookie yazmaz.
25
+
26
+ ```html
27
+ <!-- Örnek: Google Tag Manager (değişiklik gerektirmez) -->
28
+ <script>
29
+ (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
30
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
31
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
32
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
33
+ })(window,document,'script','dataLayer','GTM-XXXXXX');
34
+ </script>
35
+ ```
36
+
37
+ ### 3. Widget (body sonu, `</body>`'den önce)
38
+
39
+ ```html
40
+ <script
41
+ src="https://cdn.jsdelivr.net/gh/tariktunc/blakfy-cookie@v2/dist/cookie.min.js"
42
+ data-blakfy-locale="auto"
43
+ data-blakfy-policy-url="/cerez-politikasi"
44
+ data-blakfy-version="1.0"
45
+ data-blakfy-presets="ga4,gtm,facebook,clarity"
46
+ data-blakfy-ccpa="auto"
47
+ data-blakfy-tcf="false"
48
+ data-blakfy-position="bottom-right"
49
+ data-blakfy-theme="auto"
50
+ data-blakfy-accent="#3E5C3A"></script>
51
+ ```
52
+
53
+ **Bittiğinde:** Sayfa yüklendiğinde sağ alt köşede consent banner ve "Powered by Blakfy Studio" badge belirir. Kullanıcı bir karar verene kadar GTM/GA4/Facebook Pixel/Clarity tag'leri çalışmaz; karar verildiğinde otomatik aktif olur.
54
+
55
+ ---
56
+
57
+ ## Senaryolar
58
+
59
+ ### Vanilla HTML / WordPress / Shopify
60
+
61
+ Yukarıdaki 3 adımı `<head>` ve `</body>` öncesine yapıştır. Çalışır. Tam çalışan örnek için: [`examples/vanilla-html.html`](./examples/vanilla-html.html).
62
+
63
+ WordPress için PHP snippet: [`examples/wordpress-snippet.php`](./examples/wordpress-snippet.php).
64
+
65
+ Shopify için: theme `theme.liquid` dosyasının `<head>` ve `</body>` öncesi noktalarına aynı 3 adım eklenir. Ek bir paket gerekmez.
66
+
67
+ ### Next.js 14+ (önerilen — App Router)
68
+
69
+ ```bash
70
+ npm install @blakfy/cookie-next@2
71
+ ```
72
+
73
+ `app/layout.tsx`:
74
+
75
+ ```tsx
76
+ import { BlakfyCookieProvider, ConsentModeDefault } from "@blakfy/cookie-next";
77
+
78
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
79
+ return (
80
+ <html lang="tr">
81
+ <head>
82
+ {/* Bootstrap: GCM/UET/Yandex default denied */}
83
+ <ConsentModeDefault />
84
+ </head>
85
+ <body>
86
+ <BlakfyCookieProvider
87
+ locale="auto"
88
+ policyUrl="/cerez-politikasi"
89
+ policyVersion="1.0"
90
+ presets="ga4,gtm,facebook,clarity"
91
+ ccpa="auto"
92
+ tcf={false}
93
+ position="bottom-right"
94
+ theme="auto"
95
+ accent="#3E5C3A"
96
+ >
97
+ {children}
98
+ </BlakfyCookieProvider>
99
+ </body>
100
+ </html>
101
+ );
102
+ }
103
+ ```
104
+
105
+ Tam Next.js örneği: [`examples/nextjs/`](./examples/nextjs/).
106
+ Paket README'si: [`packages/cookie-next/README.md`](./packages/cookie-next/README.md).
107
+
108
+ ### GTM ile birlikte
109
+
110
+ GTM, default `denied` ile başlar (bootstrap sayesinde). Trigger'larında "Consent State" şartı eklemen yeterli — Tag → "Consent settings" → "Require additional consent for tag firing" → ilgili kategoriler (örn. `analytics_storage` veya `ad_storage`). Kullanıcı kabul edince `gtag('consent','update', ...)` otomatik çağrılır ve tag'ler kendiliğinden tetiklenir.
111
+
112
+ ```js
113
+ // Doğrulama (DevTools console)
114
+ window.dataLayer.find(e => e[0] === 'consent');
115
+ // → ["consent", "default", { ad_storage: "denied", ... }]
116
+ window.BlakfyCookie.acceptAll();
117
+ // → ["consent", "update", { ad_storage: "granted", ... }]
118
+ ```
119
+
120
+ ### Bing Ads (Microsoft UET) ile
121
+
122
+ UET tag'ini olduğu gibi koy — bootstrap `window.uetq.push('consent','default',{ad_storage:'denied'})` çağrısını otomatik yapar. Kullanıcı `marketing` onayı verince UET'e `update` push edilir. Microsoft Clarity de aynı sinyali okur.
123
+
124
+ ```html
125
+ <!-- UET tag — değişiklik gerektirmez -->
126
+ <script>
127
+ (function(w,d,t,r,u){var f,n,i;w[u]=w[u]||[],f=function(){var o={ti:"XXXXXXX"};
128
+ o.q=w[u],w[u]=new UET(o),w[u].push("pageLoad")},n=d.createElement(t),n.src=r,
129
+ n.async=1,n.onload=n.onreadystatechange=function(){var s=this.readyState;
130
+ s&&s!=="loaded"&&s!=="complete"||(f(),n.onload=n.onreadystatechange=null)},
131
+ i=d.getElementsByTagName(t)[0],i.parentNode.insertBefore(n,i);
132
+ })(window,document,"script","//bat.bing.com/bat.js","uetq");
133
+ </script>
134
+ ```
135
+
136
+ ### Yandex Metrica ile
137
+
138
+ Yandex'in standart consent API'si yoktur, tag-gating kullanılır. Metrica embed kodunu `type="text/plain"` ile sar:
139
+
140
+ ```html
141
+ <script type="text/plain" data-blakfy-category="analytics">
142
+ (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
143
+ m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],
144
+ k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
145
+ (window,document,"script","https://mc.yandex.ru/metrica/tag.js","ym");
146
+ ym(XXXXXXXX, "init", { clickmap:true, trackLinks:true, accurateTrackBitrate:true });
147
+ </script>
148
+ ```
149
+
150
+ **Webvisor (session replay)** için ayrı `recording` kategori onayı gerekir (KVKK/GDPR yorumu). Otomatik temizlenen cookie'ler: `_ym_*`, `yandexuid`, `yabs-frequency`.
151
+
152
+ ---
153
+
154
+ ## Tercihler Modalı (3 Sekme)
155
+
156
+ "Tercihler" veya `window.BlakfyCookie.open()` çağrıldığında açılan modal 3 sekmeden oluşur:
157
+
158
+ | Sekme | İçerik |
159
+ |---|---|
160
+ | **Kategoriler** | Zorunlu / Analitik / Pazarlama / Fonksiyonel toggle switch'leri. "Seçimleri Kaydet" ve "Tümünü Kabul Et" butonları. |
161
+ | **Hizmetler** | Aktif preset'lere göre accordion kartlar. Her kart: açıklama, veri işleyici, adres, amaçlar, teknolojiler, toplanan veriler, hukuki dayanak, saklama süresi, aktarım ülkeleri, gizlilik politikası linki. GDPR Madde 13/14 + KVKK Madde 10 zorunlu bilgi ifşası. |
162
+ | **Hakkında** | CMP kimliği (Blakfy Studio), platform açıklaması (GDPR / KVKK / CCPA), sürüm numarası. |
163
+
164
+ > **Yasal dayanak:** Hizmetler sekmesindeki bilgiler GDPR Madde 13/14 (bilgi yükümlülüğü) ve KVKK Madde 10 (aydınlatma yükümlülüğü) gerekliliklerini karşılar. Presets kullanmadan da her site kendi hizmet bilgilerini `SERVICE_METADATA` yapısına ekleyebilir.
165
+
166
+ ---
167
+
168
+ ## Renk Temaları
169
+
170
+ 3 hazır tema, `data-blakfy-theme` ile seçilir:
171
+
172
+ | Tema | Açıklama | Attribute değeri |
173
+ |---|---|---|
174
+ | **Beyaz** (varsayılan) | Beyaz arka plan, koyu metin | `light` veya atlanabilir |
175
+ | **Açık gri** | `#f0f0f0` arka plan, koyu metin | `gray` |
176
+ | **Siyah** | `#1a1a1a` arka plan, açık metin | `dark` |
177
+ | **Otomatik** | Sistem `prefers-color-scheme` ayarını okur | `auto` |
178
+
179
+ ```html
180
+ <!-- Açık gri tema -->
181
+ <script src="...cookie.min.js" data-blakfy-theme="gray" ...></script>
182
+
183
+ <!-- Siyah tema -->
184
+ <script src="...cookie.min.js" data-blakfy-theme="dark" ...></script>
185
+
186
+ <!-- Sistem temasını takip et -->
187
+ <script src="...cookie.min.js" data-blakfy-theme="auto" ...></script>
188
+ ```
189
+
190
+ Tüm temalarda `--blakfy-accent` CSS değişkeni geçerliliğini korur — buton ve aktif sekme rengi `data-blakfy-accent` ile özelleştirilebilir.
191
+
192
+ ---
193
+
194
+ ## Configuration Reference
195
+
196
+ Tüm `<script>` tag'i üzerine konabilen `data-blakfy-*` attribute'ları:
197
+
198
+ | Attribute | Default | Tip | Açıklama |
199
+ |---|---|---|---|
200
+ | `data-blakfy-locale` | `auto` | BCP47 ya da `auto` | Dil. `auto` → tarayıcıdan tespit. 23 desteklenen dil aşağıda. |
201
+ | `data-blakfy-main-lang` | `null` | BCP47 | Sitenin **birincil dili** (audit log için). Boşsa locale ile aynı. |
202
+ | `data-blakfy-policy-url` | `/cerez-politikasi` | URL | "Çerez Politikası" linki için hedef. |
203
+ | `data-blakfy-version` | `1.0` | string | **Politika versiyonu**. Bunu artırırsan tüm kullanıcılar tekrar onay vermek zorunda (re-consent). |
204
+ | `data-blakfy-audit-endpoint` | `null` | URL | Consent kararı bu endpoint'e POST edilir (KVKK Md.12 / GDPR Art.7(1) kanıt). |
205
+ | `data-blakfy-position` | `bottom-right` | enum | `bottom-right` \| `bottom-left` \| `bottom` \| `top` \| `center` |
206
+ | `data-blakfy-theme` | `auto` | enum | **`light`** (beyaz) \| **`gray`** (açık gri) \| **`dark`** (siyah) \| `auto` (`prefers-color-scheme`) |
207
+ | `data-blakfy-accent` | `#3E5C3A` | hex | Buton ve vurgu rengi. |
208
+ | `data-blakfy-presets` | `null` | virgül listesi | Etkinleştirilecek preset key'leri. Örn: `ga4,gtm,facebook,clarity`. Aşağıda 18 preset listesi. |
209
+ | `data-blakfy-tcf` | `false` | bool | IAB TCF v2.2 modülünü aç (`__tcfapi` global). |
210
+ | `data-blakfy-cmp-id` | `0` | int | TCF CMP ID. `0` = preview/test mode. Sertifikasyon sonrası gerçek ID. |
211
+ | `data-blakfy-ccpa` | `auto` | enum | `auto` (jurisdiction tespiti), `true` (her zaman aç), `false` (kapat) |
212
+ | `data-blakfy-gpc` | `respect` | enum | `respect` (tarayıcı GPC'si auto-deny say) \| `ignore` |
213
+ | `data-blakfy-dnt` | `respect` | enum | `respect` (UI'da uyar) \| `auto-deny` (auto-reject) |
214
+ | `data-blakfy-status-url` | jsDelivr `@2/status.json` | URL | Status bar mesajları için kaynak. |
215
+ | `data-blakfy-status` | `true` | bool | `false` ise status bar render edilmez. |
216
+
217
+ **Desteklenen 23 dil:** `tr`, `en`, `ar`, `fa`, `ur`, `fr`, `ru`, `de`, `he`, `uk`, `es`, `it`, `pt`, `nl`, `pl`, `sv`, `cs`, `zh`, `zh-TW`, `ja`, `ko`, `id`, `hi` (RTL: `ar`, `fa`, `ur`, `he`).
218
+
219
+ ---
220
+
221
+ ## API Reference
222
+
223
+ `window.BlakfyCookie` global olarak erişilebilir. Tüm v1 metodları korunmuştur, v2'de yeni metodlar eklendi.
224
+
225
+ | Metod | Sürüm | İmza | Açıklama |
226
+ |---|---|---|---|
227
+ | `version` | v1 | `string` | Kütüphane sürümü, örn. `"2.1.0"`. |
228
+ | `open()` | v1 | `() => void` | Tercihler modalını aç. |
229
+ | `acceptAll()` | v1 | `() => void` | Tüm kategorileri kabul et. |
230
+ | `rejectAll()` | v1 | `() => void` | Tüm kategorileri reddet (essential dışında). |
231
+ | `getConsent(cat)` | v1 | `(c: ConsentCategory) => boolean` | Kategori onaylı mı. `essential` her zaman `true`. |
232
+ | `getState()` | v1 | `() => BlakfyConsentState \| null` | Tam consent state objesi. |
233
+ | `onChange(fn)` | v1 | `(fn: (state) => void) => void` | State değişince çağrılır. |
234
+ | `setLocale(loc)` | v1 | `(loc: BlakfyLocale) => void` | Dili değiştir (UI re-render). |
235
+ | `getMainLang()` | v1 | `() => BlakfyLocale` | Audit log için ayarlanan birincil dil. |
236
+ | `onConsent(cat, fn)` | **v2** | `(c, fn: (granted: boolean) => void) => void` | Kategori-bazlı listener. Mevcut state ile **anında** çağrılır, sonra her değişimde tekrar. |
237
+ | `registerCleanup(opts)` | **v2** | `(opts: { category, cookies?, storage? }) => void` | Onay geri çekildiğinde silinecek cookie'leri/localStorage anahtarlarını kaydet. |
238
+ | `unblock(cat)` | **v2** | `(c: ConsentCategory) => void` | Kategori için tag-gating'i manuel aç. |
239
+ | `scan()` | **v2** | `() => ConsentCategory[]` | DOM'u tekrar tara (SPA navigasyonu sonrası). |
240
+ | `usePreset(name)` | **v2** | `(name: string) => Preset \| null` | Hazır preset'i runtime'da uygula. |
241
+ | `tcf.getTCString()` | **v2** | `() => string` | IAB TCF v2.2 TC string. |
242
+ | `ccpa.optOut()` | **v2** | `() => void` | CCPA "Do Not Sell" opt-out. |
243
+ | `ccpa.isOptedOut()` | **v2** | `() => boolean` | CCPA opt-out durumu. |
244
+ | `getJurisdiction()` | **v2** | `() => "GDPR" \| "CCPA" \| "LGPD" \| "default"` | Tespit edilen yetki alanı. |
245
+ | `window.__tcfapi(...)` | **v2** | IAB standart | `getTCData`, `addEventListener`, `removeEventListener` (TCF v2.2 spec). |
246
+
247
+ **ConsentCategory:** `"essential"` | `"analytics"` | `"marketing"` | `"functional"` | `"recording"`
248
+
249
+ **BlakfyConsentState alanları:** `id` (uuid), `essential` (true), `analytics`, `marketing`, `functional`, `recording`, `timestamp` (ISO), `version` (policy), `locale`, `mainLang`, `jurisdiction`, `tcString`, `uspString`.
250
+
251
+ ---
252
+
253
+ ## Tag-Gating
254
+
255
+ Üçüncü parti tag'lerini kullanıcı onay vermeden çalıştırma. 4 yöntem.
256
+
257
+ ### Harici script
258
+
259
+ ```html
260
+ <!-- type="text/plain" → tarayıcı çalıştırmaz -->
261
+ <script type="text/plain"
262
+ data-blakfy-category="marketing"
263
+ data-blakfy-src="https://connect.facebook.net/en_US/fbevents.js"
264
+ async></script>
265
+ ```
266
+
267
+ Onay verildiğinde widget script'in `type` attribute'unu `text/javascript`'e çevirir, `data-blakfy-src` → `src` taşır ve DOM'a yeniden ekler.
268
+
269
+ ### Inline script
270
+
271
+ ```html
272
+ <script type="text/plain" data-blakfy-category="analytics">
273
+ console.log("Analytics tag fired");
274
+ fbq('init', 'PIXEL_ID');
275
+ </script>
276
+ ```
277
+
278
+ ### Iframe (YouTube, Vimeo, harita, vb.)
279
+
280
+ ```html
281
+ <iframe data-blakfy-src="https://www.youtube.com/embed/VIDEO_ID"
282
+ data-blakfy-category="marketing"
283
+ data-blakfy-placeholder="auto"
284
+ width="560" height="315"
285
+ title="YouTube video"
286
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope"
287
+ allowfullscreen></iframe>
288
+ ```
289
+
290
+ `data-blakfy-placeholder="auto"` → otomatik "Çerez onayı bekleniyor" placeholder UI'ı gösterilir.
291
+
292
+ ### React/Next.js declarative gating
293
+
294
+ ```tsx
295
+ "use client";
296
+ import { useGating } from "@blakfy/cookie-next";
297
+
298
+ export function YouTubeEmbed({ id }: { id: string }) {
299
+ const allowed = useGating("marketing");
300
+ if (!allowed) {
301
+ return (
302
+ <div className="aspect-video rounded bg-zinc-100 flex items-center justify-center">
303
+ Onay bekleniyor — bu içeriği görmek için pazarlama çerezlerini kabul edin.
304
+ </div>
305
+ );
306
+ }
307
+ return (
308
+ <iframe
309
+ src={`https://www.youtube.com/embed/${id}`}
310
+ className="w-full aspect-video"
311
+ title="YouTube"
312
+ allow="accelerometer; clipboard-write; encrypted-media; gyroscope"
313
+ allowFullScreen
314
+ />
315
+ );
316
+ }
317
+ ```
318
+
319
+ ---
320
+
321
+ ## 18 Hazır Preset
322
+
323
+ `data-blakfy-presets="ga4,gtm,facebook,clarity"` gibi virgüllü liste ile aktive edilir. Preset; cookie'leri ve localStorage anahtarlarını otomatik **registerCleanup**'a kaydeder, böylece kullanıcı onayı geri çekince bunlar otomatik silinir.
324
+
325
+ | Key | Araç | Kategori | Örnek Cookie / Storage |
326
+ |---|---|---|---|
327
+ | `ga4` | Google Analytics 4 | analytics | `_ga`, `_ga_*`, `_gid`, `_gat` |
328
+ | `gtm` | Google Tag Manager | analytics | `_dc_gtm_*` |
329
+ | `maps` | Google Maps | functional | `NID`, `SID`, `HSID` |
330
+ | `recaptcha` | Google reCAPTCHA | functional | `_GRECAPTCHA` |
331
+ | `facebook` | Facebook Pixel | marketing | `_fbp`, `_fbc`, `fr` |
332
+ | `youtube` | YouTube embed | marketing | `VISITOR_INFO1_LIVE`, `YSC`, `PREF` |
333
+ | `vimeo` | Vimeo embed | marketing | `vuid`, `_ga` |
334
+ | `hotjar` | Hotjar | analytics | `_hjSession*`, `_hjid` |
335
+ | `clarity` | Microsoft Clarity | analytics | `_clck`, `_clsk`, `MUID` |
336
+ | `linkedin` | LinkedIn Insight | marketing | `li_sugr`, `bcookie`, `lidc`, `UserMatchHistory` |
337
+ | `yandex` | Yandex Metrica | analytics + recording | `_ym_*`, `yandexuid`, `yabs-frequency` |
338
+ | `bing` | Bing Ads (UET) | marketing | `MUID`, `_uetsid`, `_uetvid` |
339
+ | `tiktok` | TikTok Pixel | marketing | `tt_*`, `_ttp` |
340
+ | `pinterest` | Pinterest Tag | marketing | `_pinterest_*`, `_pin_unauth` |
341
+ | `tawkto` | Tawk.to chat | functional | `__tawkUUID`, `Tawk_*` |
342
+ | `intercom` | Intercom | functional | `intercom-*` |
343
+ | `hubspot` | HubSpot | marketing | `__hssc`, `__hssrc`, `__hstc`, `hubspotutk` |
344
+ | `mailchimp` | Mailchimp | marketing | `_mcid`, `mc_*` |
345
+
346
+ **Manuel ekleme** (preset'sız):
347
+
348
+ ```js
349
+ window.BlakfyCookie.registerCleanup({
350
+ category: "marketing",
351
+ cookies: ["my_custom_pixel", /^_track_/],
352
+ storage: ["myAppMarketingCache"]
353
+ });
354
+ ```
355
+
356
+ ---
357
+
358
+ ## Compliance
359
+
360
+ | Yasa / Standart | Yetki Alanı | Modül | Ne yapar |
361
+ |---|---|---|---|
362
+ | **GDPR** | AB | `core/` + `ui/` | Eşit prominence kabul/red butonu, pre-tick yok, granular kategori onayı. |
363
+ | **ePrivacy Directive** | AB | `core/consent-store` | Onay öncesi cookie yazılmaz. |
364
+ | **KVKK** | Türkiye | `core/audit.js` | Md.12 ispat yükümlülüğü için audit log POST. |
365
+ | **CCPA / CPRA** | Kaliforniya | `compliance/ccpa.js` | "Do Not Sell" linki, USP string `1YYY`, GPC saygısı. |
366
+ | **LGPD** | Brezilya | `i18n/pt.js` + `geo/` | Portekizce UI, jurisdiction tespiti (v2.1'de tam destek). |
367
+ | **Google Consent Mode v2** | Google ekosistemi | `compliance/google-cmv2.js` | `gtag('consent','update', {...})` 7 sinyal. |
368
+ | **Microsoft UET** | Bing Ads + Clarity | `compliance/microsoft-uet.js` | `uetq.push('consent','update', {ad_storage})` |
369
+ | **Yandex Metrica** | Yandex ekosistemi | `compliance/yandex-metrica.js` | Tag-gating + Webvisor ayrı `recording` kategori. |
370
+ | **IAB TCF v2.2** | AB AdTech (AdSense) | `compliance/tcf-v2.js` | `__tcfapi`, TC string, GVL fetch. |
371
+ | **GPC** | Tarayıcı standardı | `compliance/gpc.js` | `navigator.globalPrivacyControl` → marketing/analytics auto-deny. |
372
+ | **DNT** | Tarayıcı standardı | `compliance/dnt.js` | `navigator.doNotTrack === "1"` → UI uyarı veya auto-deny. |
373
+
374
+ ### TCF v2.2 (AdSense / Ad Manager kullanıcıları için)
375
+
376
+ `data-blakfy-tcf="true" data-blakfy-cmp-id="0"` ile preview mode'da çalışır. Production için IAB Europe sertifikasyonu gerekir (~2-3 ay, yıllık ~€2.000 ücret). Süreç ve audit gereksinimleri: [`TCF-CERTIFICATION.md`](./TCF-CERTIFICATION.md).
377
+
378
+ ```js
379
+ // TC string okuma
380
+ window.BlakfyCookie.tcf.getTCString();
381
+ // IAB standart API
382
+ window.__tcfapi("getTCData", 2, (data, success) => console.log(data));
383
+ ```
384
+
385
+ ### CCPA / CPRA (ABD trafiği)
386
+
387
+ `data-blakfy-ccpa="auto"` → `geo/jurisdiction.js` Kaliforniya tespit ederse:
388
+
389
+ - Banner'daki "Reddet" → **"Do Not Sell or Share My Personal Information"**
390
+ - Footer'a kalıcı `<a class="blakfy-ccpa-link">` (yasal zorunluluk)
391
+ - USP string `1YYY` (versiyon, opt-out, sale, third-party) `__uspapi` üzerinden expose edilir
392
+ - `Sec-GPC: 1` header otomatik opt-out sayılır
393
+
394
+ ### GPC / DNT default davranışı
395
+
396
+ - **GPC** (`navigator.globalPrivacyControl === true`): Kullanıcı açık onay vermediyse `marketing` ve `analytics` otomatik **denied**. CCPA jurisdiction'da yasal opt-out.
397
+ - **DNT** (`navigator.doNotTrack === "1"`): Default'ta sadece banner'da uyarı yazısı. `data-blakfy-dnt="auto-deny"` ile auto-reject yapılabilir. (DNT zayıf bir standart; GPC tercih edilir.)
398
+
399
+ ---
400
+
401
+ ## Troubleshooting
402
+
403
+ ### Widget hiç görünmüyor
404
+
405
+ 1. Console'da hata var mı? Network sekmesinde `cookie.min.js` 200 dönüyor mu?
406
+ 2. Script tag'i `</body>`'den önce mi? `<head>` içine konursa DOM hazır olmadan render denenir.
407
+ 3. Daha önce kabul/red verildiyse banner görünmez (kalıcı). Modal'ı tetiklemek için: `window.BlakfyCookie.open()` veya footer'a "Çerez Tercihleri" linki koy.
408
+
409
+ ### Banner her sayfada / her seferinde tekrar açılıyor
410
+
411
+ `data-blakfy-version` (politika versiyonu) değişti mi? Bu değer her cookie'de saklanır; uyuşmuyorsa re-consent tetiklenir. **Dikkat:** Kütüphane sürümü `cookie.min.js` patch güncellemeleri kullanıcıyı **etkilemez** (v2 düzeltmesi). v1'de bu bir bug'dı.
412
+
413
+ ### GTM / GA4 tetiklenmiyor
414
+
415
+ - **Bootstrap script GTM'den önce mi yükleniyor?** `cookie-defaults.min.js` `<head>`'in **ilk** script'i olmalı. Aksi halde GTM `consent default` çağrısını kaçırır.
416
+ - Tag → "Consent settings" → "Require additional consent for tag firing" doğru kategorilere ayarlı mı?
417
+ - Kullanıcı kabul etti mi: `window.BlakfyCookie.getState()` ile kontrol et.
418
+
419
+ ### Yandex Metrica çalışıyor ama Webvisor (session replay) çalışmıyor
420
+
421
+ Webvisor `marketing` değil, **`recording`** kategorisi gerektirir. Modal'da bu seçeneğe ayrı onay vermelisin. KVKK/GDPR yorumu: session replay biyometriye yakın özel veri olduğu için ek granular onay zorunlu.
422
+
423
+ ### TCF preview mode'da takıldım
424
+
425
+ `data-blakfy-cmp-id="0"` preview mode'dur. AdSense/Ad Manager production için IAB Europe sertifikasyonu sonrası atanan gerçek CMP ID girilmeli. Detay: [`TCF-CERTIFICATION.md`](./TCF-CERTIFICATION.md).
426
+
427
+ ### "Powered by Blakfy Studio" badge'i nasıl gizlerim?
428
+
429
+ **Gizlenemez.** 3 katmanlı anti-tampering korumalı (CSS `!important`, MutationObserver re-injection, kod-baked HTML). Lisans şartının parçasıdır. Marka koruması.
430
+
431
+ ### Next.js'te FOUC (içerik atlaması) görüyorum
432
+
433
+ `@blakfy/cookie-next@2`'ye yükselt. v1'de FOUC vardı; v2'de `next/script` `beforeInteractive` strateji kullanılıyor.
434
+
435
+ ### `acceptAll()` sonrası 3rd-party tag'ler hala engelli
436
+
437
+ `window.BlakfyCookie.scan()` çağır — SPA navigasyonu veya dinamik DOM ekleme sonrası gating observer'ı tekrar tetikler.
438
+
439
+ ---
440
+
441
+ ## Migration v1 → v2
442
+
443
+ **Kısa cevap:** Değişiklik gerekmez. v1 kullanıcıları `@1` etiketinde kalır, çalışmaya devam eder. v2'ye opt-in yapmak için **CDN URL'sindeki `@1` → `@2`** ve dosya adı `cookie.js` → `dist/cookie.min.js` güncellemesi yeterli — tüm v1 attribute'ları korunur, kullanıcı consent cookie'si geriye uyumlu okunur.
444
+
445
+ Detay: [`MIGRATION.md`](./MIGRATION.md).
446
+
447
+ ---
448
+
449
+ ## Footer "Çerez Tercihleri" linki
450
+
451
+ ```html
452
+ <a href="#" onclick="event.preventDefault(); window.BlakfyCookie.open();">
453
+ Çerez Tercihleri
454
+ </a>
455
+ ```
456
+
457
+ Veya React:
458
+
459
+ ```tsx
460
+ <button onClick={() => window.BlakfyCookie?.open()}>Çerez Tercihleri</button>
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Diğer Kaynaklar
466
+
467
+ - [`ARCHITECTURE.md`](./ARCHITECTURE.md) — modül yapısı, veri akışı, boyut bütçesi
468
+ - [`COMPLIANCE.md`](./COMPLIANCE.md) — her yasa için detaylı uyumluluk mappingleri
469
+ - [`CHANGELOG.md`](./CHANGELOG.md) — sürüm notları
470
+ - [`MIGRATION.md`](./MIGRATION.md) — v1 → v2 geçiş
471
+ - [`TCF-CERTIFICATION.md`](./TCF-CERTIFICATION.md) — IAB Europe başvuru süreci
472
+ - [`packages/cookie-next/README.md`](./packages/cookie-next/README.md) — npm paketi rehberi
473
+
474
+ ---
475
+
476
+ ## License
477
+
478
+ MIT © Blakfy Studio. "Powered by Blakfy Studio" branding badge anti-tampering korumalı ve kaldırılamaz.
479
+
480
+ Issues: https://github.com/tariktunc/blakfy-cookie/issues
@@ -0,0 +1,106 @@
1
+ # IAB TCF v2.2 Sertifikasyon Süreci
2
+
3
+ > Bu doküman v2.0.0 release sonrası başlatılacak süreçtir. Kod hazır, ama IAB Europe'tan resmi CMP ID alınmadan widget "preview mode"da çalışır.
4
+
5
+ ---
6
+
7
+ ## Neden Sertifikasyon Lazım?
8
+
9
+ Eğer site sahibi:
10
+ - Google AdSense
11
+ - Google Ad Manager (DV360, Google Ads — re-marketing dahil)
12
+ - Major SSP'ler (Magnite, Index Exchange, Xandr...)
13
+
14
+ kullanıyorsa, **Mart 2024'ten beri** TCF v2.2 sertifikalı bir CMP zorunlu. Sertifikasız widget "non-compliant" sayılır ve Google reklam servisi durdurabilir.
15
+
16
+ ---
17
+
18
+ ## Süreç (5 Adım)
19
+
20
+ ### 1. Başvuru
21
+ - URL: https://iabeurope.eu/cmp-list/
22
+ - Form: CMP adı, URL, teknik temas kişisi, audit dokümanları
23
+ - Süre: 1 hafta cevap
24
+
25
+ ### 2. Teknik Audit
26
+ IAB Europe denetçisi şunları kontrol eder:
27
+ - `__tcfapi` global fonksiyonun varlığı ve doğru komut yüzeyi (✅ kodda var)
28
+ - TC string formatı (Base64URL, doğru segment yapısı) (✅)
29
+ - Vendor List senkronizasyonu (GVL fetch) (✅)
30
+ - UI'da vendor toggle erişilebilirliği (✅ src/ui/modal.js)
31
+ - DSAR (Data Subject Access Request) akışı dokümante edildi mi
32
+ - Consent withdrawal her zaman mümkün mü (✅ widget her zaman erişilebilir)
33
+
34
+ ### 3. Ücret
35
+ - **Annual fee**: ~€2.000 (CMP boyutuna göre değişir)
36
+ - Faturalama: Yıllık peşin
37
+
38
+ ### 4. CMP ID Atama
39
+ - Audit geçince IAB Europe bir **numeric CMP ID** atar (örn. `123`)
40
+ - Bu ID widget'a yazılır:
41
+ ```html
42
+ <script src="..." data-blakfy-cmp-id="123"></script>
43
+ ```
44
+ - ID `0` = preview/test mode (audit öncesi)
45
+
46
+ ### 5. Yıllık Yenileme
47
+ - Her yıl re-audit (kod değişikliği varsa)
48
+ - Yenileme ücreti aynı
49
+
50
+ ---
51
+
52
+ ## Geliştirici Tarafında Yapılacaklar (kullanıcıya talimat)
53
+
54
+ ```bash
55
+ # Sertifikasyon onayı geldiğinde
56
+ 1. CMP ID'yi al (örn. 123)
57
+ 2. Site script tag'ine ekle:
58
+ data-blakfy-cmp-id="123"
59
+ 3. Yeniden deploy.
60
+ ```
61
+
62
+ Kütüphane güncellemesi gerekmez — `data-blakfy-cmp-id="0"` (preview) ile `data-blakfy-cmp-id="123"` (prod) arasındaki tek fark TC string'in `cmpId` field'ı.
63
+
64
+ ---
65
+
66
+ ## Preview Mode Davranışı (CMP ID 0)
67
+
68
+ - `__tcfapi` çalışır
69
+ - TC string üretilir ama `cmpId=0`
70
+ - Test ortamlarında ve sertifikasyon beklenirken kullanılır
71
+ - Production AdSense kullanımı için **uygun değildir** — Google reddeder
72
+
73
+ ---
74
+
75
+ ## Vendor List
76
+
77
+ - Kaynak: `https://vendor-list.consensu.org/v3/vendor-list.json`
78
+ - Boyut: ~500 KB JSON, 1500+ vendor
79
+ - Strateji: Lazy fetch + 24 saat cache
80
+ - UI'da arama/filtreleme: src/ui/modal.js içinde (vendor toggle paneli)
81
+
82
+ ---
83
+
84
+ ## DSAR (Data Subject Access Request) Akışı
85
+
86
+ GDPR Art. 15 + 17 gereği kullanıcı:
87
+ - Verilerine **erişim** isteyebilir → site sahibi audit log'tan döndürür
88
+ - **Silme** isteyebilir → audit log + cookie temizlenir
89
+ - **Onay geri çekme** isteyebilir → widget her zaman açık (`BlakfyCookie.open()`)
90
+
91
+ Site sahibinin yapması gereken:
92
+ - `data-blakfy-audit-endpoint` ile DSAR taleplerini sorgulayabileceği bir endpoint kurmak
93
+ - Privacy policy sayfasında DSAR talimatları yazmak (örnek README'de)
94
+
95
+ ---
96
+
97
+ ## Maliyet Özeti
98
+
99
+ | Kalem | Yıllık |
100
+ |---|---|
101
+ | IAB Europe sertifikasyon ücreti | ~€2.000 |
102
+ | Audit hazırlık (developer saati) | bir kerelik, dahil |
103
+ | GVL CDN serving (Cloudflare) | ücretsiz (consensu.org host eder) |
104
+ | **TOPLAM** | **~€2.000/yıl** |
105
+
106
+ Eğer site AdSense/Ad Manager kullanmıyorsa **sertifikasyona gerek yok**, kod yine de hazır kalır.
@@ -0,0 +1,76 @@
1
+ /*!
2
+ * Blakfy Cookie Widget v2.1.0
3
+ * https://github.com/tariktunc/blakfy-cookie
4
+ * MIT License | (c) Blakfy Studio
5
+ *
6
+ * KVKK + GDPR + CCPA + Google CMv2 + Microsoft UET + Yandex + TCF v2.2 + GPC + DNT
7
+ * 23 languages | 18 presets | Tag-gating | Powered by Blakfy Studio
8
+ */
9
+ (() => {
10
+ // src/compliance/google-cmv2.js
11
+ var defaultsInstalled = false;
12
+ var installDefaults = () => {
13
+ if (typeof window === "undefined") return;
14
+ if (defaultsInstalled) return;
15
+ defaultsInstalled = true;
16
+ window.dataLayer = window.dataLayer || [];
17
+ if (typeof window.gtag !== "function") {
18
+ window.gtag = function() {
19
+ window.dataLayer.push(arguments);
20
+ };
21
+ }
22
+ window.gtag("consent", "default", {
23
+ ad_storage: "denied",
24
+ ad_user_data: "denied",
25
+ ad_personalization: "denied",
26
+ analytics_storage: "denied",
27
+ functionality_storage: "denied",
28
+ personalization_storage: "denied",
29
+ security_storage: "granted",
30
+ wait_for_update: 500
31
+ });
32
+ };
33
+
34
+ // src/compliance/microsoft-uet.js
35
+ var defaultsInstalled2 = false;
36
+ var installDefaults2 = () => {
37
+ if (typeof window === "undefined") return;
38
+ if (defaultsInstalled2) return;
39
+ defaultsInstalled2 = true;
40
+ window.uetq = window.uetq || [];
41
+ window.uetq.push("consent", "default", { ad_storage: "denied" });
42
+ };
43
+
44
+ // src/compliance/yandex-metrica.js
45
+ var defaultsInstalled3 = false;
46
+ var installDefaults3 = () => {
47
+ if (typeof window === "undefined") return;
48
+ if (defaultsInstalled3) return;
49
+ defaultsInstalled3 = true;
50
+ if (typeof window.ym !== "function") {
51
+ window.ym = function() {
52
+ };
53
+ window.ym.__blakfyStub = true;
54
+ }
55
+ };
56
+
57
+ // src/cookie-defaults.js
58
+ (function() {
59
+ if (typeof window === "undefined") return;
60
+ if (window.__blakfyConsentDefaultsLoaded) return;
61
+ window.__blakfyConsentDefaultsLoaded = true;
62
+ try {
63
+ installDefaults();
64
+ } catch (e) {
65
+ }
66
+ try {
67
+ installDefaults2();
68
+ } catch (e) {
69
+ }
70
+ try {
71
+ installDefaults3();
72
+ } catch (e) {
73
+ }
74
+ })();
75
+ })();
76
+ /*! For license information please see cookie-defaults.js.LEGAL.txt */
File without changes
@@ -0,0 +1,10 @@
1
+ /*!
2
+ * Blakfy Cookie Widget v2.1.0
3
+ * https://github.com/tariktunc/blakfy-cookie
4
+ * MIT License | (c) Blakfy Studio
5
+ *
6
+ * KVKK + GDPR + CCPA + Google CMv2 + Microsoft UET + Yandex + TCF v2.2 + GPC + DNT
7
+ * 23 languages | 18 presets | Tag-gating | Powered by Blakfy Studio
8
+ */
9
+ (()=>{var n=!1,e=()=>{typeof window!="undefined"&&(n||(n=!0,window.dataLayer=window.dataLayer||[],typeof window.gtag!="function"&&(window.gtag=function(){window.dataLayer.push(arguments)}),window.gtag("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"granted",wait_for_update:500})))};var a=!1,o=()=>{typeof window!="undefined"&&(a||(a=!0,window.uetq=window.uetq||[],window.uetq.push("consent","default",{ad_storage:"denied"})))};var i=!1,d=()=>{typeof window!="undefined"&&(i||(i=!0,typeof window.ym!="function"&&(window.ym=function(){},window.ym.__blakfyStub=!0)))};(function(){if(typeof window!="undefined"&&!window.__blakfyConsentDefaultsLoaded){window.__blakfyConsentDefaultsLoaded=!0;try{e()}catch(t){}try{o()}catch(t){}try{d()}catch(t){}}})();})();
10
+ /*! For license information please see cookie-defaults.min.js.LEGAL.txt */
File without changes