BGH Ruling VI ZR 144/23: When Your Shop Sends Data to Third Parties

Germany's Federal Court of Justice allows injunctions against data transfers to third parties. What it decided, what is open and what a test shop really sends.

by ·

On 16 September 2026 heise online ran the headline “Landmark ruling: BGH strengthens consumer rights in online data sharing” (opens in a new tab). Behind it is a judgment of Germany's Federal Court of Justice (Bundesgerichtshof, BGH) of 21 July 2026, case number VI ZR 144/23. A claimant had sued an online shop because, by the claimant's own account, its pages sent data to Google, Facebook, Pinterest and other providers as soon as they loaded.

I run into this topic all the time. In WordPress and WooCommerce projects I regularly see themes and plugins that, unasked, pull fonts, videos, reCAPTCHA or whole libraries from third-party servers — and I rebuild them. The question that almost always follows is: what actually goes out? Until now the honest answer was usually: more than you think, but nobody knows exactly who hasn't looked.

So for this article I did both. I read the judgment together with both lower-court rulings, because a fair amount of the coverage is shortened or simply wrong. And I built a test shop, embedded typical third parties and logged what they send — with made-up data, and set up so that the data transmissions were intercepted instead of reaching the provider. That one transmission still slipped through on my first attempt is part of the results. By the end you will know what the BGH decided, what it left open, which data flows besides the IP address, and how to find and stop that on your own site.

A note on jurisdiction and on what this is. This article describes a German judgment. The underlying EU ruling allows each member state to provide injunctive relief under national law; the BGH confirmed that Germany's Civil Code does. Outside Germany, the GDPR analysis and the technical part transfer — whether you can be sued for an injunction the same way depends on your national law.

This is not legal advice. I am an IT consultant, not a lawyer, and I am not permitted to give legal advice — under the German Legal Services Act, advice on an individual case is reserved to lawyers. What you get here is prepared professional information: I trace every legal statement back to the judgment, a statute or a supervisory authority publication, and I mark throughout what is case law and what is my assessment. For a binding assessment of your shop you need a lawyer or your data protection officer. The technical part of this article, on the other hand, is squarely my field.

What the case was about

The defendant runs an online shop whose name is anonymised in all three judgments. Third-party functions are embedded in its pages so that the browser loads them directly from the providers' servers. In the process, the third-party server receives the visitor's IP address “to enable retrieval from there”. The judgment calls this a “so-called cloud solution” (BGH, para. 2 (opens in a new tab), German). What is meant is ordinary embedding, not a redirect.

Which services these were is not in the BGH judgment, but it is in the first-instance ruling. The claim before the Regional Court (Landgericht) of Wiesbaden (opens in a new tab) (German) lists 17 services:

Google Tag Manager, Google Analytics, Google Fonts, Google Recaptca, Google Optimize, Doubleclick, Youtube, Facebook, Pinterest, Taboola, Fonts Awesome, Fonts.com, Bing Ads, Cquotient, Amplify, Trbo, Zenloop — Regional Court of Wiesbaden, judgment of 20 January 2022 – 10 O 14/21, claim items a–q (spelling as in the judgment)

That is a fairly typical shop stack: tag manager and analytics, advertising and social pixels, three font services, video, captcha and product recommendations.

