مولّد شعار موافقة الكوكيز ذاتي الاستضافة
أجب عن بضعة أسئلة واحصل على شعار موافقة على الكوكيز تملكه أنت: HTML وCSS وJavaScript عادي خالص تلصقه مباشرة في موقعك. يحظر فعليًا النصوص البرمجية غير الأساسية حتى الموافقة، ويخزّن الاختيار في localStorage، ويضع زر «رفض الكل» بنفس بروز زر «قبول الكل» - وهو التفصيل الذي تفرضه جهات تنظيمية مثل CNIL الفرنسية تحديدًا. لا منصة موافقة خارجية، لا حساب، لا حد لعدد مشاهدات الصفحة.
كل شيء يُنشأ داخل متصفحك. المقتطف الذي تحصل عليه لا يُجري أي طلبات شبكة خاصة به - لا شبكة توصيل محتوى (CDN)، ولا خادم لإدارة الموافقات، ولا عدّاد مشاهدات صفحات قد ينفد.
يظهر في نص الشريط - يجب أن يعرف الزوار من يطلب الموافقة.
مطلوب. لا تكون الموافقة مستنيرة بدونه.
فئات ملفات تعريف الارتباط التي تحددها
Strictly necessary
معفاة من الموافقة، لذا فهي حاضرة دائمًا ولا يمكن إيقافها.
تعتبر هيئة CNIL الفرنسية نحو 6 أشهر ممارسة جيدة، سواء للرفض أو للموافقة.
يُتاح باسم window.cookieConsent ويُخزَّن تحت "cookieConsent.v1".
أمران لا يمكنك إيقافهما هنا
يظهر "رفض الكل" دائمًا بجانب "قبول الكل"، بنفس الحجم والوزن، في المستوى الأول من الشريط - وتُنشأ الفئات الاختيارية دائمًا غير محددة. هذان هما التفصيلان اللذان تفرض الجهات التنظيمية فعليًا غرامات على المواقع بسببهما، لذا لا يوجد عمدًا أي خيار لكسرهما.
- يجب إصلاحهAdd your site or company name - the banner has to say who is asking.
معاينة
We use cookies
This site uses cookies that are strictly necessary to run the site. With your permission we would also like to set optional cookies. You can accept them all, refuse them all, or choose category by category.
<style>
/* Cookie consent banner - generated by usezivo.com.
Dependency-free: no fonts, no CDN, no network requests of its own. */
.cc-cookieconsent-root { position: fixed; z-index: 2147483000; }
.cc-cookieconsent-backdrop {
position: fixed; inset: 0; z-index: 2147482999;
background: rgba(15, 23, 42, 0.45);
}
.cc-cookieconsent-banner {
position: fixed;
left: 0; right: 0; bottom: 0; max-width: none; border-radius: 0; border-left: 0; border-right: 0; border-bottom: 0;
box-sizing: border-box;
padding: 18px 20px;
background: #ffffff;
color: #0f172a;
border: 1px solid #e2e8f0;
border-radius: 14px;
box-shadow: 0 10px 40px rgba(15, 23, 42, 0.18);
font: 400 14px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
.cc-cookieconsent-title { margin: 0 0 6px; font-size: 15px; font-weight: 700; }
.cc-cookieconsent-text { margin: 0 0 14px; color: #475569; }
.cc-cookieconsent-text a { color: #2563eb; text-decoration: underline; }
/* Accept and Reject are deliberately the SAME component: same size, same
weight, same visual prominence, side by side at the first level. */
.cc-cookieconsent-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.cc-cookieconsent-btn {
appearance: none;
flex: 0 0 auto;
min-width: 148px;
padding: 11px 18px;
font: inherit;
font-weight: 600;
line-height: 1.2;
border-radius: 10px;
border: 1px solid #2563eb;
background: #2563eb;
color: #ffffff;
cursor: pointer;
}
.cc-cookieconsent-btn:hover { filter: brightness(0.94); }
.cc-cookieconsent-btn:focus-visible { outline: 3px solid #2563eb; outline-offset: 2px; }
.cc-cookieconsent-btn--secondary { background: transparent; color: #2563eb; }
.cc-cookieconsent-link {
appearance: none; background: none; border: 0; padding: 8px 4px;
font: inherit; color: #475569; text-decoration: underline; cursor: pointer;
}
.cc-cookieconsent-link:hover { color: #0f172a; }
.cc-cookieconsent-panel {
position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
box-sizing: border-box;
width: min(620px, calc(100vw - 32px));
max-height: min(760px, calc(100vh - 32px));
overflow-y: auto;
padding: 22px;
background: #ffffff; color: #0f172a;
border-radius: 16px;
box-shadow: 0 20px 60px rgba(15, 23, 42, 0.3);
font: 400 14px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
.cc-cookieconsent-panel h2 { margin: 0 0 6px; font-size: 17px; }
.cc-cookieconsent-panel-intro { margin: 0 0 16px; color: #475569; }
.cc-cookieconsent-cat {
padding: 14px 0;
border-top: 1px solid #e2e8f0;
}
.cc-cookieconsent-cat-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.cc-cookieconsent-cat-name { font-weight: 600; }
.cc-cookieconsent-cat-desc { margin: 6px 0 0; color: #64748b; font-size: 13px; }
.cc-cookieconsent-always { font-size: 12px; font-weight: 600; color: #16a34a; }
/* Switch */
.cc-cookieconsent-switch { position: relative; display: inline-block; width: 44px; height: 24px; flex: 0 0 auto; }
.cc-cookieconsent-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.cc-cookieconsent-slider {
position: absolute; inset: 0; border-radius: 999px;
background: #cbd5e1; transition: background 0.15s ease; pointer-events: none;
}
.cc-cookieconsent-slider::after {
content: ""; position: absolute; top: 3px; left: 3px;
width: 18px; height: 18px; border-radius: 50%; background: #fff;
transition: transform 0.15s ease;
}
.cc-cookieconsent-switch input:checked + .cc-cookieconsent-slider { background: #2563eb; }
.cc-cookieconsent-switch input:checked + .cc-cookieconsent-slider::after { transform: translateX(20px); }
.cc-cookieconsent-switch input:focus-visible + .cc-cookieconsent-slider { outline: 3px solid #2563eb; outline-offset: 2px; }
.cc-cookieconsent-panel-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; padding-top: 16px; border-top: 1px solid #e2e8f0; }
@media (max-width: 520px) {
.cc-cookieconsent-banner { left: 8px; right: 8px; bottom: 8px; max-width: none; border-radius: 14px; border: 1px solid #e2e8f0; transform: none; top: auto; }
.cc-cookieconsent-btn { flex: 1 1 100%; min-width: 0; }
}
@media (prefers-color-scheme: dark) {
.cc-cookieconsent-banner, .cc-cookieconsent-panel { background: #0f172a; color: #e2e8f0; border-color: #334155; }
.cc-cookieconsent-text, .cc-cookieconsent-panel-intro, .cc-cookieconsent-cat-desc { color: #94a3b8; }
.cc-cookieconsent-cat, .cc-cookieconsent-panel-actions { border-color: #334155; }
.cc-cookieconsent-link { color: #94a3b8; }
.cc-cookieconsent-link:hover { color: #e2e8f0; }
.cc-cookieconsent-slider { background: #475569; }
@media (max-width: 520px) { .cc-cookieconsent-banner { border-color: #334155; } }
}
</style>
<!-- Cookie consent banner - generated by usezivo.com. Paste before </body>. -->
<div id="cc-cookieconsent-banner" class="cc-cookieconsent-banner" role="dialog" aria-modal="false" aria-labelledby="cc-cookieconsent-title" hidden>
<p class="cc-cookieconsent-title" id="cc-cookieconsent-title">We use cookies</p>
<p class="cc-cookieconsent-text">This site uses cookies that are strictly necessary to run the site. With your permission we would also like to set optional cookies. You can accept them all, refuse them all, or choose category by category. <a href="/privacy">Privacy policy</a></p>
<div class="cc-cookieconsent-actions">
<button type="button" class="cc-cookieconsent-btn" data-cc-cookieconsent-action="accept">Accept all</button>
<button type="button" class="cc-cookieconsent-btn" data-cc-cookieconsent-action="reject">Reject all</button>
<button type="button" class="cc-cookieconsent-link" data-cc-cookieconsent-action="open">Customise</button>
</div>
</div>
<div id="cc-cookieconsent-panel" class="cc-cookieconsent-panel" role="dialog" aria-modal="true" aria-labelledby="cc-cookieconsent-panel-title" hidden>
<h2 id="cc-cookieconsent-panel-title">Cookie preferences</h2>
<p class="cc-cookieconsent-panel-intro">Strictly necessary cookies cannot be switched off. Every other category is off until you turn it on.</p>
<div class="cc-cookieconsent-cat">
<div class="cc-cookieconsent-cat-head">
<span class="cc-cookieconsent-cat-name">Strictly necessary</span>
<span class="cc-cookieconsent-always">Always active</span>
</div>
<p class="cc-cookieconsent-cat-desc">Needed for the site to work: security, load balancing, remembering what is in your basket and storing this cookie choice. These are exempt from consent.</p>
</div>
<div class="cc-cookieconsent-cat">
<div class="cc-cookieconsent-cat-head">
<span class="cc-cookieconsent-cat-name">Analytics</span>
<label class="cc-cookieconsent-switch">
<input type="checkbox" data-cc-cookieconsent-cat="analytics" aria-label="Analytics">
<span class="cc-cookieconsent-slider"></span>
</label>
</div>
<p class="cc-cookieconsent-cat-desc">Help us understand which pages are visited and where people get stuck, so we can improve the site. Measurement only, never used to target advertising.</p>
</div>
<div class="cc-cookieconsent-panel-actions">
<button type="button" class="cc-cookieconsent-btn" data-cc-cookieconsent-action="save">Save my choices</button>
<button type="button" class="cc-cookieconsent-btn cc-cookieconsent-btn--secondary" data-cc-cookieconsent-action="accept">Accept all</button>
<button type="button" class="cc-cookieconsent-btn cc-cookieconsent-btn--secondary" data-cc-cookieconsent-action="reject">Reject all</button>
</div>
</div>
<script>
/* Cookie consent - generated by usezivo.com. Vanilla JS, no dependencies,
no network requests. Paste after the markup, or load as an external file. */
(function () {
"use strict";
var KEY = "cookieConsent.v1";
var MAX_AGE_MS = 183 * 24 * 60 * 60 * 1000;
var OPTIONAL = ["analytics"];
var PREFIX = "cc-cookieconsent";
var banner = document.getElementById(PREFIX + "-banner");
var panel = document.getElementById(PREFIX + "-panel");
var backdrop = null;
var lastFocus = null;
// --- storage ------------------------------------------------------------
// localStorage can throw outright in some privacy modes, so every access is
// guarded. If it is unavailable the banner simply reappears next visit,
// which is the safe direction to fail in: nothing gets unblocked.
function read() {
try {
var raw = localStorage.getItem(KEY);
if (!raw) return null;
var saved = JSON.parse(raw);
if (!saved || typeof saved !== "object") return null;
if (typeof saved.at !== "number" || Date.now() - saved.at > MAX_AGE_MS) return null;
var out = { necessary: true };
for (var i = 0; i < OPTIONAL.length; i++) {
out[OPTIONAL[i]] = saved.categories && saved.categories[OPTIONAL[i]] === true;
}
return out;
} catch (e) {
return null;
}
}
function write(categories) {
try {
localStorage.setItem(KEY, JSON.stringify({ v: 1, at: Date.now(), categories: categories }));
} catch (e) {
/* storage blocked - the choice applies to this page load only */
}
}
var state = read();
// --- script gating ------------------------------------------------------
// Third-party tags are written as:
// <script type="text/plain" data-cookie-category="analytics" src="..."></script>
// The browser will not execute type="text/plain", so nothing runs until the
// matching category is granted, at which point the tag is swapped for a real
// one. Inline tags work the same way.
function unblock(granted) {
var pending = document.querySelectorAll('script[type="text/plain"][data-cookie-category]');
for (var i = 0; i < pending.length; i++) {
var node = pending[i];
var category = node.getAttribute("data-cookie-category");
if (!granted[category]) continue;
var real = document.createElement("script");
for (var a = 0; a < node.attributes.length; a++) {
var attr = node.attributes[a];
if (attr.name === "type" || attr.name === "data-cookie-category") continue;
real.setAttribute(attr.name, attr.value);
}
real.type = "text/javascript";
if (!node.src) real.text = node.text;
node.parentNode.replaceChild(real, node);
}
}
var listeners = [];
function emit(granted) {
unblock(granted);
for (var i = 0; i < listeners.length; i++) {
try {
listeners[i](granted);
} catch (e) {
/* one bad listener must not break the rest */
}
}
try {
document.dispatchEvent(new CustomEvent("cookieConsent:change", { detail: granted }));
} catch (e) {
/* CustomEvent unsupported - the callback API still works */
}
}
// --- UI -----------------------------------------------------------------
function showBanner() {
if (!banner) return;
banner.hidden = false;
/* no backdrop configured */
}
function hideBanner() {
if (banner) banner.hidden = true;
if (backdrop && backdrop.parentNode) {
backdrop.parentNode.removeChild(backdrop);
backdrop = null;
}
}
function boxes() {
return panel ? panel.querySelectorAll("[data-" + PREFIX + "-cat]") : [];
}
function openPanel() {
if (!panel) return;
lastFocus = document.activeElement;
// Reflect the stored choice, or leave every optional box OFF when there is
// no stored choice yet. Nothing is ever pre-ticked.
var current = read();
var list = boxes();
for (var i = 0; i < list.length; i++) {
var id = list[i].getAttribute("data-" + PREFIX + "-cat");
list[i].checked = !!(current && current[id]);
}
panel.hidden = false;
var first = panel.querySelector("button, input");
if (first) first.focus();
document.addEventListener("keydown", onKeydown);
}
function closePanel() {
if (!panel) return;
panel.hidden = true;
document.removeEventListener("keydown", onKeydown);
if (lastFocus && lastFocus.focus) lastFocus.focus();
}
function onKeydown(e) {
// Escape closes the PREFERENCES panel only. It never dismisses the banner:
// dismissing without choosing must not be treated as consent.
if (e.key === "Escape") closePanel();
}
function decide(categories) {
var granted = { necessary: true };
for (var i = 0; i < OPTIONAL.length; i++) {
granted[OPTIONAL[i]] = categories[OPTIONAL[i]] === true;
}
state = granted;
write(granted);
closePanel();
hideBanner();
emit(granted);
}
function all(value) {
var out = {};
for (var i = 0; i < OPTIONAL.length; i++) out[OPTIONAL[i]] = value;
return out;
}
function fromPanel() {
var out = {};
var list = boxes();
for (var i = 0; i < list.length; i++) {
out[list[i].getAttribute("data-" + PREFIX + "-cat")] = list[i].checked === true;
}
return out;
}
document.addEventListener("click", function (e) {
var target = e.target.closest ? e.target.closest("[data-" + PREFIX + "-action]") : null;
if (!target) return;
var action = target.getAttribute("data-" + PREFIX + "-action");
if (action === "accept") decide(all(true));
else if (action === "reject") decide(all(false));
else if (action === "save") decide(fromPanel());
else if (action === "open") openPanel();
else if (action === "close") closePanel();
});
// --- public API ---------------------------------------------------------
window["cookieConsent"] = {
/** true if that category has been granted. Always true for "necessary". */
has: function (category) {
if (category === "necessary") return true;
return !!(state && state[category]);
},
/** The full granted map, or null if no choice has been made yet. */
get: function () {
return state ? JSON.parse(JSON.stringify(state)) : null;
},
/** Run cb now (if a choice exists) and on every later change. Returns an unsubscribe fn. */
onChange: function (cb) {
listeners.push(cb);
if (state) {
try {
cb(state);
} catch (e) {
/* ignore */
}
}
return function () {
var i = listeners.indexOf(cb);
if (i > -1) listeners.splice(i, 1);
};
},
/** Wire this to a permanent "Cookie preferences" link in your footer. */
openPreferences: openPanel,
/** Forget the stored choice and ask again. Withdrawal must be as easy as consent. */
reset: function () {
try {
localStorage.removeItem(KEY);
} catch (e) {
/* ignore */
}
state = null;
showBanner();
},
};
// --- boot ---------------------------------------------------------------
if (state) {
// A stored choice: apply it silently, do not nag.
emit(state);
} else {
// No choice yet -> nothing is unblocked, and the banner asks.
showBanner();
}
})();
</script>يتم تحديث المقتطف مباشرة، لكن أصلح العناصر أعلاه قبل نشره.
من أين تأتي القواعد أعلاه
- CNIL - Questions-réponses sur les lignes directrices et la recommandation « cookies et autres traceurs »« Il doit toutefois être aussi facile d'accepter que de refuser les traceurs. » Continuing to browse is no longer valid consent and must be read as refusal; withdrawing consent must be as simple as giving it; ~6 months is good practice for storing the choice.
- CNIL - Recommandation « cookies et autres traceurs » (consolidated PDF)The recommendation itself: a « Tout refuser » button at the same level and with the same appearance as « Tout accepter » is a clear and simple way of letting users express their choice.
- CNIL - Cookies: la CNIL incite les organismes à auditer leurs sites webCNIL's own audit checklist, including the refusal-as-easy-as-acceptance point and the exemption for strictly necessary cookies.
تنتج هذه الأداة واجهة الشريط وآلية تخزين الموافقة. وهي ليست استشارة قانونية ولا يمكنها وحدها جعل الموقع متوافقًا - ما يهم فعليًا هو أي أدوات تتبع تستخدمها، وهل ربطتها فعليًا عبر البوابة، وما تنص عليه سياسة الخصوصية لديك. كما تختلف القواعد بين الدول وتتغير مع الوقت. إذا كانت المخاطر كبيرة، اطلب من محامٍ مراجعتها.
لماذا الاستضافة الذاتية بدلاً من Axeptio أو Cookiebot
منصات الموافقة المُستضافة منتجات ممتازة، لكن باقاتها المجانية مُقيَّدة بحصة: تجاوز حد شهري من مشاهدات الصفحة يجعل الشعار يتوقف عن العمل أو تبدأ الفاتورة. كما أنها تُحمّل جافاسكريبت خاصًا بها من نطاقها الخاص في كل مشاهدة صفحة، وهو طلب من طرف ثالث يُضاف إلى موقعك باسم الخصوصية، واعتمادية يمكن أن تتغير دون أن تتحكم بها.
المقتطف الذي تكتبه هذه الأداة يزن حوالي 6 كيلوبايت، ولا يحتوي على أي اعتماديات، ولا يُجري أي طلبات شبكة خاصة به، ويعيش في مستودعك الخاص حيث يمكنك قراءة كل سطر فيه. لا يوجد مزوّد قد تنتهي حصته، ولا شيء يتصل خفية بأي خادم خارجي.
| ما يفعله الشعار | كيف |
|---|---|
| يحظر العلامات قبل الموافقة | تُكتب علامات الطرف الثالث بصيغة type="text/plain" مع خاصية data-cookie-category، وهو ما ترفض المتصفحات تنفيذه. عند الموافقة، يُستبدل العنصر بعنصر سكريبت حقيقي، ولا يُنفَّذ إلا في تلك اللحظة. |
| الرفض سهل بقدر الموافقة | زرّا «قبول الكل» و«رفض الكل» هما نفس مكوّن الزر - بنفس العرض والحشو والوزن والألوان - جنبًا إلى جنب في المستوى الأول. |
| لا شيء محدَّد مسبقًا | مفاتيح التفضيل المُولَّدة لا تحمل خاصية checked أبدًا. أبدًا. |
| الصمت ليس موافقة | إغلاق الشعار أو تجاهله لا يخزّن شيئًا ولا يُلغي حظر شيء. فقط النقر الصريح يسجّل اختيارًا. |
| سحب الموافقة في أي وقت | تستدعي <ns/>.openPreferences() لإعادة فتح اللوحة، و.reset() لنسيان الاختيار - اربط أيًّا منهما برابط في تذييل الصفحة. |
| يتذكّر الإجابة | localStorage، مع طابع زمني وفترة انتهاء تختارها (6 أشهر افتراضيًا)، حتى لا يُسأل الزوار مجددًا في كل صفحة. |
الأسئلة الشائعة
كيف أنشئ شعار كوكيز مجاني ومتوافق دون منصة مدفوعة؟
أدخل اسم موقعك، رابط سياسة الخصوصية، وفئات الكوكيز التي تستخدمها فعليًا، ثم انسخ الكتلة المُولَّدة إلى صفحتك قبل وسم إغلاق body. تحصل على HTML وCSS وJavaScript عادي دون اعتماد على Axeptio أو Cookiebot أو Tarteaucitron أو أي منصة موافقة أخرى - فلا حد لعدد المشاهدات في الخطة المجانية ولا نص برمجي خارجي يُحمَّل في كل صفحة.
هل يحظر فعليًا Google Analytics قبل الموافقة، أم يخفي الشعار فقط؟
يحظره فعليًا، لكن عليك فعل شيء واحد: تغيير الوسم من type="text/javascript" إلى type="text/plain" وإضافة data-cookie-category="analytics". لا ينفّذ المتصفح نصًا من نوع text/plain، فيبقى الوسم خاملًا في الصفحة. وبمجرد أن يمنح الزائر تلك الفئة، يُستنسخ النص البرمجي في عنصر script حقيقي ويعمل.
لماذا لا يوجد خيار لإخفاء زر رفض الكل؟
لأن هذه هي المشكلة الأكثر ذكرًا في الشعارات غير المتوافقة. موقف CNIL هو أنه يجب أن يكون رفض المتتبعات سهلًا بقدر قبولها، وتعتبر زر «رفض الكل» في المستوى الأول، بنفس مظهر «قبول الكل»، هو الطريقة الواضحة لتحقيق ذلك. يُنتج هذا المولّد دائمًا الزرّين من نفس فئة CSS، فيكونان متطابقين في الحجم والوزن.
هل هذا يجعل موقعي متوافقًا قانونيًا مع GDPR؟
لا، واحذر من أي أداة تدّعي غير ذلك. هذا يولّد واجهة الشعار وآلية تخزين الموافقة. يعتمد التوافق أيضًا على المتتبعات التي تستخدمها فعليًا، وهل كل واحدة منها مرّت فعلًا عبر البوابة، وما تنص عليه سياسات الخصوصية والكوكيز لديك، وقواعد تختلف حسب البلد وتتغير بمرور الوقت.