Technical audit · 08.09.2026

tallinn.ee

Official portal of the City of Tallinn

The official portal of the City of Tallinn — a single capture of a district page, 216 requests, 19 nodes, about eighty seconds. There is no consent management mechanism on the page at all, and Google analytics runs even without a consent mode (gcs=-). On load, without any choice, the Facebook / Meta Pixel fires (PageView delivered to Meta), as do GA4, Google DoubleClick advertising via the embedded video, and the Cloudflare analytics beacon; separately, the Mouseflow session-recording tool loads and initializes from the markup. All of this while the data-protection terms explicitly promise: third-party content only after consent, and without consent no data is processed. The security headers are set strictly, but that has nothing to do with consent.

Request timeline

+0 ms · district-page load
Served via Cloudflare. The security headers are set strictly: Content-Security-Policy (default-src 'self' with a narrow allowlist), HSTS, X-Frame-Options SAMEORIGIN, X-Content-Type-Options nosniff. There is no consent management platform on the page.
+165…+166 ms · tag container and session recording from the markup
Straight from the markup, www.googletagmanager.com/gtm.js and cdn.mouseflow.com/projects/730378e1-… — the Mouseflow session-recording tool — start almost simultaneously. There is no consent condition before them.
+201 ms · embedded YouTube video
www.youtube.com — the embedded video begins loading; later it is played (stream from googlevideo.com), and its player pulls in Google DoubleClick.
+375…+719 ms · Facebook / Meta Pixel
connect.facebook.net/fbevents.js (pulled in by the GTM container) and signals/config, then www.facebook.com/tr at +719 ms — a PageView event of pixel 1368983323488812, response 200.
+911…+927 ms · DoubleClick via YouTube
googleads.g.doubleclick.net and static.doubleclick.net — requests initiated by the embedded YouTube video's player.
+1059 ms · Cloudflare Web Analytics
static.cloudflareinsights.com/beacon.min.js — an analytics beacon, from the page markup.
+5589 ms · GA4 page_view
region1.analytics.google.com/g/collect — a page_view event, counter G-XPFT2B0539, gcs=-. The page URL and title go to Google.

Declared versus actual

✓ Controller — the institutions of the City of Tallinn (Tallinna linna asutused); data-protection terms (Andmekaitsetingimused) — declared
✓ Google Analytics is used to get an overview of site traffic; Google stores the IP address and site-usage data — declared
✓ Embedded third-party content (Internet Archive, Google Maps, Twitter, Microsoft, Facebook, Google, LinkedIn, Livestream) — to view it you must first agree to those third parties' terms — declared
✓ 'If you do not give consent or withdraw it, we do not process your personal data' — declared
✓ Cookie removal — via browser settings (aboutcookies.org) — declared
✓ Supervisory authority — Andmekaitse Inspektsioon — declared
+ Mouseflow — a session-recording tool; loads and initializes without consent, not named in the policy — not declared
+ Cloudflare Web Analytics — an analytics beacon, not named in the policy — not declared
+ That Facebook is present as a tracking pixel (PageView on load), not as content opened by consent — not declared
+ That the analytics and advertising requests go out without any consent mechanism (gcs=-) — not declared

Transfer timings

+166 ms cdn.mouseflow.com

Project 730378e1-… script, from the markup; initializes recording. Not named in the policy. The recording upload is not observed within the capture window.

+719 ms www.facebook.com

PageView, pixel 1368983323488812, GET /tr, response 200. Without consent.

+911 ms googleads.g.doubleclick.net

Pulled in by the embedded YouTube video's player.

+1059 ms static.cloudflareinsights.com

Analytics beacon from the markup. Not named in the policy.

+5589 ms region1.analytics.google.com

GA4 page_view, G-XPFT2B0539, gcs=- (consent mode not configured).

Detected trackers

Indicators of GDPR non-compliance

Context

tallinn.ee is the official portal of the City of Tallinn; the controller is the institutions of the City of Tallinn (Tallinna linna asutused). The site is served via Cloudflare and keeps a strict header posture: Content-Security-Policy (default-src 'self' with a narrow allowlist), HSTS, X-Frame-Options SAMEORIGIN, X-Content-Type-Options nosniff.

The capture is a single recording of a district page (/et/peterburitee): 216 requests, 19 nodes, about eighty seconds, recorded on 8 September 2026. Over the course of the session an embedded YouTube video is played on the page. Processing is described by the city’s data-protection terms (‘Policy and cookies’).

Who receives data directly

Google (Analytics, DoubleClick via YouTube), Meta (Facebook Pixel), Mouseflow (session recording), Cloudflare (analytics beacon). Functionally — reCAPTCHA and Google Fonts.

Declared vs. actual

The discrepancy here is not in the details but at the very foundation: the policy promises a consent mechanism that does not exist on the page.

