diff --git a/backend/news/+dsgvo.feature b/backend/news/+dsgvo.feature
new file mode 100644
index 0000000..2dd540c
--- /dev/null
+++ b/backend/news/+dsgvo.feature
@@ -0,0 +1 @@
+Add control panel for GDPR / DSGVO settings. @davisagli
diff --git a/backend/news/+dsgvoTrackerPrivacy.feature b/backend/news/+dsgvoTrackerPrivacy.feature
new file mode 100644
index 0000000..ff3c2b5
--- /dev/null
+++ b/backend/news/+dsgvoTrackerPrivacy.feature
@@ -0,0 +1 @@
+Add tracker, tracker options and privacy URL fields to the DSGVO control panel. @iFlameing
diff --git a/backend/pyproject.toml b/backend/pyproject.toml
index a7be5ee..6ec2f41 100644
--- a/backend/pyproject.toml
+++ b/backend/pyproject.toml
@@ -182,6 +182,8 @@ lint.select = [
lint.ignore = [
# DoNotAssignLambda
"E731",
+ # https://docs.astral.sh/ruff/rules/suppressible-exception/
+ "SIM105",
]
[tool.ruff.lint.isort]
diff --git a/backend/src/kitconcept/website/controlpanels/configure.zcml b/backend/src/kitconcept/website/controlpanels/configure.zcml
index fb8b793..a7dc44d 100644
--- a/backend/src/kitconcept/website/controlpanels/configure.zcml
+++ b/backend/src/kitconcept/website/controlpanels/configure.zcml
@@ -1,3 +1,12 @@
+
+
+
diff --git a/backend/src/kitconcept/website/controlpanels/dsgvo.py b/backend/src/kitconcept/website/controlpanels/dsgvo.py
new file mode 100644
index 0000000..0870cc4
--- /dev/null
+++ b/backend/src/kitconcept/website/controlpanels/dsgvo.py
@@ -0,0 +1,155 @@
+from kitconcept.website import _
+from kitconcept.website.interfaces import IBrowserLayer
+from plone.autoform import directives
+from plone.registry.interfaces import IRegistry
+from plone.restapi.controlpanels import RegistryConfigletPanel
+from plone.restapi.interfaces import ISiteEndpointExpander
+from plone.schema import JSONField
+from zope import schema
+from zope.component import adapter
+from zope.component import getUtility
+from zope.interface import Interface
+from zope.interface import implementer
+from zope.schema.vocabulary import SimpleVocabulary
+
+import json
+
+
+# These are the modules supported in
+# https://github.com/kitconcept/volto-dsgvo-banner/blob/main/packages/volto-dsgvo-banner/src/components/Block/View.jsx
+DSGVO_MODULES = SimpleVocabulary.fromValues([
+ "tracking",
+ "youtube",
+ "facebook",
+ "google",
+ "vimeo",
+ "twitter",
+])
+
+DSGVO_TRACKERS = SimpleVocabulary.fromValues(["google", "matomo"])
+
+TRACKER_OPTIONS_SCHEMA = json.dumps({
+ "type": "object",
+})
+
+PRIVACY_URL_SCHEMA = json.dumps({
+ "type": "object",
+})
+
+
+class IDSGVOSettings(Interface):
+ """Settings for @kitconcept/volto-dsgvo-banner"""
+
+ show_banner = schema.Bool(
+ title=_("label_dsgvo_show_banner", default="Show GDPR banner on first visit"),
+ description=_(
+ "help_dsgvo_show_banner",
+ default="If true, the cookie consent banner will be shown immediately. "
+ "If false, users will be prompted to accept cookies only in the context "
+ "of blocks where they are needed.",
+ ),
+ default=True,
+ )
+
+ modules = schema.List(
+ title=_("label_dsgvo_modules", default="Show privacy settings for"),
+ description=_(
+ "help_dsgvo_modules",
+ default="List of 3rd-party sites to be shown in privacy preferences.",
+ ),
+ value_type=schema.Choice(
+ vocabulary=DSGVO_MODULES,
+ ),
+ default=["tracking", "youtube", "facebook", "google"],
+ required=True,
+ )
+
+ tracker = schema.Choice(
+ title=_("label_dsgvo_tracker", default="Tracker"),
+ description=_(
+ "help_dsgvo_tracker",
+ default="Analytics tracker to use. Choose 'google' for Google Analytics "
+ "or 'matomo' for Matomo.",
+ ),
+ vocabulary=DSGVO_TRACKERS,
+ required=False,
+ default=None,
+ )
+
+ directives.widget(
+ "tracker_options",
+ frontendOptions={
+ "widget": "modalJSONEditor",
+ },
+ )
+ tracker_options = JSONField(
+ title=_("label_dsgvo_tracker_options", default="Tracker options"),
+ description=_(
+ "help_dsgvo_tracker_options",
+ default="JSON object with tracker configuration. "
+ 'For Google Analytics: {"id": "G-XXXXXXX", "gaOptions": {"anonymizeIp": true}}. '
+ 'For Matomo: {"id": 1, "urlBase": "https://matomo.example.com/"}.',
+ ),
+ schema=TRACKER_OPTIONS_SCHEMA,
+ required=False,
+ default=None,
+ missing_value=None,
+ widget="",
+ )
+
+ directives.widget(
+ "privacy_url",
+ frontendOptions={
+ "widget": "modalJSONEditor",
+ },
+ )
+ privacy_url = JSONField(
+ title=_("label_dsgvo_privacy_url", default="Privacy policy URL"),
+ description=_(
+ "help_dsgvo_privacy_url",
+ default="JSON object mapping language codes to privacy policy paths or URLs. "
+ 'Example: {"en": "/en/privacy", "de": "/de/datenschutz"}.',
+ ),
+ schema=PRIVACY_URL_SCHEMA,
+ required=False,
+ default=None,
+ missing_value=None,
+ widget="",
+ )
+
+
+@adapter(Interface, Interface)
+class DSGVOControlpanel(RegistryConfigletPanel):
+ """REST API control panel for DSGVO settings."""
+
+ schema = IDSGVOSettings
+ configlet_id = "dsgvo-settings"
+ configlet_category_id = "plone-general"
+ schema_prefix = "kitconcept.website.dsgvo"
+
+
+@adapter(Interface, IBrowserLayer)
+@implementer(ISiteEndpointExpander)
+class DSGVOSiteEndpointExpander:
+ """Add DSGVO settings to the @site endpoint."""
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self, data):
+ registry = getUtility(IRegistry)
+ settings = registry.forInterface(
+ IDSGVOSettings, prefix="kitconcept.website.dsgvo", check=False
+ )
+ try:
+ data["kitconcept.website.dsgvo"] = {
+ "show_banner": settings.show_banner,
+ "modules": settings.modules,
+ "tracker": settings.tracker,
+ "tracker_options": settings.tracker_options,
+ "privacy_url": settings.privacy_url,
+ }
+ except AttributeError:
+ # Probably the upgrade step wasn't run yet, so the records don't exist.
+ pass
diff --git a/backend/src/kitconcept/website/locales/de/LC_MESSAGES/kitconcept.website.po b/backend/src/kitconcept/website/locales/de/LC_MESSAGES/kitconcept.website.po
new file mode 100644
index 0000000..39f89f6
--- /dev/null
+++ b/backend/src/kitconcept/website/locales/de/LC_MESSAGES/kitconcept.website.po
@@ -0,0 +1,87 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2026-06-17 12:10+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+"Language-Code: de\n"
+"Language-Name: German\n"
+"Preferred-Encodings: utf-8 latin1\n"
+"Domain: kitconcept.website\n"
+
+#: kitconcept/website/distributions.zcml:17
+msgid "A CMS solution for public websites. Created by kitconcept."
+msgstr ""
+
+#: kitconcept/website/profiles.zcml:14
+msgid "Configure a new site based on kitconcept.website"
+msgstr ""
+
+#: kitconcept/website/profiles/default/controlpanel.xml
+msgid "GDPR Settings"
+msgstr "DSGVO-Einstellungen"
+
+#. Default: "List of 3rd-party sites to be shown in privacy preferences."
+#: kitconcept/website/controlpanels/dsgvo.py:56
+msgid "help_dsgvo_modules"
+msgstr "Liste der Drittanbieter-Dienste, die in den Datenschutzeinstellungen angezeigt werden."
+
+#. Default: "JSON object mapping language codes to privacy policy paths or URLs. Example: {\"en\": \"/en/privacy\", \"de\": \"/de/datenschutz\"}."
+#: kitconcept/website/controlpanels/dsgvo.py:108
+#, fuzzy
+msgid "help_dsgvo_privacy_url"
+msgstr "JSON-Objekt, das Sprachcodes auf Pfade oder URLs zur Datenschutzrichtlinie abbildet. Beispiel: {\"en\": \"/en/privacy\", \"de\": \"/de/datenschutz\"}."
+
+#. Default: "If true, the cookie consent banner will be shown immediately. If false, users will be prompted to accept cookies only in the context of blocks where they are needed."
+#: kitconcept/website/controlpanels/dsgvo.py:45
+msgid "help_dsgvo_show_banner"
+msgstr "Wenn aktiviert, wird das Cookie-Zustimmungsbanner sofort angezeigt. Wenn deaktiviert, werden Benutzer nur im Kontext von Blöcken, in denen Cookies benötigt werden, zur Zustimmung aufgefordert."
+
+#. Default: "Analytics tracker to use. Choose 'google' for Google Analytics or 'matomo' for Matomo."
+#: kitconcept/website/controlpanels/dsgvo.py:69
+msgid "help_dsgvo_tracker"
+msgstr "Zu verwendender Analytics-Tracker. Wählen Sie 'google' für Google Analytics oder 'matomo' für Matomo."
+
+#. Default: "JSON object with tracker configuration. For Google Analytics: {\"id\": \"G-XXXXXXX\", \"gaOptions\": {\"anonymizeIp\": true}}. For Matomo: {\"id\": 1, \"urlBase\": \"https://matomo.example.com/\"}."
+#: kitconcept/website/controlpanels/dsgvo.py:87
+#, fuzzy
+msgid "help_dsgvo_tracker_options"
+msgstr "JSON-Objekt mit Tracker-Konfiguration. Für Google Analytics: {\"id\": \"G-XXXXXXX\", \"gaOptions\": {\"anonymizeIp\": true}}. Für Matomo: {\"id\": 1, \"urlBase\": \"https://matomo.example.com/\"}."
+
+#: kitconcept/website/distributions.zcml:17
+msgid "kitconcept Website"
+msgstr ""
+
+#: kitconcept/website/profiles.zcml:14
+msgid "kitconcept.website"
+msgstr ""
+
+#. Default: "Show privacy settings for"
+#: kitconcept/website/controlpanels/dsgvo.py:55
+msgid "label_dsgvo_modules"
+msgstr "Datenschutzeinstellungen anzeigen für"
+
+#. Default: "Privacy policy URL"
+#: kitconcept/website/controlpanels/dsgvo.py:107
+msgid "label_dsgvo_privacy_url"
+msgstr "Datenschutzrichtlinien-URL"
+
+#. Default: "Show GDPR banner on first visit"
+#: kitconcept/website/controlpanels/dsgvo.py:44
+msgid "label_dsgvo_show_banner"
+msgstr "DSGVO-Banner beim ersten Besuch anzeigen"
+
+#. Default: "Tracker"
+#: kitconcept/website/controlpanels/dsgvo.py:68
+msgid "label_dsgvo_tracker"
+msgstr "Tracker"
+
+#. Default: "Tracker options"
+#: kitconcept/website/controlpanels/dsgvo.py:86
+msgid "label_dsgvo_tracker_options"
+msgstr "Tracker-Optionen"
diff --git a/backend/src/kitconcept/website/locales/en/LC_MESSAGES/kitconcept.site.po b/backend/src/kitconcept/website/locales/en/LC_MESSAGES/kitconcept.site.po
deleted file mode 100644
index a9830da..0000000
--- a/backend/src/kitconcept/website/locales/en/LC_MESSAGES/kitconcept.site.po
+++ /dev/null
@@ -1,31 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2025-05-28 08:40+0000\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0\n"
-"Language-Code: en\n"
-"Language-Name: English\n"
-"Preferred-Encodings: utf-8 latin1\n"
-"Domain: kitconcept.website\n"
-
-#: kitconcept/website/distributions.zcml:16
-msgid "A CMS solution for public websites. Created by kitconcept."
-msgstr ""
-
-#: kitconcept/website/profiles.zcml:14
-msgid "Policy package to install our site"
-msgstr ""
-
-#: kitconcept/website/distributions.zcml:16
-msgid "kitconcept Site"
-msgstr ""
-
-#: kitconcept/website/profiles.zcml:14
-msgid "kitconcept.website: Install"
-msgstr ""
diff --git a/backend/src/kitconcept/website/locales/en/LC_MESSAGES/kitconcept.website.po b/backend/src/kitconcept/website/locales/en/LC_MESSAGES/kitconcept.website.po
new file mode 100644
index 0000000..9cd7395
--- /dev/null
+++ b/backend/src/kitconcept/website/locales/en/LC_MESSAGES/kitconcept.website.po
@@ -0,0 +1,85 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2026-06-17 12:10+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+"Language-Code: en\n"
+"Language-Name: English\n"
+"Preferred-Encodings: utf-8 latin1\n"
+"Domain: kitconcept.website\n"
+
+#: kitconcept/website/distributions.zcml:17
+msgid "A CMS solution for public websites. Created by kitconcept."
+msgstr ""
+
+#: kitconcept/website/profiles.zcml:14
+msgid "Configure a new site based on kitconcept.website"
+msgstr ""
+
+#: kitconcept/website/profiles/default/controlpanel.xml
+msgid "GDPR Settings"
+msgstr ""
+
+#. Default: "List of 3rd-party sites to be shown in privacy preferences."
+#: kitconcept/website/controlpanels/dsgvo.py:56
+msgid "help_dsgvo_modules"
+msgstr ""
+
+#. Default: "JSON object mapping language codes to privacy policy paths or URLs. Example: {\"en\": \"/en/privacy\", \"de\": \"/de/datenschutz\"}."
+#: kitconcept/website/controlpanels/dsgvo.py:108
+msgid "help_dsgvo_privacy_url"
+msgstr ""
+
+#. Default: "If true, the cookie consent banner will be shown immediately. If false, users will be prompted to accept cookies only in the context of blocks where they are needed."
+#: kitconcept/website/controlpanels/dsgvo.py:45
+msgid "help_dsgvo_show_banner"
+msgstr ""
+
+#. Default: "Analytics tracker to use. Choose 'google' for Google Analytics or 'matomo' for Matomo."
+#: kitconcept/website/controlpanels/dsgvo.py:69
+msgid "help_dsgvo_tracker"
+msgstr ""
+
+#. Default: "JSON object with tracker configuration. For Google Analytics: {\"id\": \"G-XXXXXXX\", \"gaOptions\": {\"anonymizeIp\": true}}. For Matomo: {\"id\": 1, \"urlBase\": \"https://matomo.example.com/\"}."
+#: kitconcept/website/controlpanels/dsgvo.py:87
+msgid "help_dsgvo_tracker_options"
+msgstr ""
+
+#: kitconcept/website/distributions.zcml:17
+msgid "kitconcept Website"
+msgstr ""
+
+#: kitconcept/website/profiles.zcml:14
+msgid "kitconcept.website"
+msgstr ""
+
+#. Default: "Show privacy settings for"
+#: kitconcept/website/controlpanels/dsgvo.py:55
+msgid "label_dsgvo_modules"
+msgstr ""
+
+#. Default: "Privacy policy URL"
+#: kitconcept/website/controlpanels/dsgvo.py:107
+msgid "label_dsgvo_privacy_url"
+msgstr ""
+
+#. Default: "Show GDPR banner on first visit"
+#: kitconcept/website/controlpanels/dsgvo.py:44
+msgid "label_dsgvo_show_banner"
+msgstr ""
+
+#. Default: "Tracker"
+#: kitconcept/website/controlpanels/dsgvo.py:68
+msgid "label_dsgvo_tracker"
+msgstr ""
+
+#. Default: "Tracker options"
+#: kitconcept/website/controlpanels/dsgvo.py:86
+msgid "label_dsgvo_tracker_options"
+msgstr ""
diff --git a/backend/src/kitconcept/website/locales/kitconcept.site.pot b/backend/src/kitconcept/website/locales/kitconcept.site.pot
deleted file mode 100644
index 1965224..0000000
--- a/backend/src/kitconcept/website/locales/kitconcept.site.pot
+++ /dev/null
@@ -1,34 +0,0 @@
-#--- PLEASE EDIT THE LINES BELOW CORRECTLY ---
-#SOME DESCRIPTIVE TITLE.
-#FIRST AUTHOR , YEAR.
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2025-05-28 08:40+0000\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0\n"
-"Language-Code: en\n"
-"Language-Name: English\n"
-"Preferred-Encodings: utf-8 latin1\n"
-"Domain: kitconcept.website\n"
-
-#: kitconcept/website/distributions.zcml:16
-msgid "A CMS solution for public websites. Created by kitconcept."
-msgstr ""
-
-#: kitconcept/website/profiles.zcml:14
-msgid "Policy package to install our site"
-msgstr ""
-
-#: kitconcept/website/distributions.zcml:16
-msgid "kitconcept Site"
-msgstr ""
-
-#: kitconcept/website/profiles.zcml:14
-msgid "kitconcept.website: Install"
-msgstr ""
diff --git a/backend/src/kitconcept/website/locales/kitconcept.website.pot b/backend/src/kitconcept/website/locales/kitconcept.website.pot
new file mode 100644
index 0000000..f78ff17
--- /dev/null
+++ b/backend/src/kitconcept/website/locales/kitconcept.website.pot
@@ -0,0 +1,88 @@
+#--- PLEASE EDIT THE LINES BELOW CORRECTLY ---
+#SOME DESCRIPTIVE TITLE.
+#FIRST AUTHOR , YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2026-06-17 12:10+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+"Language-Code: en\n"
+"Language-Name: English\n"
+"Preferred-Encodings: utf-8 latin1\n"
+"Domain: kitconcept.website\n"
+
+#: kitconcept/website/distributions.zcml:17
+msgid "A CMS solution for public websites. Created by kitconcept."
+msgstr ""
+
+#: kitconcept/website/profiles.zcml:14
+msgid "Configure a new site based on kitconcept.website"
+msgstr ""
+
+#: kitconcept/website/profiles/default/controlpanel.xml
+msgid "GDPR Settings"
+msgstr ""
+
+#. Default: "List of 3rd-party sites to be shown in privacy preferences."
+#: kitconcept/website/controlpanels/dsgvo.py:56
+msgid "help_dsgvo_modules"
+msgstr ""
+
+#. Default: "JSON object mapping language codes to privacy policy paths or URLs. Example: {\"en\": \"/en/privacy\", \"de\": \"/de/datenschutz\"}."
+#: kitconcept/website/controlpanels/dsgvo.py:108
+msgid "help_dsgvo_privacy_url"
+msgstr ""
+
+#. Default: "If true, the cookie consent banner will be shown immediately. If false, users will be prompted to accept cookies only in the context of blocks where they are needed."
+#: kitconcept/website/controlpanels/dsgvo.py:45
+msgid "help_dsgvo_show_banner"
+msgstr ""
+
+#. Default: "Analytics tracker to use. Choose 'google' for Google Analytics or 'matomo' for Matomo."
+#: kitconcept/website/controlpanels/dsgvo.py:69
+msgid "help_dsgvo_tracker"
+msgstr ""
+
+#. Default: "JSON object with tracker configuration. For Google Analytics: {\"id\": \"G-XXXXXXX\", \"gaOptions\": {\"anonymizeIp\": true}}. For Matomo: {\"id\": 1, \"urlBase\": \"https://matomo.example.com/\"}."
+#: kitconcept/website/controlpanels/dsgvo.py:87
+msgid "help_dsgvo_tracker_options"
+msgstr ""
+
+#: kitconcept/website/distributions.zcml:17
+msgid "kitconcept Website"
+msgstr ""
+
+#: kitconcept/website/profiles.zcml:14
+msgid "kitconcept.website"
+msgstr ""
+
+#. Default: "Show privacy settings for"
+#: kitconcept/website/controlpanels/dsgvo.py:55
+msgid "label_dsgvo_modules"
+msgstr ""
+
+#. Default: "Privacy policy URL"
+#: kitconcept/website/controlpanels/dsgvo.py:107
+msgid "label_dsgvo_privacy_url"
+msgstr ""
+
+#. Default: "Show GDPR banner on first visit"
+#: kitconcept/website/controlpanels/dsgvo.py:44
+msgid "label_dsgvo_show_banner"
+msgstr ""
+
+#. Default: "Tracker"
+#: kitconcept/website/controlpanels/dsgvo.py:68
+msgid "label_dsgvo_tracker"
+msgstr ""
+
+#. Default: "Tracker options"
+#: kitconcept/website/controlpanels/dsgvo.py:86
+msgid "label_dsgvo_tracker_options"
+msgstr ""
diff --git a/backend/src/kitconcept/website/profiles/default/controlpanel.xml b/backend/src/kitconcept/website/profiles/default/controlpanel.xml
index 39d3bda..294cd03 100644
--- a/backend/src/kitconcept/website/profiles/default/controlpanel.xml
+++ b/backend/src/kitconcept/website/profiles/default/controlpanel.xml
@@ -2,6 +2,18 @@
diff --git a/backend/src/kitconcept/website/profiles/default/metadata.xml b/backend/src/kitconcept/website/profiles/default/metadata.xml
index e76db3f..28197c8 100644
--- a/backend/src/kitconcept/website/profiles/default/metadata.xml
+++ b/backend/src/kitconcept/website/profiles/default/metadata.xml
@@ -1,6 +1,6 @@
- 20260611001
+ 20260617001
profile-kitconcept.contactblock:default
diff --git a/backend/src/kitconcept/website/profiles/default/registry/kitconcept.website.controlpanels.dsgvo.IDSGVOSettings.xml b/backend/src/kitconcept/website/profiles/default/registry/kitconcept.website.controlpanels.dsgvo.IDSGVOSettings.xml
new file mode 100644
index 0000000..40a11ff
--- /dev/null
+++ b/backend/src/kitconcept/website/profiles/default/registry/kitconcept.website.controlpanels.dsgvo.IDSGVOSettings.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/backend/src/kitconcept/website/profiles/default/registry/plone.i18n.interfaces.ILanguageSchema.xml b/backend/src/kitconcept/website/profiles/default/registry/plone.i18n.interfaces.ILanguageSchema.xml
deleted file mode 100644
index cd2730f..0000000
--- a/backend/src/kitconcept/website/profiles/default/registry/plone.i18n.interfaces.ILanguageSchema.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- en
-
- en
-
-
diff --git a/backend/src/kitconcept/website/upgrades/configure.zcml b/backend/src/kitconcept/website/upgrades/configure.zcml
index 506ec48..d32bae3 100644
--- a/backend/src/kitconcept/website/upgrades/configure.zcml
+++ b/backend/src/kitconcept/website/upgrades/configure.zcml
@@ -5,5 +5,6 @@
+
diff --git a/backend/src/kitconcept/website/upgrades/v20260617001/__init__.py b/backend/src/kitconcept/website/upgrades/v20260617001/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/backend/src/kitconcept/website/upgrades/v20260617001/configure.zcml b/backend/src/kitconcept/website/upgrades/v20260617001/configure.zcml
new file mode 100644
index 0000000..7c7a796
--- /dev/null
+++ b/backend/src/kitconcept/website/upgrades/v20260617001/configure.zcml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/backend/tests/settings/test_dsgvo_settings.py b/backend/tests/settings/test_dsgvo_settings.py
new file mode 100644
index 0000000..a2cf325
--- /dev/null
+++ b/backend/tests/settings/test_dsgvo_settings.py
@@ -0,0 +1,26 @@
+class TestDSGVOSettings:
+ def test_dsgvo_controlpanel(self, manager_request):
+ resp = manager_request.get("/@controlpanels/dsgvo-settings")
+ assert resp.status_code == 200
+ properties = resp.json()["schema"]["properties"]
+ assert "show_banner" in properties
+ assert "modules" in properties
+ assert "tracker" in properties
+ assert "tracker_options" in properties
+ assert "privacy_url" in properties
+
+ def test_dsgvo_settings_in_site_endpoint(self, anon_request):
+ resp = anon_request.get("/@site")
+ assert resp.status_code == 200
+ data = resp.json()
+ assert "kitconcept.website.dsgvo" in data
+ assert data["kitconcept.website.dsgvo"]["show_banner"] is True
+ assert data["kitconcept.website.dsgvo"]["modules"] == [
+ "tracking",
+ "youtube",
+ "facebook",
+ "google",
+ ]
+ assert data["kitconcept.website.dsgvo"]["tracker"] is None
+ assert data["kitconcept.website.dsgvo"]["tracker_options"] is None
+ assert data["kitconcept.website.dsgvo"]["privacy_url"] is None
diff --git a/docs/docs/_static/images/gdpr-settings-overview.png b/docs/docs/_static/images/gdpr-settings-overview.png
new file mode 100644
index 0000000..eae556c
Binary files /dev/null and b/docs/docs/_static/images/gdpr-settings-overview.png differ
diff --git a/docs/docs/_static/images/gdpr-settings-privacy-url-set.png b/docs/docs/_static/images/gdpr-settings-privacy-url-set.png
new file mode 100644
index 0000000..ac0b339
Binary files /dev/null and b/docs/docs/_static/images/gdpr-settings-privacy-url-set.png differ
diff --git a/docs/docs/_static/images/gdpr-settings-tracker-dropdown.png b/docs/docs/_static/images/gdpr-settings-tracker-dropdown.png
new file mode 100644
index 0000000..9f2eb1a
Binary files /dev/null and b/docs/docs/_static/images/gdpr-settings-tracker-dropdown.png differ
diff --git a/docs/docs/_static/images/gdpr-settings-tracker-options-modal.png b/docs/docs/_static/images/gdpr-settings-tracker-options-modal.png
new file mode 100644
index 0000000..6d9953d
Binary files /dev/null and b/docs/docs/_static/images/gdpr-settings-tracker-options-modal.png differ
diff --git a/docs/docs/how-to-guides/settings/configure-gdpr-settings.md b/docs/docs/how-to-guides/settings/configure-gdpr-settings.md
new file mode 100644
index 0000000..d57b2a0
--- /dev/null
+++ b/docs/docs/how-to-guides/settings/configure-gdpr-settings.md
@@ -0,0 +1,114 @@
+---
+myst:
+ html_meta:
+ description: "Configure the GDPR consent banner, third-party privacy modules, analytics tracker and privacy policy link."
+ keywords: "GDPR, DSGVO, cookie banner, privacy, Google Analytics, Matomo, control panel"
+doc_type: how-to
+audience: admin
+tags: [settings, privacy, gdpr]
+---
+
+# Configure GDPR settings
+
+This guide shows you how to configure the cookie consent banner, the third-party privacy modules shown to visitors, the analytics tracker, and the privacy policy link, all from the **GDPR Settings** control panel.
+
+## Prerequisites
+
+- You are logged in with a role that can access **Site Setup** (Manager or Site Administrator).
+
+## Steps
+
+### 1. Open the GDPR Settings control panel
+
+1. Go to **Site Setup**.
+2. Under the general settings, open **GDPR Settings**.
+
+
+
+### 2. Show or hide the banner on first visit
+
+Tick **Show GDPR banner on first visit** to display the cookie consent banner immediately to every visitor. Untick it if you only want visitors to be asked for consent in the context of blocks that need it (for example, a YouTube video block).
+
+### 3. Choose which privacy modules are shown
+
+In **Show privacy settings for**, add or remove the third-party services that visitors can individually allow or block in their privacy preferences. Available options are:
+
+- `tracking`
+- `youtube`
+- `facebook`
+- `google`
+- `vimeo`
+- `twitter`
+
+By default, `tracking`, `youtube`, `facebook`, and `google` are selected.
+
+### 4. Choose the analytics tracker
+
+In the **Tracker** field, select which analytics service the site should use:
+
+- `google` for Google Analytics.
+- `matomo` for Matomo.
+
+Leave it empty if you don't want to enable any analytics tracker.
+
+
+
+### 5. Configure the tracker options
+
+Click **Open configuration** next to **Tracker options** to open the JSON editor:
+
+
+
+The modal opens with `null`. Replace it with the configuration for the tracker you selected in step 4:
+
+- For Google Analytics:
+
+ ```json
+ {
+ "id": "G-XXXXXXX",
+ "gaOptions": { "anonymizeIp": true }
+ }
+ ```
+
+- For Matomo:
+
+ ```json
+ {
+ "id": 1,
+ "urlBase": "https://matomo.example.com/"
+ }
+ ```
+
+Click **Close** to save the JSON and return to the control panel.
+
+### 6. Set the privacy policy URL
+
+Click **Open configuration** next to **Privacy policy URL** to open the JSON editor. Enter a JSON object that maps each language code to the path or URL of the privacy policy page for that language. The cookie consent banner automatically picks the URL that matches the visitor's current language.
+
+For a site with English and German:
+
+```json
+{
+ "en": "/en/privacy",
+ "de": "/de/datenschutz"
+}
+```
+
+
+
+The modal opens with `null`. Replace it with your JSON object, then click **Close** to save and return to the control panel.
+
+### 7. Save
+
+Click **Save** in the left toolbar.
+
+## Verification
+
+1. Visit the site as an anonymous user. If you enabled the banner on first visit, it should appear immediately.
+2. Open the privacy preferences and confirm that only the modules you selected in step 3 are listed.
+3. Click the privacy policy link in the banner and confirm it leads to the correct language-specific page you configured in step 6.
+4. Accept tracking and confirm that the analytics requests for the tracker you configured (Google Analytics or Matomo) are sent.
+
+## Notes
+
+- These settings apply to the `@kitconcept/volto-dsgvo-banner` add-on bundled with this distribution. Without that add-on installed, this control panel has no effect on the front end.
diff --git a/frontend/mrs.developer.json b/frontend/mrs.developer.json
index 6d65242..02dddbe 100644
--- a/frontend/mrs.developer.json
+++ b/frontend/mrs.developer.json
@@ -70,7 +70,7 @@
"package": "@kitconcept/volto-dsgvo-banner",
"url": "git@github.com:kitconcept/volto-dsgvo-banner.git",
"https": "https://github.com/kitconcept/volto-dsgvo-banner.git",
- "tag": "4.0.0-alpha.1"
+ "tag": "tracker-settings-ttw"
},
"volto-heading-block": {
"develop": true,
diff --git a/frontend/packages/kitconcept-website/news/+dsgvo.feature b/frontend/packages/kitconcept-website/news/+dsgvo.feature
new file mode 100644
index 0000000..2dd540c
--- /dev/null
+++ b/frontend/packages/kitconcept-website/news/+dsgvo.feature
@@ -0,0 +1 @@
+Add control panel for GDPR / DSGVO settings. @davisagli
diff --git a/frontend/packages/kitconcept-website/news/+dsgvoTrackerPrivacy.feature b/frontend/packages/kitconcept-website/news/+dsgvoTrackerPrivacy.feature
new file mode 100644
index 0000000..ff3c2b5
--- /dev/null
+++ b/frontend/packages/kitconcept-website/news/+dsgvoTrackerPrivacy.feature
@@ -0,0 +1 @@
+Add tracker, tracker options and privacy URL fields to the DSGVO control panel. @iFlameing
diff --git a/frontend/packages/kitconcept-website/src/config/settings.ts b/frontend/packages/kitconcept-website/src/config/settings.ts
index 1a5d99c..35ff40f 100644
--- a/frontend/packages/kitconcept-website/src/config/settings.ts
+++ b/frontend/packages/kitconcept-website/src/config/settings.ts
@@ -1,8 +1,20 @@
import { ConfigType } from '@plone/registry';
+import newsSVG from '@plone/volto/icons/news.svg';
export default function install(config: ConfigType) {
config.settings.supportedLanguages = ['de', 'en'];
+ // Clear DSGVO add-on settings so it gets them from the `@site` endpoint
+ const dsgvoSettings = config.settings.DSGVOBanner as {
+ showBanner?: boolean;
+ modules?: Array;
+ };
+ delete dsgvoSettings.showBanner;
+ delete dsgvoSettings.modules;
+ delete dsgvoSettings.tracker;
+ delete dsgvoSettings.privacy_url;
+ config.settings.controlPanelsIcons['dsgvo-settings'] = newsSVG;
+
// Volto Light Theme Configuration
config.settings.siteHeader = true;
config.settings.siteLabel = 'Site';
diff --git a/news/+gdprcontrolpanel.internal b/news/+gdprcontrolpanel.internal
new file mode 100644
index 0000000..755de2c
--- /dev/null
+++ b/news/+gdprcontrolpanel.internal
@@ -0,0 +1 @@
+Add docs for GDPR controlpanel. @iFlameing
\ No newline at end of file