According to the claimant, an order was placed with the shop in 2020. The claimant alleges that besides the IP address, “numerous usage data from the ordering process” flowed to third parties (BGH, para. 3). The Higher Regional Court (Oberlandesgericht) of Frankfurt (opens in a new tab) (German) summarises this as “information about the hardware and software of [the claimant's] devices”; the alternative claims list, by way of example: IP address, time of access, referrer, operating system and browser with version, language settings, installed applications and supported programming languages. Name, postal address or email address are not on that list. Name and address appear only as proof of the order and as an argument for why the IP address points to the claimant. There is no claim that they went to third parties; an email address does not come up at all. Before the Higher Regional Court the claimant is described as a computer scientist who logged the network traffic during a later order.

The defendant countered that visitors had consented via the cookie banner, and that data processing agreements were in place with several of the services. To this day no court has decided whether that holds.

The path through the courts:

Court Date, case number Outcome
Regional Court of Wiesbaden 20 Jan 2022 – 10 O 14/21 Claim dismissed: request too vague, and unfounded in any case; the GDPR bars national claims, § 1004 of the Civil Code does not apply by analogy
Higher Regional Court of Frankfurt am Main 30 Mar 2023 – 16 U 22/22 Appeal dismissed: the new request (“any data”) is specific enough, but the GDPR governs the consequences exhaustively; no further appeal allowed
BGH, VI Civil Senate 21 Jul 2026 – VI ZR 144/23 Appeal on points of law (admitted by the BGH) successful: Frankfurt judgment set aside, case remitted

What the BGH decided

The core is in the headnote, and it is shorter than most of the headlines about it:

“A claim for injunctive relief under national law directed against a renewed transfer of personal data in breach of the General Data Protection Regulation cannot, as a matter of principle, be rejected by invoking an exhaustive regulatory content of the provisions of Union law.” — BGH, judgment of 21 July 2026 – VI ZR 144/23, headnote (my translation)

In plain terms: if you want to stop a transfer of your data that breaches data protection law, you may also use German civil law to do so. The Higher Regional Court had ruled out exactly that, because the GDPR was an “exhaustive, because fully harmonised” regime that left no room for national law without an opening clause (para. 7). That reasoning no longer holds.

The reason lies in Luxembourg. On 4 September 2025, in case C-655/23 (opens in a new tab), the Court of Justice of the European Union held that the GDPR itself provides no preventive injunction where the data subject does not also request erasure. But it does not prevent member states from providing such a remedy (para. 52). On the contrary: such an action is “such as to enhance the effectiveness of those provisions” (para. 50). The CJEU judgment came almost two and a half years after the Frankfurt judgment — Frankfurt could not have known it.

As legal bases, the BGH names two routes in the German Civil Code (Bürgerliches Gesetzbuch, BGB) (para. 15):

  • § 1004(1) and § 823(1) BGB by analogy, read with Art. 1(1) and Art. 2(1) of the Basic Law — the general right of personality in its form as the right to informational self-determination.
  • § 1004(1) sentence 2 by analogy and § 823(2) BGB, where a data protection provision is breached that qualifies as a protective law.

Two details strike me as more important in practice than the coverage makes them look.

First: “any data” is specific enough. The original wording, “personal or personally relatable data of the claimant – such as the claimant's IP address –”, was held too vague by both lower courts, because an enforcement court would first have to apply legal concepts. The main request filed later — to refrain from transmitting “any data of the claimant upon page access” without the claimant's consent to the services named in the request — does meet the requirements, “at any rate” (paras. 9–11). Anyone suing in future therefore has a wording the BGH accepted as specific enough — whether such a broad request is also well-founded is a separate question.

Second: the judgment does not stand alone. It is part of a line. In November 2024 the senate had still expressly left the question open (VI ZR 10/24, para. 83 (opens in a new tab), German). After the CJEU came VI ZR 375/24 (opens in a new tab) on 12 May 2026 (withdrawal of an unlawful report to the German credit agency SCHUFA — open whether under the GDPR itself, in any event under national law, German) and VI ZR 97/22 (opens in a new tab) on 23 June 2026 — the case that had been referred to the CJEU (German). VI ZR 144/23 carries this line over to third parties in online shops.

What the BGH did not decide

This is the difference between “landmark ruling” and “the shop lost”. The BGH awarded the claimant nothing. It rejected one line of reasoning of the Higher Regional Court and sent the case back. Among the things still open:

  • Whether the transfer was unlawful at all. The BGH only says a claim “cannot be ruled out” and the legal bases are “to be considered” (paras. 14–15).
  • Whether consent via the cookie banner was valid. The defendant relied on it; no court has examined it.
  • Whether the transferred data are personal data. That all data are personal “simply because they are transferred together with [the claimant's] IP address” is expressly reported by the BGH as “the claimant's view” (para. 11) — not as a finding of its own.
  • Whether there is a risk of repetition. Without it — or an imminent first infringement — there is no injunction. In VI ZR 97/22 the injunction request failed on exactly this point: a one-off misdirected message, the application process closed (paras. 26–30). The claimant there is nonetheless entitled to damages in principle.
  • Whether a national claim is superfluous where GDPR rights suffice in the individual case. The BGH leaves this open and only notes that on the facts found so far, none of the GDPR rights, in particular not erasure under Art. 17, achieves the claimant's aim (para. 16).

I see one more open point myself, without the judgment addressing it: in October 2025 the same senate held that an injunction request which also covers conduct that is unobjectionable under data protection law is too broad and therefore unfounded (VI ZR 431/24, headnote a (opens in a new tab), German). Whether “any data” fails that test was not discussed in VI ZR 144/23. Which of these questions the Higher Regional Court has to answer depends on what its decision turns on. How it will decide, nobody knows — and I am not forecasting it.

Where the coverage sounds different

Reading the reports, I noticed several things that do not match the judgment. This is no criticism of colleagues writing under time pressure — but if you set up your shop on that basis, you should know the differences:

  • “Consumer rights”. The word “consumer” does not appear in the judgment. The BGH speaks of the “data subject” (para. 13), the “injured party” (para. 15) and the “person concerned” (para. 16); the legal bases attach to the right of personality, not to consumer status. The BGH does not say so expressly, though. According to the Regional Court's statement of facts, the claimant ordered “as a consumer” — so the reports are right about the person, the claim just does not depend on it. In VI ZR 97/22 the claimant was a job applicant.
  • “The CJEU case was about compensation after a data leak.” In C-655/23 (opens in a new tab) a bank employee accidentally sent a message containing an applicant's salary expectations to a third party via a career network. The claims were for an injunction and compensation for non-material damage (paras. 2, 23–24). It was not a hack or mass leak but a single misdirected message — though in data protection terms very much a “personal data breach” within the meaning of Art. 4(12) GDPR.
  • “The browser is redirected to third-party servers.” The judgment says the browser is “directed” to the services' pages (para. 2). According to the Higher Regional Court's statement of facts, what is meant is that the functions are “embedded” — so loading embedded content, not redirecting the page.
  • “Without valid consent.” Stated as fact in some reports, but that is exactly what is open. Nor does § 25 of the German Telecommunications Digital Services Data Protection Act (TDDDG) appear in the judgment.
  • At least one report gives a wrong date (21 June instead of 21 July), another counts twelve instead of 17 services, and one suggests a “Regional Court of Frankfurt” as first instance — it was actually Wiesbaden.

Why the IP address alone matters

To place the judgment, you need three older building blocks.

An IP address is personal data if the recipient has legal means to have the person behind it identified via the internet access provider. The CJEU held this for dynamic IP addresses in 2016 (C-582/14 “Breyer” (opens in a new tab), operative part 1). That judgment still interpreted the old Data Protection Directive 95/46/EC. In 2022 the Regional Court of Munich I classified the dynamic IP address as personal data under the GDPR as well (3 O 17493/20, paras. 4–5).

If you embed it, you share responsibility. An online fashion retailer had embedded Facebook's “Like” button; on page load, the browser sent the IP address and browser data to Facebook — without a click, without a Facebook account. In 2019 the CJEU held that the website operator can be jointly responsible with the provider for collecting and transmitting that data, though not for what Facebook does with it afterwards (C-40/17 “Fashion ID” (opens in a new tab), operative part 2). This judgment, too, concerned the old directive. For shop operators the message still stands: “the provider loads it, not me” is not an argument.

Google Fonts, 2022. On 20 January 2022 the Regional Court of Munich I (opens in a new tab) (German) ordered a website operator (3 O 17493/20) to stop disclosing the claimant's IP address to Google by embedding Google Fonts, and awarded 100 euros in damages. Interesting in hindsight: the court already based the injunction on § 823(1) read with § 1004 BGB by analogy — exactly the route the BGH now keeps open in principle. It rejected a legitimate interest in a single sentence: Google Fonts could also be used without a connection to Google's servers being made on page load (para. 8).

What followed belongs in the picture too. A wave of warning letters came next. In December 2022 police and public prosecutors in Berlin searched premises of a law firm and a client on suspicion of fraudulent warning letters and attempted extortion in at least 2,418 cases, each demanding a settlement of 170 euros (police statement of 21 December 2022 (opens in a new tab), German). The allegation: the page visits are said to have been faked by software — with no person involved, there would be no infringement of personality rights, and whoever deliberately triggers the transfer effectively consents. I found no outcome of the proceedings; the presumption of innocence applies. In 2023 the Regional Court of Munich I (opens in a new tab) (German) found in one such case that the sender of the warning letter was entitled to neither an injunction nor compensation: no personally affected individual, abuse of rights (4 O 13063/22). The lesson: injunctive relief is a tool for people who are genuinely affected, not a business model.

Injunction is not compensation

The two get mixed up constantly. The CJEU separates them cleanly in C-655/23: compensation under Art. 82 GDPR “fulfils an exclusively compensatory function”, whereas the purpose of an injunction “is purely preventive” (para. 82). A mere infringement is not enough for compensation; the damage must be proven (C-300/21 (opens in a new tab), operative part 1 and para. 50). It can, however, lie in the loss of control over one's own data; for such a case, the BGH considered an amount in the region of 100 euros legally unobjectionable (VI ZR 10/24, paras. 98–101). An injunction, by contrast, is not about money for the past but about making it stop.

TDDDG or GDPR?

This gets muddled often, too. The German Data Protection Conference (DSK), the joint body of Germany's supervisory authorities, distinguishes two steps in its guidance for providers of digital services (opens in a new tab) (version 1.2, November 2024, German):

  • § 25 TDDDG governs storing information on the end device and reading it from there — cookies, local storage, but also a script that actively reads device properties and sends them to a server, for example to build a fingerprint (paras. 21, 24).
  • Art. 6 GDPR governs the processing of personal data after that. And explicitly: embedding third-party content “regularly involves a disclosure of personal data to the operators of the respective third-party server” — typical examples being “advertisements, fonts, scripts” (para. 101, my translation). Where third-party services are engaged as processors for tracking but also process the data for their own purposes — or merely reserve the right to — legitimate interest under point (f) can, in the DSK's view, generally not justify the transfer “even if only of the IP address” (para. 111).

The BGH case concerns the second step: the transfer. The claimant had also complained that cookies were stored without consent (Regional Court's statement of facts); no court examined that, and none of the three judgments mentions § 25 TTDSG or TDDDG.

What this means for you as a shop operator

This section is my assessment, based on the decisions cited — unless I explicitly quote case law, none of it is a statement by the BGH.

First, a transfer of the reasoning that I consider obvious: by its wording, the BGH's legal statement applies to personal data in general — so also when a shop sends email addresses to advertising platforms. That was not the facts of this case, but it is the part that affects many shops.

  1. Data subjects have an additional tool. Besides complaining to the supervisory authority and claiming damages, they can sue for an injunction, and the BGH has accepted a request wording as specific enough. The risk for a shop does not rise overnight, but the hurdle for a lawsuit is lower.
  2. Quietly switching it off is not enough once it has happened. According to BGH case law, merely discontinuing a practice does not as a rule remove the risk of repetition; that usually takes a cease-and-desist declaration backed by a contractual penalty (VI ZR 431/24, para. 27 (opens in a new tab), German; likewise Regional Court of Munich I, 3 O 17493/20, para. 10). If you receive a warning letter, you need a lawyer — not just a quick commit.
  3. Consent becomes the central question. According to the defendant, the shop had a cookie banner through which visitors also consented to the third-party services. No court has examined whether that holds — the Higher Regional Court has to clarify it if its decision turns on it. For you this means: not “do I have a banner?”, but “does nothing really load before the decision, and does everything really stay silent after a no?”
  4. Abuse remains abuse. Automated mass warning letters have not become more attractive through this judgment; the courts have developed standards for them.

So the real question is technical: what does your shop send, when, to whom? That is exactly what I measured.

The third parties of a typical shop

Most of the 17 services from the case fall into categories that show up in almost every shop:

Category Examples (italics: from the claim) What happens on page load
Tag manager Google Tag Manager loads further scripts, depending on configuration
Web and data analytics Google Analytics, Trbo page views and events go to the provider
Advertising and conversions Doubleclick, Bing Ads, Taboola, TikTok pixels report page views, cart and purchases
Social Facebook, Pinterest pixels as above, some with “advanced matching”
Fonts Google Fonts, Fonts Awesome, Fonts.com CSS and font files from the third-party server
Video and captcha Youtube, Google Recaptca iframe or script from the provider
Recommendations and testing Cquotient, Google Optimize usage behaviour goes to the engine
Payment and reviews Stripe, PayPal, Trustpilot script and often iframes from the provider
Libraries jsDelivr and other CDNs JavaScript from the third-party server

What they all have in common: the browser makes the connection. So the third-party server has the IP address, the user agent and the referrer before any script does anything at all. Google describes exactly this for Google Fonts: IP address, requested URL and HTTP headers including user agent and referer (Google Fonts FAQ (opens in a new tab)).

The measurement: a test shop with made-up data

Documentation says what a provider can send. I wanted to see what it sends. So on 17 September 2026 I built a small test shop: product page, cart, order confirmation. Customer “Erika Mustermann”, email erika.mustermann@example.com, order TEST-10042, a hiking boot SKU-4711 for 89.90 euros — all invented, all provider IDs are test IDs.

I embedded the providers following the snippets from each vendor's documentation — Stripe.js only loaded, not initialised, Trustpilot only with its loader script and no widget — and configured them the way I often find them in shops:

  • Active without consent: Google Fonts, a library from jsDelivr, the Google tag (gtag.js) for Google Analytics and Google Ads in Consent Mode “advanced” with the default set to “denied”, Stripe.js, the PayPal SDK in sandbox mode, Trustpilot, a YouTube video on the product page and reCAPTCHA with Google's test key in the cart.
  • Only after consent: Meta Pixel (with email, phone, name, city and postcode), TikTok Pixel and Microsoft UET for Bing Ads (each with email and phone number), Pinterest Tag (with email) — features called “advanced matching”, “enhanced conversions” or “enhanced match” — plus Microsoft Clarity and Hotjar.

That puts eight of the 17 services from the claim into the test: Google Analytics, Google Fonts, reCAPTCHA, Doubleclick, YouTube, Facebook, Pinterest and Bing Ads. gtag.js does come from the Google Tag Manager server, but I did not embed a Tag Manager container.

The trick is the network rule. A Playwright script with Chromium lets only a fixed list of 18 vendor files load for real — the scripts, stylesheets and fonts without which no vendor code would run — and even those only if their address contains none of my made-up data. Every other request to a third-party host is logged with URL, referer, cookie and content-type headers and payload, and then aborted.

That list has a backstory that is a finding in itself. On the first run, my rule let through everything the browser classifies as a script. During the adversarial fact check of this article it turned out that exactly this way, six transmissions to Google Ads had actually gone out — to googleads.g.doubleclick.net, with the test order, product ID, value and page URL. Google sends this conversion hit as a request the browser loads like a script. With made-up data and a made-up account ID that is harmless, but the lesson is valuable: if you sort third parties only by “script or not” — or allow an advertising service's host for scripts in a Content Security Policy — such transmissions get through. The figures below come from the run with the fixed list, in which none of the requests let through contained test data.

measure.cjs (excerpt)
const LOADABLE = new Set(['script', 'stylesheet', 'font']);
// Only these exact vendor files may load. A resource type alone is not enough:
// Google Ads sends its conversion hit as a "script" request with the order in the query.
const ALLOW = [
	/^https:\/\/www\.googletagmanager\.com\/gtag\/js\?id=(G-TEST123456|AW-000000000)(&cx=c&gtm=\w+)?$/,
	/^https:\/\/connect\.facebook\.net\/en_US\/fbevents\.js$/,
	// … 16 more exact vendor files
];
// Belt and braces: never let a request through that carries any of the fake test data.
const MARKERS = ['TEST-10042', 'SKU-4711', '89.9', 'localhost', 'erika', 'mustermann', '4915100000000'];

// …

await context.route('**/*', async (route) => {
	const req = route.request();
	const url = new URL(req.url());
	if (url.origin === ORIGIN || url.protocol === 'data:' || url.protocol === 'blob:') return route.continue();
	const headers = await req.allHeaders();
	const entry = {
		run: name, page: current, resourceType: req.resourceType(), host: url.host, method: req.method(),
		url: req.url(), referer: headers.referer || '', cookie: headers.cookie || '',
		contentType: headers['content-type'] || '', postData: (req.postData() || '').slice(0, 20000),
	};
	const decoded = decodeURIComponent(req.url()).toLowerCase();
	const carriesData = MARKERS.some((m) => decoded.includes(m.toLowerCase()));
	if (LOADABLE.has(req.resourceType()) && ALLOW.some((re) => re.test(req.url())) && !carriesData) {
		lines.push({ ...entry, action: 'loaded' });
		return route.continue();
	}
	lines.push({ ...entry, action: 'aborted' });
	return route.abort('blockedbyclient');
});

Two runs, each through all three pages: once without consent, once with. Afterwards I searched the intercepted requests for the made-up data — in plain text and as SHA-256 hashes —, checked every hit in the raw request, and verified that none of the requests let through contained such data.

26 intercepted transmissions to six third-party hosts. The result that surprised me most concerns Google Analytics. In Consent Mode “advanced”, the Google tags load before consent and, according to Google, send “measurements without cookies” (Google: Consent mode overview (opens in a new tab)). What that means on an order confirmation is shown by the intercepted transmission:

POST region1.google-analytics.com/g/collect (shortened)
gcs=G100            # after consent: G111
en=purchase
pr1=idSKU-4711~nmTestprodukt Wanderschuh~pr89.9~qt1
ep.transaction_id=TEST-10042
epn.value=89.9
cu=EUR
dl=http://localhost/thanks.html
dt=Danke für deine Bestellung — Test-Shop
sr=1280x720
ul=de-de
uap=Linux

Order number, product, price, page URL, page title, screen size, language and operating system — without consent. What was not in it: a cookie and a cross-page identifier. The client ID was different on each of the three pages. Google Ads reported in parallel via pagead2.googlesyndication.com, also with page URL, order value and order number.

Also going out without consent would have been: on every page, a logging event from the PayPal SDK to the sandbox with domain, user agent, language and a session ID that was the same on all three pages — unlike Google, a cross-page identifier —, plus the requests of the Stripe, YouTube and reCAPTCHA iframes. The IP address is part of every one of these connections, even if it appears in no payload — it is simply the sender address. Incidentally, the referer header of all 113 intercepted requests across both runs contained only http://localhost:8790/, not the path. The full page URL came via the payload.

87 intercepted transmissions (the number varies between runs by a single Hotjar ping). The key findings:

Recipient What it contained
Google (Analytics, Ads, remarketing) purchase with order number, product, value and page URL to region1.google-analytics.com and www.google.com
TikTok email and phone number as SHA-256, page URL, user agent, product and value; cookie _ttp
Pinterest email as SHA-256, on purchase the complete order with order number, product name, product ID and value in plain text
Microsoft UET (Bing Ads) email and phone number as SHA-256, page URL, page title, language, screen size, purchase value; cookie MUID
Doubleclick purchase with order number, product ID, value, page URL and page title to googleads.g.doubleclick.net — as a script request, see above

This is what it looks like in TikTok's raw request:

POST analytics.tiktok.com/api/v2/pixel (shortened)
{
	"event": "Purchase",
	"context": {
		"user": {
			"email": "5e5a6082e3087d33b2a6a5700d8a307361e4a10408448a344b9e8a4f61e9cd84",
			"phone_number": "e18d0e0ef936bd206d9a2c6ca4168109aa26240f1cd79284b5da4bac5ec8dd31"
		},
		"page": { "url": "http://localhost:8790/thanks.html" }
	},
	"properties": { "content_id": "SKU-4711", "value": 89.9, "currency": "EUR" }
}

The first value is exactly the SHA-256 hash of erika.mustermann@example.com. Microsoft even normalised the address before hashing: the hash it sent corresponds to erikamustermann@example.com, i.e. without the dot in the local part.

What could not be measured — and why that is no all-clear

An honest measurement includes what it does not show:

  • Meta Pixel sent nothing. The script loaded, but rejected the made-up pixel ID as invalid right in the browser (console: “Invalid PixelID”), requested no configuration and never fired. With advanced matching, according to Meta's documentation, email, name, phone, city and postcode among others are sent, “hashed automatically by the pixel using SHA-256” (Meta: Advanced matching (opens in a new tab)).
  • Google did not send the email, even though I passed it. That is documented: the Google tag only collects such data once the corresponding terms of service have been accepted in the Ads or Analytics account (Google Ads Help (opens in a new tab)). For my made-up tag IDs there is no account in which those terms could have been accepted. In a real shop with enhanced conversions turned on, this looks different.
  • Hotjar recognised the headless browser as a bot from its user agent and did not start; occasionally a single rejection message went out. Clarity delivered no script for the made-up project ID.
  • The iframes of Stripe, YouTube and reCAPTCHA were aborted. What would have happened inside them, such as the fraud-detection signals Stripe says it sends to m.stripe.com, is not measured.
  • The configuration is a model. Which services load before consent in your shop is decided by your setup, not my table.

Real shops with real IDs therefore send more than my test shop, not less.

Why a hash is not anonymisation

SHA-256 sounds like encryption, but here it is the opposite of anonymity. The same email address produces the same hash everywhere. That is exactly why it is sent: Microsoft matches the hashed data against users signed in to Microsoft services (Microsoft: Enhanced conversions (opens in a new tab)), and Pinterest writes that enhanced match “sends hashed email addresses to Pinterest to match site events when there's no Pinterest cookie present” (Pinterest: Enhanced match (opens in a new tab)). The data protection commissioner of Baden-Württemberg puts it briefly: user IDs or hashes used as a substitute for identifying features are not anonymisation (LfDI BW, FAQ on cookies and tracking, question 3.2 (opens in a new tab), German).

How to find out what your site sends

You do not need a script for this. A browser is enough if you keep a few things in mind.

  1. Fresh profile. A private window without extensions, so that neither old cookies nor an ad blocker distort the picture.
  2. Measure before the decision. Open developer tools (F12), “Network” tab, then load the page — and do not click the cookie banner. Everything now in the list that does not come from your own domain goes out without consent. Showing the “Domain” column and sorting by it helps enormously.
  3. Go all the way. Product page, cart, checkout, order confirmation. The interesting transmissions often only come on the last page.
  4. Measure again after “Reject”. A banner that still loads things after “Reject” is worse than none.
  5. After “Accept”, look into the payloads. Click a request, “Payload” tab: there you see order values, product IDs and long hex values that look suspiciously like hashes.
  6. Export as HAR if you want to archive the recording or show it to someone.

For ongoing monitoring, a Content Security Policy in report-only mode works well. It blocks nothing, but reports every violation in the browser console — and, if you specify an endpoint, to your server:

Response headers
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp
Reporting-Endpoints: csp="https://shop.example/csp-reports"

Every resource from a third-party domain then shows up as a violation. That is a very honest inventory, because it comes from your real visitors' real browsers.

How to stop it

Self-host what can be self-hosted

Fonts, icon fonts and JavaScript libraries belong on your own server. German supervisory authorities have explicitly recommended this for Google Fonts since 2022 (LfD Lower Saxony (opens in a new tab), German; HBDI (opens in a new tab), German). It is the cheapest measure there is: download once, embed, done. This site does exactly that — Martian Mono, Instrument Sans and a small JetBrains Mono subset sit as WOFF2 files in its own repository.

Load only after the decision

Anything that cannot be self-hosted and needs consent may only load after consent. The DSK is clear: while the consent banner is displayed, no further scripts and in particular no content from third-party servers are loaded initially, “insofar as consent is required for this” (guidance, para. 121, my translation).

For Google that means: Consent Mode has two variants. In “basic” mode, the Google tags stay blocked until someone interacts with the banner, and according to Google nothing is sent to Google before that. In “advanced” mode they load immediately and send measurements without cookies (Google (opens in a new tab)). You saw above what that means on a thank-you page. I found no statement by a supervisory authority specifically on “advanced” mode. My assessment: if you take the judgment seriously, “basic” is the variant you can explain without having to argue.

For YouTube, maps and similar embeds there is the well-known two-click solution: first a local preview image, the iframe only loads after the click. The youtube-nocookie.com variant does not change the fact that the browser connects to a third-party server when loading the iframe — and thereby transmits the IP address.

Server-side tagging does not solve the problem, it moves it

With server-side tagging, the browser sends the data to your own server, which forwards it to Google, Meta and co. That can make data flows easier to control, because you can filter. In practice, though, it usually remains a transfer of personal data — unless you fully anonymise before anything goes on, and hashes or IDs are not enough for that. The data protection commissioner of Baden-Württemberg writes: “Of course, server-side tracking must also comply with the requirements of the TTDSG and — since the transfer of personal data is processing — the GDPR” (FAQ, question 3.2, my translation; the TTDSG is now called TDDDG). And Google itself still has consent collected in the browser with server-side Tag Manager (Google (opens in a new tab)).

Advanced matching, enhanced conversions, enhanced match — the features have a different name at every provider and at their core do the same thing: they send customer data along as a hash. That is a deliberate decision you make in the configuration, not a side effect. Only turn it on if you have a legal basis for it and your privacy policy says so accurately.

A Content Security Policy as a guard rail

The report-only variant above can be switched to enforcing. Then the browser simply loads nothing that is not allowed — not even the plugin someone installs six months from now. This site sends the following policy (measured live on 17 September 2026):

Content-Security-Policy of www.jpkc.com/db/
default-src 'self'; script-src 'self' 'unsafe-inline' blob:; worker-src 'self' blob:;
style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self';
connect-src 'self' blob:; manifest-src 'self'; object-src 'none'; base-uri 'self';
form-action 'self'; frame-ancestors 'self'; upgrade-insecure-requests

When loading an article, my browser made requests exclusively to www.jpkc.com. To be honest: 'unsafe-inline' for scripts and styles is no model of security against injected code. As protection against unplanned third parties the policy still works, because no third-party host appears anywhere in it. For a shop with payment providers the list gets longer — but then at least it is a deliberate list.

WordPress and WooCommerce: the usual places

In WordPress projects I mostly find the third parties in the same places.

  • Themes load Google Fonts. The rules for the official theme directory prohibit resources from third-party servers without consent — with one explicit exception: Google Fonts (Theme Review Handbook (opens in a new tab)). So a theme from the directory may load Google Fonts remotely. After the Munich ruling, the Themes team itself recommended hosting fonts locally (post of 18 June 2022 (opens in a new tab)).
  • The emoji script is more harmless than its reputation. WordPress adds a small detection script to every page. But it does not contact s.w.org on every page load. Only if the browser cannot render flags or the newest emoji does WordPress load a polyfill from your own server; if such an emoji is on the page, that polyfill fetches the image from s.w.org (emoji-loader.js (opens in a new tab) and formatting.php (opens in a new tab), WordPress 7.1). Only then is a connection made.
  • WooCommerce Order Attribution has been enabled by default since version 8.5.0 (WooCommerce 8.5.0 (opens in a new tab)). It stores origin, UTM parameters and device type in the order data and sets sbjs_* cookies in the browser for that. According to the documentation, this data is only read on an order and stored as order metadata in the shop; Automattic only receives statistical attribution data without customer data, and only after a prior opt-in (WooCommerce documentation (opens in a new tab)). The cookies still fall under § 25 TDDDG — whether they are permissible without consent is a separate assessment. WooCommerce supports the WP Consent API for this.
  • Payment plugins load Stripe.js earlier than necessary. The official WooCommerce Stripe plugin loads it by default on product pages and in the cart already, not only at checkout; a filter turns that off (source class-wc-stripe-helper.php (opens in a new tab)). Stripe itself even recommends including the script on every page (Stripe: Including Stripe.js (opens in a new tab)) and sends fraud-detection signals to m.stripe.com. These risk signals can be turned off with the parameter advancedFraudSignals=false, but hCaptcha and input field events cannot (Stripe: Advanced fraud detection (opens in a new tab)). Whether you want to do without them is a trade-off between privacy and fraud protection, not a purely technical question.
  • Plugins that add “just a small widget”. Reviews, chat, newsletter pop-ups, product recommendations. Each of them is an entry in the list from the case.

The essentials in five sentences

  1. On 21 July 2026 the BGH decided that data subjects can also defend themselves against a transfer that breaches data protection law with an injunction under German law — not that the shop in the case acted unlawfully.
  2. The case was about 17 embedded services and the IP address transmitted along with device and usage data, not about names or email addresses.
  3. Whether the transfer was unlawful, whether the cookie banner holds up and whether there is a risk of repetition is still for the Higher Regional Court of Frankfurt to clarify.
  4. In my test shop, order number, product and price went to Google without consent, and after consent the email address went as a hash to TikTok, Pinterest and Microsoft, with the phone number also going to TikTok and Microsoft.
  5. The most robust answer is technical: self-host, load only after the decision, do not mistake hashes for anonymisation and set a Content Security Policy as a guard rail.

If you implement only one thing from this article, make it the measurement: private window, F12, Network, click through to the order confirmation once without touching the banner. The list you then see is exactly the list this case was about.

I checked every statement in this article against the primary sources before publication — how that works is described in Who Checks the Checker? Adversarial Fact-Fidelity for AI Text. And if you want to know how long you may keep the data from your forms at all: Retention Periods: How Long You May Really Keep Applicant and Contact Data.

Sources

The case

Case law

Authorities

Vendors