First — consent is not requested at all. Across 216 requests there is no consent management platform and no script with the signs of a banner in the recording. Moreover, Google analytics runs even without a consent mode: the GA4 page_view event goes out with the status gcs=-, meaning Consent Mode is not configured. On an ordinary page load, without any user choice, the Facebook / Meta Pixel fires and transmits (PageView, pixel 1368983323488812, response 200), as do GA4 (G-XPFT2B0539), Google DoubleClick (via the embedded video’s player) and the Cloudflare analytics beacon. Separately, at +166 ms, the Mouseflow session-recording tool (project 730378e1-…) loads and initializes straight from the markup.

Second — the policy states the exact opposite. The data-protection terms plainly say that embedded third-party content — Google Maps, Twitter, Microsoft, Facebook, Google, LinkedIn, Livestream — is shown only after the visitor agrees to those third parties’ terms (‘peate kõigepealt nõustuma’). And separately: ‘if you do not give consent or withdraw it, we do not process your personal data’. In fact the data goes to Google, Meta and Cloudflare before and without any consent. The ‘consent first, otherwise we do not process’ model stated by the policy is not implemented on the page.

Third — the session recording and some recipients are undisclosed. Mouseflow is a session-recording and heatmap tool; on a municipal portal it loads without consent and is not mentioned in the policy even once. The Cloudflare analytics beacon is also not named. Facebook appears in the policy only as embedded content whose access opens by consent — whereas in the recording it works as a tracking pixel sending a PageView on page load.

The security headers, meanwhile, are set strictly — the site protected the transport and the content but left the question of consent unaddressed. For a portal of an executive-branch body, from which an exemplary standard is expected, this discrepancy is especially notable.

Proven: there is no consent mechanism on the page. No request to a consent management platform and no script with the signs of a banner across 216 requests. GA4 runs with the status gcs=- — Google’s consent mode is not configured.

Proven: the trackers transmit data on load. Facebook /tr goes out at +719 ms (PageView, response 200); GA4 page_view at +5589 ms; DoubleClick at +911 ms via the YouTube player; the Cloudflare beacon at +1059 ms. All without any consent choice.

Proven: the session-recording tool is loaded and initialized. The Mouseflow script (project 730378e1-…) is pulled in at +166 ms straight from the page markup.

Not proven, and explicitly caveated: the Mouseflow recording upload. Within the capture window (about eighty seconds) no separate request uploading the recorded session to Mouseflow is observed — the loading and initialization of the recording script are recorded, but not the fact of sending the recording itself. The conclusion concerns the deployment of the tool without consent, not a confirmed transfer of a recording.

Observation boundaries

The capture covers one page — a district card — and records browser behaviour, not the services’ internal workings: server-side processing, the configuration of the tag container and contracts with recipients are not verified by a browser-level capture. The Mouseflow script in the recording is served from cache (response 304); what exactly it transmits and when is not established from this file beyond the fact of loading and initialization. The DoubleClick requests are attributed to the embedded YouTube player by the initiator (ytembeds). reCAPTCHA and Google Fonts are classified as the functional part.

The file is published redacted of personal data: cookie values in requests have been removed. Response headers, statuses, the load order and initiators are preserved, so the absence of a consent mechanism, the gcs=- status of GA4 and the delivery of the Facebook pixel are verified directly against the published file.

The legal assessment is made by the competent authority — Andmekaitse Inspektsioon.

Conclusion

The official portal of the City of Tallinn carefully protected the transport and the content — a strict content security policy, HSTS, nosniff — but left the question of consent entirely open. There is no consent management mechanism on the page, and Google analytics runs even without a consent mode (gcs=-). On an ordinary load, without any user choice, the Facebook / Meta Pixel sends a PageView to Meta, GA4 sends an event to Google, the embedded YouTube video pulls in Google DoubleClick advertising, and the Mouseflow session-recording tool loads and initializes from the markup. The Cloudflare analytics beacon goes out there too.

The site’s own data-protection terms meanwhile promise the exact opposite: third-party content only after consent, and without consent personal data is not processed. The Mouseflow session-recording tool and the Cloudflare analytics beacon are not named in the policy at all, and Facebook is described as content opened by consent — whereas it works as a pixel on load. For a site of an executive-branch body, from which an exemplary standard is expected, the gap between the promised and the actual here is fundamental.

Remediation: introduce a consent management mechanism and condition on it the loading and firing of all statistics and advertising components — GA4, the Facebook pixel, Mouseflow, embedded YouTube videos with DoubleClick advertising, and the Cloudflare beacon — so that before consent none of these requests goes out; configure Google’s consent mode (currently gcs=-); name the Mouseflow session-recording tool and the Cloudflare analytics in the data-protection terms as recipients, with the purpose and legal basis stated; and bring the description of Facebook into line with its actual role (a tracking pixel, not content by consent).

Evidence

How to verify: download the file and compute its checksum — sha256sum file.har (Linux, macOS) or certutil -hashfile file.har SHA256 (Windows); it must match the one shown. The conclusions apply to the scope of this measurement — see the limitations of the method.

Original (audit)
HAR file: ee/tallinn-ee-2026-09-08.har
SHA-256: 4e994d8446f981f2673c2d30b9dd903664a09882b3dbb53b456b51c278702b44
Re-check snapshot
Awaiting changes
HAR files are stored on EU infrastructure (Proton Drive). SHA-256 is published for integrity verification.