Cookie consent for Django

The banner is one tag in base.html, with the key from your settings through a context processor. The consents your forms ask for are recorded from the view with one HTTP call, each with a signed receipt.

Set it up with your AI agent

Connect the Croombit MCP server to your editor or coding agent and paste this. It creates the site, the cookie categories and the banner, and edits your code.

Using Croombit: create a site for this project and keep the cookie categories it comes with. Write the banner text and publish the banner. Create a TEST publishable key for localhost:3000. This is a Django project: add a croombit context processor exposing CROOMBIT_PUBLISHABLE_KEY, put the cmp.js tag first in <head> of templates/base.html, and record the newsletter field of our signup view with requests.post to /v1/consent using CROOMBIT_SECRET_KEY.

The agent works in TEST. Going live takes two steps in the console: verify your domain and swap in a LIVE key — see going live.

Or by hand

1. Settings and a context processor

# settings.py
CROOMBIT_PUBLISHABLE_KEY = os.environ["CROOMBIT_PUBLISHABLE_KEY"]  # pk_test_… / pk_live_…
CROOMBIT_SECRET_KEY = os.environ["CROOMBIT_SECRET_KEY"]            # sk_… — server only

TEMPLATES[0]["OPTIONS"]["context_processors"].append("core.context_processors.croombit")

# core/context_processors.py
from django.conf import settings

def croombit(request):
    return {"CROOMBIT_KEY": settings.CROOMBIT_PUBLISHABLE_KEY}

2. Add the tag to base.html

{# templates/base.html #}
<head>
  <meta charset="utf-8">
  <script src="https://croombit.com/cmp.js" data-tc-api-key="{{ CROOMBIT_KEY }}"></script>
  {# …everything else after it #}
</head>

3. Hold back trackers

Tags in your templates: type="text/plain" plus data-tc-consent. They stay inert until the visitor grants that category.

<script type="text/plain" data-tc-consent="analytics" async
        src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>
<script type="text/plain" data-tc-consent="analytics">
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXX');
</script>

4. Record consents from your view

A plain POST /v1/consent with your secret key. The Idempotency-Key makes a retry safe. See Record and query consent.

import uuid
import requests
from django.conf import settings

# e.g. in the view that handles your signup form
requests.post(
    "https://api.croombit.com/v1/consent",
    headers={
        "Authorization": f"Bearer {settings.CROOMBIT_SECRET_KEY}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "subject": f"email:{user.email}",
        "purpose": "newsletter",
        "state": "GRANTED" if form.cleaned_data["newsletter"] else "DENIED",
        "channel": "signup_form",
    },
    timeout=10,
).raise_for_status()

Questions

I use django-csp. What do I allow?

https://croombit.com in script-src for the banner and https://api.croombit.com in connect-src for its calls.

Does it work with Wagtail?

Yes. Wagtail renders through Django templates; add the tag to the base template your pages extend.