From 6a38cb09519889e698b0694d6ca3e332a4bd195a Mon Sep 17 00:00:00 2001 From: Mick <103085050+Apolloccrypt@users.noreply.github.com> Date: Sun, 22 Mar 2026 07:11:17 +0100 Subject: [PATCH 01/24] Revise Xandr and SmartOcto entries in index.html Updated Xandr entry to include Microsoft contact details and added SmartOcto entry with DPO information. --- index.html | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 2111a80..098259a 100644 --- a/index.html +++ b/index.html @@ -115,7 +115,13 @@

πŸ“š Meer Info

{ name: "Google (Ads/Analytics)", email: "privacy@google.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 100% van geteste NL nieuwssites" }, { name: "Criteo", email: "privacy@criteo.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, { name: "Index Exchange", email: "privacy@indexexchange.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, - { name: "Xandr (Microsoft)", email: "privacy@xandr.com", category: "Ad-Tech & Tracking" }, + { + name: "Xandr (Microsoft Advertising)", + email: "privacy@microsoft.com", + webform: "https://privacy.microsoft.com/", + note: "⚠️ Xandr is Microsoft-owned. Contact via Microsoft privacy portal. 0% GDPR response rate (noyb 2024)." + } + { name: "Meta (Facebook/Instagram) ⚠️", email: "FORM_REQUIRED", @@ -171,7 +177,12 @@

πŸ“š Meer Info

{ name: "Jumbo Supermarkten", email: "privacy@jumbo.com", category: "Retail & E-Commerce" }, // === ANALYTICS & DATA PLATFORMS === - { name: "Smartocto (Content Insights)", email: "privacy@smartocto.com", category: "Analytics", note: "Gebruikt door NOS.nl (niet in cookie banner)" }, + { + name: "SmartOcto", + email: "dpo@smartocto.com", + alt_email: "info@smartocto.com", + note: "DPO verified from official privacy policy. NL-based, GDPR compliant." + } { name: "Content Insights", email: "privacy@contentinsights.com", category: "Analytics" }, { name: "Piano Analytics", email: "privacy@piano.io", category: "Analytics" }, { name: "Comscore", email: "privacy@comscore.com", category: "Analytics" }, From 482ce0606cc0687458eaa27e0133467b5c5cbecb Mon Sep 17 00:00:00 2001 From: mit Date: Sun, 22 Mar 2026 07:20:51 +0100 Subject: [PATCH 02/24] Fix v1.1.1: Correct bouncing emails Xandr/SmartOcto + syntax errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixed: Xandr email (privacy@xandr.com β†’ privacy@microsoft.com) - Fixed: SmartOcto email (privacy@smartocto.com β†’ dpo@smartocto.com) - Fixed: Missing commas in brokers array (JavaScript syntax errors) - Fixed: Missing category fields for both brokers - Added: Compliance warnings (Xandr 0% GDPR response rate) - Version: v1.1.0 β†’ v1.1.1 Resolves bounce reports from multiple users. --- index.html | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 2111a80..da84cd0 100644 --- a/index.html +++ b/index.html @@ -97,7 +97,7 @@

πŸ“š Meer Info

+ diff --git a/script.js b/script.js new file mode 100644 index 0000000..fe0130f --- /dev/null +++ b/script.js @@ -0,0 +1,316 @@ +const brokers = [ + // === CREDIT BUREAUS & DATA ENRICHMENT === + { name: "Experian Nederland", email: "privacy@experian.nl", category: "Credit Bureaus", note: "AP boete 2.7M (2025) voor onvoldoende vendor disclosure" }, + { name: "Graydon", email: "privacy@graydon.nl", category: "Credit Bureaus" }, + { name: "Creditsafe", email: "privacy@creditsafe.com", category: "Credit Bureaus" }, + { name: "Focum BV", email: "privacy@focum.nl", category: "Credit Bureaus" }, + { name: "Dun & Bradstreet", email: "privacy@dnb.com", category: "Credit Bureaus" }, + { name: "Bisnode (Dun & Bradstreet)", email: "privacy@bisnode.nl", category: "Credit Bureaus" }, + + // === AD-TECH & TRACKING === + { name: "Google (Ads/Analytics)", email: "privacy@google.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 100% van geteste NL nieuwssites" }, + { name: "Criteo", email: "privacy@criteo.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, + { name: "Index Exchange", email: "privacy@indexexchange.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, + { + name: "Xandr (Microsoft Advertising)", + email: "FORM_REQUIRED", + formUrl: "https://account.microsoft.com/privacy/privacy-request-signedout", + category: "Ad-Tech & Tracking", + note: "E-mail privacy@microsoft.com bouncet; dit adres is niet ingericht voor privacyverzoeken. Gebruik het Microsoft privacy formulier (vereist Microsoft-account). 0% GDPR response rate (noyb 2024).", + isForm: true + }, + { + name: "Meta (Facebook/Instagram)", + email: "FORM_REQUIRED", + formUrl: "https://www.facebook.com/help/contact/540977946302970", + category: "Ad-Tech & Tracking", + note: "Email werkt niet meer sinds maart 2026. Verplicht formulier (dark pattern).", + isForm: true + }, + { name: "Outbrain", email: "privacy@outbrain.com", category: "Ad-Tech & Tracking" }, + { name: "Taboola", email: "privacy@taboola.com", category: "Ad-Tech & Tracking" }, + { name: "Magnite (Rubicon)", email: "privacy@magnite.com", category: "Ad-Tech & Tracking" }, + { name: "PubMatic", email: "privacy@pubmatic.com", category: "Ad-Tech & Tracking" }, + { name: "OpenX", email: "privacy@openx.com", category: "Ad-Tech & Tracking" }, + { name: "LinkedIn Marketing", email: "privacy@linkedin.com", category: "Ad-Tech & Tracking" }, + { name: "TikTok", email: "privacy@tiktok.com", category: "Ad-Tech & Tracking" }, + { name: "Snap Inc. (Snapchat)", email: "privacy@snap.com", category: "Ad-Tech & Tracking" }, + { name: "Twitter / X Corp", email: "privacy@twitter.com", category: "Ad-Tech & Tracking" }, + { + name: "Pinterest", + email: "FORM_REQUIRED", + formUrl: "https://help.pinterest.com/nl/contact?current_page=about_you_page&personal_data=personal_data_adjust#no-back", + category: "Ad-Tech & Tracking", + note: "E-mail privacy@pinterest.com bouncet; dit adres is niet ingericht voor privacyverzoeken. Gebruik het contactformulier.", + isForm: true + }, + { name: "Amazon Ads", email: "privacy@amazon.com", category: "Ad-Tech & Tracking" }, + { name: "AppNexus (Xandr)", email: "privacy@xandr.com", category: "Ad-Tech & Tracking" }, + { name: "AdForm", email: "privacy@adform.com", category: "Ad-Tech & Tracking" }, + { name: "Sizmek (Amazon)", email: "privacy@sizmek.com", category: "Ad-Tech & Tracking" }, + { name: "The Trade Desk", email: "privacy@thetradedesk.com", category: "Ad-Tech & Tracking" }, + { name: "MediaMath", email: "privacy@mediamath.com", category: "Ad-Tech & Tracking" }, + + // === MEDIA & PUBLISHERS === + { + name: "DPG Media (NU.nl, AD.nl, Qmusic)", + email: "FORM_REQUIRED", + formUrl: "https://privacy.dpgmedia.nl/nl/privacy-rights", + category: "Media & Publishers", + note: "E-mail privacy@dpgmedia.nl bouncet; dit adres is niet ingericht voor privacyverzoeken. Gebruik het DPG Media formulier voor inzage, correctie, verwijdering en bezwaar. 104 van 121 partners niet genoemd in cookie banner.", + isForm: true + }, + { name: "RTL Nederland", email: "privacy@rtl.nl", category: "Media & Publishers" }, + { name: "Sanoma Media", email: "privacy@sanoma.com", category: "Media & Publishers" }, + { name: "NPO / NOS", email: "privacy@npo.nl", category: "Media & Publishers", note: "Pre-consent tracking gedetecteerd (cookies voor banner)" }, + { name: "Mediahuis (Telegraaf, NHD)", email: "privacy@mediahuis.nl", category: "Media & Publishers" }, + { name: "Talpa Network", email: "privacy@talpanetwork.com", category: "Media & Publishers" }, + + // === TELECOM === + { name: "KPN", email: "privacy@kpn.com", category: "Telecom" }, + { name: "VodafoneZiggo", email: "privacy@vodafoneziggo.nl", category: "Telecom" }, + { name: "T-Mobile / Odido", email: "dpo@odido.nl", category: "Telecom", note: "Data lek januari 2026 (mogelijk betrokken)" }, + { name: "Tele2", email: "privacy@tele2.nl", category: "Telecom" }, + { name: "Youfone", email: "privacy@youfone.nl", category: "Telecom" }, + { name: "Simyo", email: "privacy@simyo.nl", category: "Telecom" }, + { name: "Lebara", email: "privacy@lebara.nl", category: "Telecom" }, + + // === RETAIL & E-COMMERCE === + { name: "Kruidvat Loyalty", email: "vragen@klantenservice.kruidvat.nl", category: "Retail & E-Commerce", note: "AP boete 600k voor cookie wall" }, + { name: "Albert Heijn Bonus", email: "dpo@aholddelhaize.com", category: "Retail & E-Commerce" }, + { + name: "Bol.com", + email: "FORM_REQUIRED", + category: "Retail & E-Commerce", + note: "E-mail privacy@bol.com bouncet; dit adres is niet ingericht voor privacyverzoeken. Verzoeken verlopen alleen via de ingelogde account-omgeving; geen publiek e-mail of formulier beschikbaar. Gegevens zijn 7 dagen inzichtelijk en worden daarna verwijderd. Best practice: 100% vendor disclosure (13/13).", + isForm: true, + loginOnly: true + }, + { name: "Coolblue", email: "privacy@coolblue.nl", category: "Retail & E-Commerce", note: "AP boete 40k voor pre-consent tracking" }, + { name: "Wehkamp", email: "privacy@wehkamp.nl", category: "Retail & E-Commerce" }, + { name: "Zalando", email: "mijngegevens@zalando.nl", category: "Retail & E-Commerce" }, + { name: "HEMA", email: "hemaklantenservice@hema.nl", category: "Retail & E-Commerce" }, + { name: "Action", email: "privacy@action.nl", category: "Retail & E-Commerce" }, + { name: "MediaMarkt", email: "privacy@mediamarkt.nl", category: "Retail & E-Commerce" }, + { name: "Jumbo Supermarkten", email: "privacy@jumbo.com", category: "Retail & E-Commerce" }, + + // === ANALYTICS & DATA PLATFORMS === + { + name: "SmartOcto", + email: "dpo@smartocto.com", + alt_email: "info@smartocto.com", + category: "Analytics", + note: "DPO verified from official privacy policy. NL-based, GDPR compliant." + }, + { name: "Content Insights", email: "privacy@contentinsights.com", category: "Analytics" }, + { name: "Piano Analytics", email: "privacy@piano.io", category: "Analytics" }, + { name: "Comscore", email: "privacy@comscore.com", category: "Analytics" }, + { name: "Nielsen", email: "privacy@nielsen.com", category: "Analytics" }, + { name: "Chartbeat", email: "privacy@chartbeat.com", category: "Analytics" }, + + // === MARKETING CLOUDS === + { name: "Salesforce Marketing Cloud", email: "privacy@salesforce.com", category: "Marketing" }, + { name: "Adobe Marketing Cloud", email: "privacy@adobe.com", category: "Marketing" }, + { name: "Oracle Marketing Cloud", email: "privacy@oracle.com", category: "Marketing" }, + { name: "HubSpot", email: "privacy@hubspot.com", category: "Marketing" }, + { name: "Mailchimp", email: "privacy@mailchimp.com", category: "Marketing" } +]; + +// Vul de +
+ + - - - +
@@ -66,11 +66,11 @@

Volledige Disclaimer

Door te genereren accepteer je deze voorwaarden.

Bug Melden?

-

Als een contact email niet meer werkt of je vindt fouten, open een GitHub Issue of tag @mickbeer op LinkedIn.

+

Als een contact email niet meer werkt of je vindt fouten, open een GitHub Issue of tag @mick-beer op LinkedIn.

Meer Info

- Volledig onderzoek (Medium)
+ Volledig onderzoek (Medium)
Autoriteit Persoonsgegevens
GitHub Repository

@@ -87,18 +87,14 @@

Over dit project

  • Burgers inzicht geven in hoe hun data werkelijk wordt behandeld
  • Alles wat ik publiceer is gebaseerd op reproduceerbaar technisch onderzoek. Geen data wordt bewaard of verspreid. Na analyse wordt alles permanent verwijderd (responsible disclosure).

    -
    -

    Omdat dit volledig onafhankelijk gebeurt, heb ik geen budget voor servers, tools of tijd. Daarom stel ik het enorm op prijs als je mijn werk steunt via een donatie:

    -

    Buy Me a Coffee

    -

    Elke bijdrage helpt me om dit onderzoek voort te zetten en de Nederlandse privacy-discussie feitelijk en onafhankelijk te houden.

    -

    Dank je wel
    Mick Beer - Security Architect & onafhankelijk onderzoeker

    diff --git a/script.js b/script.js index fe0130f..dd91da1 100644 --- a/script.js +++ b/script.js @@ -8,7 +8,7 @@ const brokers = [ { name: "Bisnode (Dun & Bradstreet)", email: "privacy@bisnode.nl", category: "Credit Bureaus" }, // === AD-TECH & TRACKING === - { name: "Google (Ads/Analytics)", email: "privacy@google.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 100% van geteste NL nieuwssites" }, + { name: "Google (Ads/Analytics)", email: "privacy@google.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 100% van geteste NL nieuwssites. Bron: Onderzoek Volkskrant & Telegraaf (Medium)" }, { name: "Criteo", email: "privacy@criteo.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, { name: "Index Exchange", email: "privacy@indexexchange.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, { @@ -98,7 +98,7 @@ const brokers = [ { name: "SmartOcto", email: "dpo@smartocto.com", - alt_email: "info@smartocto.com", + altEmail: "info@smartocto.com", category: "Analytics", note: "DPO verified from official privacy policy. NL-based, GDPR compliant." }, @@ -116,8 +116,8 @@ const brokers = [ { name: "Mailchimp", email: "privacy@mailchimp.com", category: "Marketing" } ]; -// Vul de dynamically with optgroups per category +const companySelect = document.getElementById('company'); const categories = {}; brokers.forEach(broker => { @@ -136,113 +136,113 @@ Object.keys(categories).sort().forEach(cat => { opt.textContent = broker.name; optgroup.appendChild(opt); }); - bedrijfSelect.appendChild(optgroup); + companySelect.appendChild(optgroup); }); -// Andere optie +// Other option const otherOpt = document.createElement('option'); -otherOpt.value = 'Andere'; +otherOpt.value = 'other'; otherOpt.textContent = 'Ander bedrijf (handmatig invoeren)'; -bedrijfSelect.appendChild(otherOpt); +companySelect.appendChild(otherOpt); -// Extra input voor 'Andere' +// Extra input for 'other' const extraLabel = document.createElement('label'); -extraLabel.htmlFor = 'extraBedrijf'; +extraLabel.htmlFor = 'extra-company'; extraLabel.textContent = 'Ander bedrijf (naam + eventueel email privacy@...)'; extraLabel.style.display = 'none'; const extraInput = document.createElement('input'); extraInput.type = 'text'; -extraInput.id = 'extraBedrijf'; +extraInput.id = 'extra-company'; extraInput.placeholder = 'Bijv. Bedrijfsnaam - privacy@bedrijf.nl'; extraInput.style.display = 'none'; -bedrijfSelect.parentNode.insertBefore(extraLabel, bedrijfSelect.nextSibling.nextSibling); -bedrijfSelect.parentNode.insertBefore(extraInput, extraLabel.nextSibling); +companySelect.parentNode.insertBefore(extraLabel, companySelect.nextSibling.nextSibling); +companySelect.parentNode.insertBefore(extraInput, extraLabel.nextSibling); -bedrijfSelect.addEventListener('change', () => { - const show = bedrijfSelect.value === 'Andere'; +companySelect.addEventListener('change', () => { + const show = companySelect.value === 'other'; extraLabel.style.display = show ? 'block' : 'none'; extraInput.style.display = show ? 'block' : 'none'; - const selected = brokers.find(b => b.name === bedrijfSelect.value); - const banner = document.getElementById('updateBanner'); - const text = document.getElementById('updateText'); + const selected = brokers.find(b => b.name === companySelect.value); + const banner = document.getElementById('update-banner'); + const text = document.getElementById('update-text'); if (selected && (selected.note || selected.isForm)) { let message = selected.note || ''; if (selected.isForm) { message = `${selected.name} vereist een formulier (geen email). ${message}`; } - text.textContent = message; + text.innerHTML = message; banner.style.display = 'block'; } else { banner.style.display = 'none'; } }); -function genereerMail() { - const naam = document.getElementById('naam').value.trim(); +function generateMail() { + const name = document.getElementById('name').value.trim(); const email = document.getElementById('email').value.trim(); - let bedrijf = bedrijfSelect.value; + let company = companySelect.value; const extra = extraInput.value.trim(); const type = document.getElementById('type').value; - if (!naam || !email || !bedrijf) { + if (!name || !email || !company) { alert('Vul aub naam, email en een bedrijf in!'); return; } - let ontvanger = ''; - let bedrijfNaam = bedrijf; + let recipient = ''; + let companyName = company; let isForm = false; let formUrl = ''; - if (bedrijf === 'Andere') { + if (company === 'other') { if (!extra) { alert('Vul aub naam (en liefst email) van het bedrijf in!'); return; } const parts = extra.split('-').map(p => p.trim()); - bedrijfNaam = parts[0]; - ontvanger = parts[1] || `privacy@${bedrijfNaam.toLowerCase().replace(/[^a-z0-9]/g,'')}.nl`; + companyName = parts[0]; + recipient = parts[1] || `privacy@${companyName.toLowerCase().replace(/[^a-z0-9]/g,'')}.nl`; } else { - const selected = brokers.find(b => b.name === bedrijf); + const selected = brokers.find(b => b.name === company); if (selected) { if (selected.isForm) { isForm = true; formUrl = selected.formUrl; - ontvanger = formUrl; + recipient = formUrl; } else { - ontvanger = selected.email; + recipient = selected.email; } } else { - ontvanger = `privacy@${bedrijf.toLowerCase().replace(/[^a-z0-9]/g,'')}.nl`; + recipient = `privacy@${company.toLowerCase().replace(/[^a-z0-9]/g,'')}.nl`; } } - const onderwerpMap = { - bezwaar: 'Bezwaar tegen verwerking persoonsgegevens (GDPR Art. 21)', - wissen: 'Verzoek tot wissen persoonsgegevens (GDPR Art. 17)', - inzage: 'Verzoek tot inzage persoonsgegevens (GDPR Art. 15)', - beide: 'Bezwaar + wissen persoonsgegevens (GDPR Art. 21 & 17)' + const subjectMap = { + objection: 'Bezwaar tegen verwerking persoonsgegevens (GDPR Art. 21)', + erase: 'Verzoek tot wissen persoonsgegevens (GDPR Art. 17)', + access: 'Verzoek tot inzage persoonsgegevens (GDPR Art. 15)', + both: 'Bezwaar + wissen persoonsgegevens (GDPR Art. 21 & 17)' }; - const onderwerp = onderwerpMap[type]; + const subject = subjectMap[type]; const body = `Geachte heer/mevrouw, -Mijn naam is ${naam} en mijn email is ${email}. +Mijn naam is ${name} en mijn email is ${email}. Ik oefen hierbij formeel mijn rechten uit onder de AVG/GDPR: ${ - (type === 'bezwaar' || type === 'beide') - ? `- Bezwaar tegen verwerking van mijn persoonsgegevens voor marketing, profiling, tracking e.d. (Art. 21 GDPR). Ik wil geen verdere verwerking door ${bedrijfNaam}.\n` + (type === 'objection' || type === 'both') + ? `- Bezwaar tegen verwerking van mijn persoonsgegevens voor marketing, profiling, tracking e.d. (Art. 21 GDPR). Ik wil geen verdere verwerking door ${companyName}.\n` : '' }${ - (type === 'wissen' || type === 'beide') + (type === 'erase' || type === 'both') ? `- Verzoek tot wissen van al mijn persoonsgegevens (Art. 17 GDPR, recht om vergeten te worden).\n` : '' }${ - type === 'inzage' + type === 'access' ? `- Verzoek tot inzage in alle persoonsgegevens die u van mij verwerkt (Art. 15 GDPR), inclusief een kopie.\n` : '' } @@ -250,9 +250,9 @@ ${ Graag ontvang ik binnen 1 maand bevestiging en bewijs van actie. Bij weigering: gemotiveerde uitleg. Met vriendelijke groet, -${naam}`; +${name}`; - const selected = brokers.find(b => b.name === bedrijfNaam) || brokers.find(b => b.name === bedrijf); + const selected = brokers.find(b => b.name === companyName) || brokers.find(b => b.name === company); const loginOnly = selected && selected.loginOnly; if (isForm) { @@ -260,7 +260,7 @@ ${naam}`; document.getElementById('result').innerHTML = `

    Geen publiek contactkanaal beschikbaar

    -

    ${bedrijfNaam} heeft geen publiek e-mailadres of formulier voor GDPR-verzoeken.

    +

    ${companyName} heeft geen publiek e-mailadres of formulier voor GDPR-verzoeken.

    Verzoeken verlopen alleen via de ingelogde account-omgeving op hun website.

    `; @@ -271,7 +271,7 @@ ${naam}`; document.getElementById('result').innerHTML = `

    Let op: Dit bedrijf vereist een formulier

    -

    ${bedrijfNaam} accepteert geen email meer voor GDPR-verzoeken.

    +

    ${companyName} accepteert geen email meer voor GDPR-verzoeken.

    Je moet hun contact formulier gebruiken. De tekst is gekopieerd naar je clipboard.

    Template (gekopieerd):

    @@ -293,12 +293,12 @@ ${naam}`; `; }); } else { - const mailto = `mailto:${ontvanger}?subject=${encodeURIComponent(onderwerp)}&body=${encodeURIComponent(body)}`; + const mailto = `mailto:${recipient}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`; document.getElementById('result').innerHTML = `

    Klaar! Open de mail:

    -

    Naar: ${ontvanger}

    -

    Onderwerp: ${onderwerp}

    +

    Naar: ${recipient}

    +

    Onderwerp: ${subject}

    Template:

    ${body}
    @@ -311,6 +311,6 @@ ${naam}`; } window.addEventListener('DOMContentLoaded', () => { - document.getElementById('brokerCount').innerHTML = + document.getElementById('broker-count').innerHTML = `${brokers.length} Nederlandse data brokers beschikbaar`; }); diff --git a/style.css b/style.css index 9cc4013..6b1ec42 100644 --- a/style.css +++ b/style.css @@ -75,12 +75,15 @@ button.secondary { button.secondary:hover { background: #616161; } +#result:empty { + display: none; +} + #result { margin-top: 2rem; padding: 1rem; background: #e8f5e9; border-left: 5px solid #4caf50; - white-space: pre-wrap; } footer { From 9f996300bb76890d6d37328c82152516be0a1e9f Mon Sep 17 00:00:00 2001 From: Sten Tijhuis <102481635+Stensel8@users.noreply.github.com> Date: Wed, 1 Apr 2026 00:08:09 +0200 Subject: [PATCH 08/24] fix: update Dutch translations and enhance changelog formatting --- CHANGELOG.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bf57e9..7b2d291 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # Changelog -All notable changes to this project will be documented in this file. +Alle noemenswaardige wijzigingen aan dit project worden in dit bestand bijgehouden. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +Het formaat is gebaseerd op [Keep a Changelog](https://keepachangelog.com/nl/1.1.0/), +dit project hanteert [Semantic Versioning](https://semver.org/lang/nl/), +en commit-berichten volgen grotendeels de stijl van [Conventional Commits](https://www.conventionalcommits.org/nl/v1.0.0/). --- @@ -16,8 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Naamgeving consistentie** – alle code-identifiers omgezet naar Engels en consistente conventies: camelCase voor JS-variabelen en -functies, kebab-case voor HTML IDs en CSS-klassen (`genereerMail` β†’ `generateMail`, `bedrijf` β†’ `company`, `ontvanger` β†’ `recipient`, etc.) - **Form-waarden** – interne option-values omgezet naar Engels (`bezwaar` β†’ `objection`, `wissen` β†’ `erase`, `inzage` β†’ `access`, `beide` β†’ `both`) - **Donatie-knop** – minder opdringerig; verplaatst van prominente gele box naar een subtiele regel in de footer -- **HTML/JS/CSS gesplitst** – code uitgesplitst in aparte bestanden voor betere onderhoudbaarheid (script.js, style.css) -- **UI** – flashy kleuren en emoji gereduceerd voor een rustigere leeservaring +- **HTML/JS/CSS gesplitst** – code uitgesplitst in aparte bestanden voor betere onderhoudbaarheid (script.js, style.css) ([#1](https://github.com/Apolloccrypt/nl-data-optout/issues/1), [#2](https://github.com/Apolloccrypt/nl-data-optout/issues/2)) +- **UI** – flashy kleuren en emoji gereduceerd voor een rustigere leeservaring ([#3](https://github.com/Apolloccrypt/nl-data-optout/issues/3), [#4](https://github.com/Apolloccrypt/nl-data-optout/issues/4)) ### Fixed - **Broken Medium URLs** – alle verwijzingen naar `medium.com/p/75744f8645c6` en het lange artikel-pad vervangen door `https://medium.com/@mick.ronan.beer` (index.html, script.js, README.md) From 9b2a97ecf0bb02951b17d07ecf84e2d3292c521e Mon Sep 17 00:00:00 2001 From: Sten Tijhuis <102481635+Stensel8@users.noreply.github.com> Date: Wed, 1 Apr 2026 00:10:45 +0200 Subject: [PATCH 09/24] fix: update changelog formatting and enhance clarity of changes --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b2d291..2cbfb87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,10 +17,14 @@ en commit-berichten volgen grotendeels de stijl van [Conventional Commits](https - **Naamgeving consistentie** – alle code-identifiers omgezet naar Engels en consistente conventies: camelCase voor JS-variabelen en -functies, kebab-case voor HTML IDs en CSS-klassen (`genereerMail` β†’ `generateMail`, `bedrijf` β†’ `company`, `ontvanger` β†’ `recipient`, etc.) - **Form-waarden** – interne option-values omgezet naar Engels (`bezwaar` β†’ `objection`, `wissen` β†’ `erase`, `inzage` β†’ `access`, `beide` β†’ `both`) - **Donatie-knop** – minder opdringerig; verplaatst van prominente gele box naar een subtiele regel in de footer -- **HTML/JS/CSS gesplitst** – code uitgesplitst in aparte bestanden voor betere onderhoudbaarheid (script.js, style.css) ([#1](https://github.com/Apolloccrypt/nl-data-optout/issues/1), [#2](https://github.com/Apolloccrypt/nl-data-optout/issues/2)) -- **UI** – flashy kleuren en emoji gereduceerd voor een rustigere leeservaring ([#3](https://github.com/Apolloccrypt/nl-data-optout/issues/3), [#4](https://github.com/Apolloccrypt/nl-data-optout/issues/4)) +- **HTML/JS/CSS gesplitst** – code uitgesplitst in aparte bestanden voor betere onderhoudbaarheid (script.js, style.css) +- **UI** – flashy kleuren en emoji gereduceerd voor een rustigere leeservaring ### Fixed +- **Microsoft** – `privacy@microsoft.com` bouncet; vervangen door Microsoft privacy formulier ([#1](https://github.com/Apolloccrypt/nl-data-optout/issues/1)) +- **Pinterest** – `privacy@pinterest.com` bouncet; vervangen door contactformulier ([#2](https://github.com/Apolloccrypt/nl-data-optout/issues/2)) +- **DPG Media** – `info@dpgmedia.nl` bouncet; vervangen door privacy-rights formulier ([#3](https://github.com/Apolloccrypt/nl-data-optout/issues/3)) +- **Bol.com** – `privacy@bol.com` bouncet; ingesteld als login-only (verzoeken alleen via ingelogde account-omgeving) ([#4](https://github.com/Apolloccrypt/nl-data-optout/issues/4)) - **Broken Medium URLs** – alle verwijzingen naar `medium.com/p/75744f8645c6` en het lange artikel-pad vervangen door `https://medium.com/@mick.ronan.beer` (index.html, script.js, README.md) - **LinkedIn URL** – alle verwijzingen gecorrigeerd naar `https://www.linkedin.com/in/mick-beer/` (met `www.` en trailing slash) in index.html, README.md, CONTRIBUTING.md, DEPLOYMENT.md en config.yml; `@mickbeer`-mention is nu een klikbare link - **Relatieve links** – `CHANGELOG.md` en `LICENSE` in de footer verwijzen nu relatief, zodat de site niet breekt bij hosting buiten GitHub Pages From 18c6cf1de73b9e77d00bb894a26b0d7953b9ff6e Mon Sep 17 00:00:00 2001 From: Sten Tijhuis <102481635+Stensel8@users.noreply.github.com> Date: Wed, 1 Apr 2026 00:17:22 +0200 Subject: [PATCH 10/24] fix: update documentation and remove obsolete information --- CHANGELOG.md | 160 ++++++++------------------ CONTRIBUTING.md | 175 +++------------------------- DEPLOYMENT.md | 234 ++++--------------------------------- README.md | 292 ++++------------------------------------------- REPO-OVERVIEW.md | 270 ------------------------------------------- 5 files changed, 106 insertions(+), 1025 deletions(-) delete mode 100644 REPO-OVERVIEW.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cbfb87..f9bbb33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,146 +11,76 @@ en commit-berichten volgen grotendeels de stijl van [Conventional Commits](https ## [1.2.0] - 2026-03-31 ### Added -- **Bronlink bij Google** – update-banner toont nu een klikbare bronverwijzing naar het Medium-onderzoek (Volkskrant & Telegraaf) +- bronlink voor Google in de update-banner (onderzoek Volkskrant & Telegraaf) ### Changed -- **Naamgeving consistentie** – alle code-identifiers omgezet naar Engels en consistente conventies: camelCase voor JS-variabelen en -functies, kebab-case voor HTML IDs en CSS-klassen (`genereerMail` β†’ `generateMail`, `bedrijf` β†’ `company`, `ontvanger` β†’ `recipient`, etc.) -- **Form-waarden** – interne option-values omgezet naar Engels (`bezwaar` β†’ `objection`, `wissen` β†’ `erase`, `inzage` β†’ `access`, `beide` β†’ `both`) -- **Donatie-knop** – minder opdringerig; verplaatst van prominente gele box naar een subtiele regel in de footer -- **HTML/JS/CSS gesplitst** – code uitgesplitst in aparte bestanden voor betere onderhoudbaarheid (script.js, style.css) -- **UI** – flashy kleuren en emoji gereduceerd voor een rustigere leeservaring +- code uitgesplitst in aparte bestanden: script.js, style.css +- alle code-identifiers omgezet naar Engels met consistente conventies + (camelCase voor JS, kebab-case voor HTML IDs en CSS) +- interne form-values omgezet naar Engels (bezwaar/wissen/inzage/beide vervallen) +- donatie-knop verplaatst naar footer, minder prominent +- UI rustigere kleuren, geen emoji +- documentatie herschreven: README, CONTRIBUTING, DEPLOYMENT en CHANGELOG ingekort + en opgeschoond; veel herhaalde, lange en overbodige tekst verwijderd +- REPO-OVERVIEW.md verwijderd ### Fixed -- **Microsoft** – `privacy@microsoft.com` bouncet; vervangen door Microsoft privacy formulier ([#1](https://github.com/Apolloccrypt/nl-data-optout/issues/1)) -- **Pinterest** – `privacy@pinterest.com` bouncet; vervangen door contactformulier ([#2](https://github.com/Apolloccrypt/nl-data-optout/issues/2)) -- **DPG Media** – `info@dpgmedia.nl` bouncet; vervangen door privacy-rights formulier ([#3](https://github.com/Apolloccrypt/nl-data-optout/issues/3)) -- **Bol.com** – `privacy@bol.com` bouncet; ingesteld als login-only (verzoeken alleen via ingelogde account-omgeving) ([#4](https://github.com/Apolloccrypt/nl-data-optout/issues/4)) -- **Broken Medium URLs** – alle verwijzingen naar `medium.com/p/75744f8645c6` en het lange artikel-pad vervangen door `https://medium.com/@mick.ronan.beer` (index.html, script.js, README.md) -- **LinkedIn URL** – alle verwijzingen gecorrigeerd naar `https://www.linkedin.com/in/mick-beer/` (met `www.` en trailing slash) in index.html, README.md, CONTRIBUTING.md, DEPLOYMENT.md en config.yml; `@mickbeer`-mention is nu een klikbare link -- **Relatieve links** – `CHANGELOG.md` en `LICENSE` in de footer verwijzen nu relatief, zodat de site niet breekt bij hosting buiten GitHub Pages -- **Result div leeg** – lege `#result` div werd altijd getoond als groene balk; verborgen via `#result:empty { display: none }` in CSS -- **Update-banner links** – note-tekst gebruikt nu `innerHTML` zodat bronlinks correct renderen -- **Versie-inconsistentie** – site toonde v1.1.1 maar changelog liep slechts tot v1.1.0; v1.1.1 is nu alsnog gedocumenteerd (zie hieronder) +- Microsoft: privacy@microsoft.com bouncet, vervangen door formulier ([#1](https://github.com/Apolloccrypt/nl-data-optout/issues/1)) +- Pinterest: privacy@pinterest.com bouncet, vervangen door formulier ([#2](https://github.com/Apolloccrypt/nl-data-optout/issues/2)) +- DPG Media: info@dpgmedia.nl bouncet, vervangen door privacy-rights formulier ([#3](https://github.com/Apolloccrypt/nl-data-optout/issues/3)) +- Bol.com: privacy@bol.com bouncet, ingesteld als login-only ([#4](https://github.com/Apolloccrypt/nl-data-optout/issues/4)) +- broken Medium URLs vervangen door https://medium.com/@mick.ronan.beer +- LinkedIn URL gecorrigeerd naar https://www.linkedin.com/in/mick-beer/ +- lege result-div werd getoond als groene balk (#result:empty hidden) +- CHANGELOG liep tot v1.1.0 terwijl de site al v1.1.1 toonde +- links naar CHANGELOG.md en LICENSE in footer zijn nu relatief --- ## [1.1.1] - 2026-03-22 ### Fixed -- **Xandr e-mail** – `privacy@xandr.com` bouncete; vervangen door Microsoft privacy formulier met `isForm: true` -- **SmartOcto e-mail** – `privacy@smartocto.com` bouncete; vervangen door geverifieerd DPO-adres `dpo@smartocto.com` -- **JavaScript syntax** – ontbrekende komma's in brokers array veroorzaakten parse-fouten -- **Ontbrekende category-velden** – Xandr en SmartOcto misten een `category` property -- **Contact emails** – meerdere bedrijven bijgewerkt naar actuele adressen +- Xandr: privacy@xandr.com bouncet, vervangen door Microsoft privacy formulier +- SmartOcto: privacy@smartocto.com bouncet, vervangen door dpo@smartocto.com +- ontbrekende komma's in de brokers array veroorzaakten parse-fouten +- Xandr en SmartOcto misten een category-veld +- diverse contactadressen bijgewerkt ### Added -- **Compliance waarschuwing Xandr** – notitie toegevoegd: 0% GDPR response rate (noyb 2024) +- notitie bij Xandr: 0% GDPR response rate (noyb 2024) --- ## [1.1.0] - 2026-03-21 ### Added -- **Meta/Facebook formulier fix** – detecteert dat Meta geen email meer accepteert, geeft formulier instructies -- **Notes systeem** – waarschuwingsbanner voor bedrijven met speciale instructies -- **60+ brokers** – uitgebreide lijst (was 25) -- **CategorieΓ«n teller** – toont aantal brokers per categorie in dropdown -- **Dark pattern waarschuwing** – bij formulier-vereiste bedrijven -- **Kopieer naar clipboard** knop – makkelijker copy-paste -- **Changelog link** in footer -- **Bug report link** in disclaimer -- **GitHub Issues templates** (broken contact, feature request) +- detectie van bedrijven die geen email meer accepteren, met formulier-instructies +- waarschuwingsbanner voor bedrijven met speciale instructies +- 60+ brokers (was 25) +- categorieteller in de dropdown +- dark pattern waarschuwing bij formulier-vereiste bedrijven +- kopieer-naar-clipboard knop +- GitHub Issue templates (broken contact, feature request) ### Changed -- **UI verbeteringen** – betere warnings, info boxes, button styling -- **Broker object structuur** – toegevoegd: `note`, `isForm`, `formUrl` fields -- **Email template** – duidelijkere formatting -- **Footer** – LinkedIn link, versie nummer, changelog link -- **Result box** – betere formatting, copy button, tips +- broker objectstructuur uitgebreid met note, isForm en formUrl velden +- email template opmaak verbeterd +- footer met versienummer en changelog link ### Fixed -- **Meta contact** – `datarequests@support.facebook.com` vervangen door formulier -- **JavaScript escaping** – backticks en dollar signs in template copy -- **Mobile responsive** – betere display op kleine schermen - -### Documentation -- README.md volledig herschreven -- CONTRIBUTING.md toegevoegd -- Issue templates toegevoegd -- Changelog gestart +- Meta: datarequests@support.facebook.com vervangen door formulier +- JavaScript escaping voor backticks en dollar signs in clipboard copy +- weergave op kleine schermen --- ## [1.0.0] - 2026-03-20 ### Added -- **Eerste release** – 25 Nederlandse data brokers -- **GDPR Art. 21, 17, 15** – bezwaar, wissen, inzage -- **CategorieΓ«n** – Credit Bureaus, Ad-Tech, Media, Telecom, Retail -- **"Ander bedrijf" optie** – handmatige invoer -- **100% lokaal** – geen server, geen tracking -- **MIT License** – open source -- **GitHub Pages** – live hosting - -### Features -- Naam + email input -- Bedrijf selectie (dropdown met categorieΓ«n) -- Type verzoek (bezwaar / wissen / inzage / beide) -- Automatische mailto: link generatie -- Email template met GDPR artikelen -- Volledige disclaimer -- Mobile-friendly design - ---- - -## Toekomstige Updates - -### Geplanned -- [ ] **English version** (international brokers) -- [ ] **CSV export** – track welke verzoeken je verstuurd hebt -- [ ] **Response tracker** – check of bedrijven binnen 1 maand reageren -- [ ] **EU brokers** – uitbreiding naar andere EU landen -- [ ] **API voor automatisering** – bulk verzoeken (optioneel) - -### Community Requests -- [ ] Browser extension (optioneel) -- [ ] Template customization (eigen tekst) -- [ ] Multi-language support - ---- - -## Contact veranderingen - -### Meta/Facebook (maart 2026) -- **Oud:** `datarequests@support.facebook.com` -- **Nieuw:** Contact formulier verplicht -- **URL:** https://www.facebook.com/help/contact/540977946302970 -- **Reden:** Dark pattern – email vervangen door formulier (meer friction) -- **Gemeld door:** Tobias L. (LinkedIn community) -- **Fix:** v1.1.0 - -### Rapporteer contact wijzigingen via GitHub Issues! - ---- - -## Versie Nummering - -We gebruiken [Semantic Versioning](https://semver.org/): - -- **MAJOR** (1.x.x) – Breaking changes (bijv. volledige UI redesign) -- **MINOR** (x.1.x) – Nieuwe features (bijv. nieuwe brokers, nieuwe functionaliteit) -- **PATCH** (x.x.1) – Bug fixes, contact updates, kleine verbeteringen - ---- - -## Contributors - -- **Mick Beer** (@Apolloccrypt) – Creator, maintainer -- **Tobias L.** – Meta contact update report -- **Community** – Bug reports, feature requests - -Wil je bijdragen? Zie [CONTRIBUTING.md](CONTRIBUTING.md)! - ---- - -

    Last update: 31 maart 2026

    +- eerste release met 25 Nederlandse data brokers +- GDPR Art. 21 (bezwaar), Art. 17 (wissen), Art. 15 (inzage) +- categorieen: Credit Bureaus, Ad-Tech, Media, Telecom, Retail +- "ander bedrijf" optie voor handmatige invoer +- alles lokaal, geen server +- MIT licentie +- GitHub Pages hosting diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ed12cef..5a593dd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,169 +1,26 @@ -# Contributing to NL Data Brokers Opt-Out Tool +# Contributing -Thanks for your interest in improving this tool! πŸ™ +## Verouderd contactadres melden -We welcome contributions from the community. Here's how you can help: +Open een [issue](https://github.com/Apolloccrypt/nl-data-optout/issues/new?template=broken-contact.md) +met de bedrijfsnaam, het oude adres en het nieuwe adres of formulier. ---- +## Broker toevoegen -## πŸ› Reporting Bugs +Via een issue of pull request. Zie DEPLOYMENT.md voor de technische details. -### Contact Email Changed? -If a broker's privacy email no longer works: +Een broker wordt toegevoegd als het bedrijf in Nederland actief is, persoonsgegevens +verwerkt van Nederlandse burgers, en een publiek privacycontact heeft. -1. [Open an Issue](https://github.com/Apolloccrypt/nl-data-optout/issues/new?template=broken-contact.md) -2. Include: - - Broker name - - Old email (if known) - - New email or contact method - - How you discovered this (bounce, company website, etc.) +## Code bijdragen -**We aim to fix contact changes within 24-48 hours.** +HTML, CSS en vanilla JavaScript. Geen frameworks, geen build stap. +Fork de repo, maak je wijzigingen, test lokaal door index.html te openen in de browser, +en open een pull request. Voeg een regel toe aan CHANGELOG.md. ---- +Geen externe dependencies, geen server-side code, geen tracking. -## ✨ Adding New Brokers +## Vragen -Want to add a data broker to the list? - -### Requirements: -- Dutch company OR active in Netherlands -- Processes personal data of Dutch citizens -- Has public privacy contact (email or form) - -### How to add: - -**Option 1: Issue (easiest)** -1. [Open a Feature Request](https://github.com/Apolloccrypt/nl-data-optout/issues/new?template=feature-request.md) -2. Include: - - Company name - - Privacy email (usually `privacy@company.nl`) - - Category (Credit Bureau / Ad-Tech / Telecom / Retail / Media / Analytics / Marketing) - - Optional: Why it's relevant (e.g., "Used by 5+ Dutch news sites") - -**Option 2: Pull Request (advanced)** -1. Fork this repo -2. Edit `index.html` (around line 119) -3. Add broker to `brokers` array: - ```javascript - { - name: "Company Name", - email: "privacy@company.nl", - category: "Ad-Tech & Tracking", - note: "Optional note (e.g., 'Used by XYZ site')" - }, - ``` -4. Test locally (open `index.html` in browser) -5. Update `CHANGELOG.md` -6. Submit PR - ---- - -## πŸ”§ Code Contributions - -### Tech Stack: -- HTML5 (structure) -- Vanilla JavaScript (no frameworks!) -- CSS3 (styling) - -**No build step required** – just edit and open in browser. - -### Code Style: -- Use existing formatting -- Add comments for complex logic -- Keep JavaScript simple (accessible to non-devs) -- No external dependencies (keep it 100% local) - -### Pull Request Process: -1. Fork repo -2. Create feature branch (`git checkout -b feature/new-broker`) -3. Make changes -4. Test locally (open `index.html` in multiple browsers) -5. Update `CHANGELOG.md` (add to `[Unreleased]` section) -6. Commit with clear message (`Add broker: CompanyName`) -7. Push to fork -8. Open Pull Request - -**We review PRs within 1-3 days.** - ---- - -## πŸ“ Documentation - -Help improve docs: -- Fix typos in README -- Clarify usage instructions -- Add examples -- Translate (future: English version) - ---- - -## 🌍 Internationalization - -**Future goal:** Support EU-wide brokers. - -Interested in creating an English version or adding international brokers? -Open a Discussion or Issue to coordinate! - ---- - -## 🚫 What We Don't Accept - -- External dependencies (jQuery, React, npm packages) -- Server-side code (keep it 100% client-side) -- Tracking/analytics scripts -- Non-privacy-related brokers -- Malicious code or spam - ---- - -## πŸ’¬ Community - -- **GitHub Issues:** Bug reports, feature requests -- **GitHub Discussions:** General questions, ideas -- **LinkedIn:** [@mickbeer](https://www.linkedin.com/in/mick-beer/) – DM for complex questions - ---- - -## πŸ† Recognition - -Contributors are credited in: -- `CHANGELOG.md` -- README (if significant contribution) - ---- - -## βš–οΈ Legal - -By contributing, you agree: -- Your contributions are your own work -- You grant this project rights to use your contribution under MIT License -- No guarantee of merge (we review all PRs) - ---- - -## 🎯 Priority Issues - -Looking for where to help? Check these: - -**High Priority:** -- ![high-priority](https://img.shields.io/badge/-high%20priority-red) labels -- Contact changes (broken emails) -- Security issues - -**Good First Issues:** -- ![good-first-issue](https://img.shields.io/badge/-good%20first%20issue-green) labels -- Adding new brokers -- Documentation improvements - ---- - -## πŸ“ž Questions? - -Not sure how to contribute? Open an Issue or DM [@mickbeer](https://www.linkedin.com/in/mick-beer/) on LinkedIn. - -**We're friendly and help new contributors!** πŸ‘‹ - ---- - -

    Thanks for helping make tracking more transparent! πŸ›‘οΈ

    +https://github.com/Apolloccrypt/nl-data-optout/issues +https://www.linkedin.com/in/mick-beer/ diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index b354153..4cc949a 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -1,237 +1,49 @@ -# πŸš€ Deployment & Update Guide +# Deployment -## Quick Reference +Live site: https://apolloccrypt.github.io/nl-data-optout/ -**Live site:** https://apolloccrypt.github.io/nl-data-optout/ -**Repository:** https://github.com/Apolloccrypt/nl-data-optout +GitHub Pages bouwt automatisch vanuit de `main` branch. Na een push duurt het +ongeveer een minuut voordat de wijziging live is. ---- +## Broker toevoegen -## πŸ“¦ File Structure - -``` -nl-data-optout/ -β”œβ”€β”€ index.html # Main tool (all-in-one file) -β”œβ”€β”€ README.md # Documentation -β”œβ”€β”€ CHANGELOG.md # Version history -β”œβ”€β”€ CONTRIBUTING.md # Contribution guidelines -β”œβ”€β”€ LICENSE # MIT License -β”œβ”€β”€ .gitignore # Git ignore rules -└── .github/ - └── ISSUE_TEMPLATE/ - β”œβ”€β”€ config.yml # Issue template config - β”œβ”€β”€ broken-contact.md - β”œβ”€β”€ feature-request.md - └── bug-report.md -``` - ---- - -## πŸ”„ How to Update - -### **Option 1: GitHub Web Interface (Easiest)** - -1. Go to https://github.com/Apolloccrypt/nl-data-optout -2. Click on `index.html` -3. Click "Edit" (pencil icon) -4. Make changes -5. Scroll down β†’ "Commit changes" -6. Add commit message (e.g., "Add broker: CompanyName") -7. Commit directly to `main` branch -8. **Wait 1-2 minutes** β†’ Changes live at https://apolloccrypt.github.io/nl-data-optout/ - ---- - -### **Option 2: Git Command Line** - -```bash -# Clone repo -git clone https://github.com/Apolloccrypt/nl-data-optout.git -cd nl-data-optout - -# Make changes (edit index.html) - -# Test locally -open index.html # macOS -xdg-open index.html # Linux -start index.html # Windows - -# Commit -git add . -git commit -m "Add broker: CompanyName" -git push origin main - -# Wait 1-2 minutes for GitHub Pages to rebuild -``` - ---- - -## ✏️ Common Updates - -### **Adding a Broker** - -Edit `index.html` around line 119: +Voeg een entry toe aan de `brokers` array in script.js: ```javascript -const brokers = [ - // ... existing brokers ... - - { - name: "New Company", - email: "privacy@newcompany.nl", - category: "Ad-Tech & Tracking", - note: "Optional note about this broker" // Optional - }, -]; +{ name: "Bedrijfsnaam", email: "privacy@bedrijf.nl", category: "Ad-Tech & Tracking" } ``` -**Don't forget:** -1. Update `CHANGELOG.md` (add to `[Unreleased]` section) -2. Test locally (open index.html in browser) -3. Commit with clear message - ---- - -### **Fixing a Contact** - -Find the broker in `index.html` (around line 119-180): +Als een bedrijf alleen een formulier accepteert: -**Email changed:** ```javascript -// OLD -{ name: "Company", email: "old@company.nl", category: "Ad-Tech" } - -// NEW -{ name: "Company", email: "new@company.nl", category: "Ad-Tech" } -``` - -**Email replaced by form:** -```javascript -{ - name: "Company ⚠️", +{ + name: "Bedrijfsnaam", email: "FORM_REQUIRED", - formUrl: "https://company.com/contact-form", - category: "Ad-Tech", - note: "Email werkt niet meer sinds [datum]. Formulier vereist.", + formUrl: "https://bedrijf.nl/privacy-form", + category: "Ad-Tech & Tracking", + note: "Email werkt niet meer. Formulier vereist.", isForm: true } ``` ---- - -### **Updating Version** - -When releasing new version: - -1. **index.html** (line ~136): Update version comment - ```html -

    v1.2.0 β€’ Laatste update: [datum]

    - ``` +## Versie bijwerken -2. **CHANGELOG.md**: Move `[Unreleased]` to new `[1.2.0] - YYYY-MM-DD` +1. Versienummer en datum aanpassen in de footer van index.html +2. Entry toevoegen aan CHANGELOG.md +3. Committen en pushen -3. **README.md**: Update version badge and "Last update" footer +## Testen -4. Commit: `git commit -m "Release v1.2.0"` +Open index.html lokaal in de browser voor je pusht. Geen server nodig. -5. Tag: `git tag v1.2.0 && git push --tags` - ---- - -## πŸ§ͺ Testing - -### **Before Pushing:** - -1. **Open `index.html` locally** in browser -2. **Test broker selection** (pick 3-5 brokers) -3. **Generate email** (check template looks correct) -4. **Test "Andere" option** (manual entry) -5. **Test form-required broker** (e.g., Meta) -6. **Check mobile** (resize browser window to 375px width) - -### **After Pushing:** - -1. Wait 1-2 minutes for GitHub Pages -2. Visit https://apolloccrypt.github.io/nl-data-optout/ -3. Hard refresh (Ctrl+F5 / Cmd+Shift+R) -4. Test 1-2 brokers to confirm changes live - ---- - -## πŸ“Š Monitoring - -### **GitHub Actions** - -GitHub Pages auto-builds from `main` branch. -Check build status: https://github.com/Apolloccrypt/nl-data-optout/actions - -### **Analytics** (None!) - -This tool has **NO analytics** – 100% privacy. -Monitor via: -- GitHub star count -- Issue activity -- LinkedIn post engagement - ---- - -## πŸ› Rollback - -If you pushed a bug: +## Rollback ```bash -# Revert last commit git revert HEAD git push origin main - -# Or reset to previous commit (DANGEROUS - only if just pushed) -git reset --hard HEAD~1 -git push --force origin main ``` -**Better:** Fix forward (commit a fix) rather than rollback. - ---- - -## πŸ”’ Security - -### **No Server = No Server-Side Security Issues** - -This is a **static site** – no backend, no database, no API. - -**Security concerns:** -- XSS: Minimal risk (no user-generated content rendered) -- Data leaks: Impossible (100% client-side) -- Dependencies: None (no npm packages) - -**If security issue found:** -1. Open Issue with `security` label -2. Or DM @mickbeer on LinkedIn -3. Fix ASAP + announce in CHANGELOG - ---- - -## πŸ“ž Need Help? - -- **GitHub Issues:** Bug reports, questions -- **LinkedIn:** [@mickbeer](https://www.linkedin.com/in/mick-beer/) -- **Email:** Via LinkedIn (no public email to avoid spam) - ---- - -## βœ… Pre-Launch Checklist - -Before announcing updates: - -- [ ] Tested locally (multiple browsers) -- [ ] Updated CHANGELOG.md -- [ ] Version number incremented (if appropriate) -- [ ] Pushed to GitHub -- [ ] Confirmed live site updated (1-2 min wait) -- [ ] Tested live site (hard refresh) -- [ ] Mobile test -- [ ] Announced on LinkedIn (if major update) - ---- +## Contact -

    Happy deploying! πŸš€

    +https://github.com/Apolloccrypt/nl-data-optout/issues +https://www.linkedin.com/in/mick-beer/ diff --git a/README.md b/README.md index 6684544..27c8f82 100644 --- a/README.md +++ b/README.md @@ -1,288 +1,40 @@ -# πŸ›‘οΈ NL Data Brokers Opt-Out Tool +# NL Data Brokers Opt-Out Tool -**Genereer GDPR-verzoeken (Art. 21, 17, 15) naar 50+ Nederlandse data brokers in 2 minuten.** +Tool voor het versturen van GDPR-verzoeken naar Nederlandse data brokers. -πŸ”— **Live Tool:** https://apolloccrypt.github.io/nl-data-optout/ +Live: https://apolloccrypt.github.io/nl-data-optout/ -![License](https://img.shields.io/badge/license-MIT-blue.svg) -![Version](https://img.shields.io/badge/version-1.1.0-green.svg) -![Status](https://img.shields.io/badge/status-active-success.svg) +## Gebruik ---- +1. Vul naam en emailadres in +2. Selecteer een bedrijf +3. Kies het type verzoek (bezwaar, wissen, inzage, of beide) +4. Klik "Genereer bezwaarmail" -## πŸ“‹ Inhoudsopgave +Lokaal: clone de repo en open index.html in je browser. Geen server nodig. -- [Over dit project](#over-dit-project) -- [Features](#features) -- [Gebruik](#gebruik) -- [Ondersteunde Bedrijven](#ondersteunde-bedrijven) -- [Privacy & Veiligheid](#privacy--veiligheid) -- [Juridische Basis](#juridische-basis) -- [Bijdragen](#bijdragen) -- [Licentie](#licentie) -- [Contact](#contact) +## Achtergrond ---- +In maart 2026 testte ik 5 Nederlandse nieuwssites op cookie compliance. NU.nl bleek 104 van 121 ad-partners niet bij naam te noemen. NOS.nl plaatst cookies voor de banner verschijnt. Google staat op elke geteste site. -## 🎯 Over dit project +Onderzoek: https://medium.com/@mick.ronan.beer -Deze tool helpt Nederlandse burgers hun **GDPR-rechten** uit te oefenen tegenover data brokers, ad-tech bedrijven, telecom providers en retailers. +## Ondersteunde bedrijven -**Achtergrond:** -In maart 2026 testte ik 5 Nederlandse nieuwssites op cookie compliance. Bevindingen: -- **NU.nl:** 121 trackers, maar **104 partners niet bij naam genoemd** -- **NOS.nl:** Pre-consent tracking (cookies **vΓ³Γ³r** banner) -- **Google:** Aanwezig op **100% van de geteste sites** +60+ bedrijven verdeeld over credit bureaus, ad-tech, media, telecom, retail, analytics en marketing clouds. Zie script.js voor de volledige lijst. Er is ook een "ander bedrijf" optie voor handmatige invoer. -**Probleem:** Als je niet weet welke bedrijven je data hebben, kun je je rechten niet uitoefenen. +## Privacy -**Oplossing:** Deze tool. +Alles draait lokaal. Geen server, geen opslag, geen tracking. De tool genereert alleen tekst, jij verstuurt de mail zelf. -πŸ“š **Volledig onderzoek:** https://medium.com/@mick.ronan.beer +## Bijdragen ---- +Zie [CONTRIBUTING.md](CONTRIBUTING.md). Verouderd contactadres of bug? Open een [issue](https://github.com/Apolloccrypt/nl-data-optout/issues). -## ✨ Features +## Licentie -- βœ… **50+ Nederlandse data brokers** (ad-tech, credit bureaus, retail, telecom, media) -- βœ… **GDPR Art. 21** (bezwaar), **Art. 17** (wissen), **Art. 15** (inzage) -- βœ… **100% lokaal** – geen server, geen data-opslag, geen tracking -- βœ… **Open source** (MIT license) -- βœ… **Meta formulier-fix** – detecteert bedrijven die email vervingen door formulieren -- βœ… **Notes systeem** – waarschuwt voor AP boetes, dark patterns, pre-consent tracking -- βœ… **CategorieΓ«n** – credit bureaus, ad-tech, telecom, retail, media, analytics +MIT. Zie [LICENSE](LICENSE). ---- +## Contact -## πŸš€ Gebruik - -### **Online (aanbevolen):** - -1. Ga naar https://apolloccrypt.github.io/nl-data-optout/ -2. Vul je naam en email in -3. Selecteer een bedrijf -4. Kies verzoek type (bezwaar, wissen, inzage, of beide) -5. Klik "Genereer bezwaarmail" -6. Open in je mailprogramma of kopieer de tekst - -**Tijd:** 2 minuten per bedrijf - ---- - -### **Lokaal draaien:** - -```bash -git clone https://github.com/Apolloccrypt/nl-data-optout.git -cd nl-data-optout -# Open index.html in je browser (geen server nodig) -``` - ---- - -## 🏒 Ondersteunde Bedrijven (60+) - -### **Credit Bureaus (6)** -- Experian Nederland (€2.7M AP boete 2025) -- Graydon, Creditsafe, Focum BV, Dun & Bradstreet, Bisnode - -### **Ad-Tech & Tracking (27)** -- Google (100% aanwezig op NL sites) -- Criteo (80% aanwezig) -- Index Exchange (80% aanwezig) -- Meta/Facebook ⚠️ (formulier vereist sinds maart 2026) -- TikTok, LinkedIn, Twitter/X, Snapchat, Pinterest -- Amazon Ads, The Trade Desk, Magnite, PubMatic, OpenX -- Outbrain, Taboola, Xandr, AppNexus, AdForm, Sizmek -- MediaMath - -### **Media & Publishers (6)** -- DPG Media (NU.nl, AD.nl) – 104 van 121 partners niet genoemd -- NPO/NOS – pre-consent tracking -- RTL Nederland, Sanoma, Mediahuis, Talpa - -### **Telecom (7)** -- KPN, VodafoneZiggo, T-Mobile/Odido, Tele2 -- Youfone, Simyo, Lebara - -### **Retail & E-Commerce (10)** -- Kruidvat (€600k AP boete cookie wall) -- Coolblue (€40k AP boete pre-consent) -- Bol.com (best practice: 100% disclosure) -- Albert Heijn, Wehkamp, Zalando, HEMA, Action, MediaMarkt, Jumbo - -### **Analytics (6)** -- Smartocto/Content Insights (gebruikt door NOS) -- Piano, Comscore, Nielsen, Chartbeat - -### **Marketing Clouds (5)** -- Salesforce, Adobe, Oracle, HubSpot, Mailchimp - -**+ "Ander bedrijf" optie** voor handmatige invoer - -Volledige lijst: zie `index.html` regel 119-180 - ---- - -## πŸ”’ Privacy & Veiligheid - -### **100% Lokaal** -- Geen server-side code -- Geen data-opslag -- Geen cookies -- Geen tracking -- Geen third-party scripts - -### **Open Source** -- Volledige broncode beschikbaar -- Auditeerbaar (200 regels JavaScript) -- MIT License (vrij te gebruiken) - -### **Hoe het werkt:** -1. JavaScript draait lokaal in je browser -2. Template wordt gegenereerd (client-side) -3. `mailto:` link opent je mail-app -4. **JIJ** verstuurt de mail (niet de tool) - -**De tool stuurt NIETS zelf** – het genereert alleen tekst voor jou. - ---- - -## βš–οΈ Juridische Basis - -### **GDPR Rechten:** - -**Art. 21 - Recht op bezwaar:** -> "Je kunt bezwaar maken tegen verwerking voor direct marketing, profiling en tracking." - -**Art. 17 - Recht om vergeten te worden:** -> "Je kunt verwijdering van je gegevens eisen als er geen wettelijke bewaarplicht is." - -**Art. 15 - Recht op inzage:** -> "Je kunt opvragen welke persoonsgegevens een bedrijf van jou verwerkt." - -### **Reactietermijn:** -Bedrijven hebben **1 maand** om te reageren (Art. 12 GDPR). - -### **Bij weigering:** -- Vraag gemotiveerde uitleg -- Dien klacht in bij [Autoriteit Persoonsgegevens](https://autoriteitpersoonsgegevens.nl/nl/zelf-doen/privacyrechten/melden) - -### **Precedenten:** -- **Experian:** €2.7M boete (oktober 2025) – vendors niet bij naam -- **Kruidvat:** €600k boete – cookie wall -- **Coolblue:** €40k boete – pre-consent tracking - ---- - -## πŸ› οΈ Technologie - -- **HTML5** – structuur -- **Vanilla JavaScript** – geen frameworks -- **CSS3** – styling -- **GitHub Pages** – hosting - -**Geen build step, geen dependencies, geen npm.** Gewoon HTML/CSS/JS. - ---- - -## πŸ› Bug Melden? - -### **Contact veranderd?** -Als een bedrijf zijn privacy-email heeft gewijzigd, [open een Issue](https://github.com/Apolloccrypt/nl-data-optout/issues/new?template=broken-contact.md). - -**Voorbeeld:** Meta/Facebook verving `datarequests@support.facebook.com` met een formulier in maart 2026. Gebruiker Tobias L. meldde dit β†’ fix binnen 24u. - -### **Nieuw bedrijf toevoegen?** -Open een [Feature Request](https://github.com/Apolloccrypt/nl-data-optout/issues/new?template=feature-request.md) met: -- Bedrijfsnaam -- Privacy email (meestal `privacy@bedrijf.nl`) -- Categorie - ---- - -## 🀝 Bijdragen - -Bijdragen welkom! Zie [CONTRIBUTING.md](CONTRIBUTING.md) voor richtlijnen. - -### **Pull Requests:** -- Update `brokers` array in `index.html` -- Test lokaal (open `index.html` in browser) -- Update `CHANGELOG.md` -- Submit PR - -### **Community:** -- [GitHub Issues](https://github.com/Apolloccrypt/nl-data-optout/issues) -- [LinkedIn: Mick Beer](https://www.linkedin.com/in/mick-beer/) - ---- - -## πŸ“Š Impact - -**Doel:** Als 1000 mensen dit gebruiken = 10.000 GDPR-verzoeken verstuurd. - -**Kosten voor bedrijven:** €50 per verzoek (handmatige verwerking) = **€500.000 overhead**. - -**Effect:** Bij €500k wordt massale tracking economisch onhoudbaar. -β†’ Bedrijven moeten kiezen: **transparanter worden** of **stoppen**. - -**Collectieve actie werkt.** πŸ’ͺ - ---- - -## πŸ“œ Licentie - -**MIT License** – vrij te gebruiken, aanpassen, distribueren. - -Zie [LICENSE](LICENSE) voor details. - ---- - -## πŸ“ž Contact - -**Maker:** Mick Beer -**LinkedIn:** https://www.linkedin.com/in/mick-beer/ -**GitHub:** https://github.com/Apolloccrypt - -**Onderzoek:** -- [Medium artikel](https://medium.com/@mick.ronan.beer) (volledig onderzoek) -- [LinkedIn post](https://linkedin.com/posts/mick-beer_nl-data-brokers-opt-out-tool-activity-7441146526682202112-F_v7) - ---- - -## ⚠️ Disclaimer - -**Dit is GEEN juridisch advies.** - -Deze tool helpt bij uitoefenen GDPR-rechten. Raadpleeg privacy-advocaat of [Autoriteit Persoonsgegevens](https://autoriteitpersoonsgegevens.nl) bij twijfel. - -Maker niet aansprakelijk voor gebruik. Eigen verantwoordelijkheid. - -Voor juridisch advies: advocaat of AP. - ---- - -## 🌟 Support dit project - -**Vind je dit nuttig?** - -- ⭐ **Star deze repo** op GitHub -- πŸ”„ **Deel** met vrienden/familie -- πŸ“’ **Post** op social media -- πŸ› **Meld bugs** via Issues -- πŸ’‘ **Voeg bedrijven toe** via PR - -**Samen maken we tracking transparanter.** πŸ›‘οΈ - ---- - -## πŸ“š Bronnen - -- [GDPR volledige tekst](https://eur-lex.europa.eu/legal-content/NL/TXT/?uri=CELEX:32016R0679) -- [ePrivacy Richtlijn](https://eur-lex.europa.eu/legal-content/NL/TXT/?uri=CELEX:32002L0058) -- [AP Cookie Richtsnoeren](https://autoriteitpersoonsgegevens.nl/themas/internet-telefoon-post/cookies) -- [CJEU Planet49 (C-673/17)](https://curia.europa.eu/juris/document/document.jsf?docid=218462) - ---- - -

    Made with ❀️ for privacy β€’ Open Source β€’ Community-Driven

    -

    v1.1.0 β€’ Last update: March 21, 2026

    +Mick Beer β€” https://www.linkedin.com/in/mick-beer/ diff --git a/REPO-OVERVIEW.md b/REPO-OVERVIEW.md deleted file mode 100644 index 3f9068b..0000000 --- a/REPO-OVERVIEW.md +++ /dev/null @@ -1,270 +0,0 @@ -# βœ… COMPLETE GITHUB REPO - KLAAR VOOR DEPLOYMENT - -## πŸ“ COMPLETE FILE STRUCTURE - -``` -nl-data-optout/ -β”œβ”€β”€ index.html βœ… Main tool (60+ brokers, Meta fix, notes system) -β”œβ”€β”€ README.md βœ… Complete documentation (impact, legal, usage) -β”œβ”€β”€ CHANGELOG.md βœ… Version history (v1.0.0 β†’ v1.1.0) -β”œβ”€β”€ CONTRIBUTING.md βœ… Contribution guidelines -β”œβ”€β”€ DEPLOYMENT.md βœ… Update & deployment guide -β”œβ”€β”€ LICENSE βœ… MIT License -β”œβ”€β”€ .gitignore βœ… Git ignore rules -└── .github/ - └── ISSUE_TEMPLATE/ - β”œβ”€β”€ config.yml βœ… Template configuration - β”œβ”€β”€ broken-contact.md βœ… Report broken contacts - β”œβ”€β”€ feature-request.md βœ… Add new brokers - └── bug-report.md βœ… Bug reports -``` - -**Total:** 11 files - ---- - -## 🎯 WHAT'S NEW IN v1.1.0 - -### **Major Features:** - -βœ… **Meta/Facebook Fix** (Tobias feedback!) -- Detecteert dat Meta email niet meer werkt -- Toont formulier instructies + link -- Kopieert template naar clipboard -- Dark pattern waarschuwing - -βœ… **60+ Brokers** (was 25) -- Credit Bureaus: 6 -- Ad-Tech: 27 -- Media: 6 -- Telecom: 7 -- Retail: 10 -- Analytics: 6 -- Marketing: 5 - -βœ… **Notes System** -- AP boetes vermeld (Experian €2.7M, Kruidvat €600k, Coolblue €40k) -- Pre-consent tracking warnings (NOS, Coolblue) -- Vendor disclosure issues (DPG Media: 104/121) -- Best practice highlights (Bol.com: 100% disclosure) - -βœ… **UI Improvements** -- Warning banner voor speciale instructies -- Info boxes voor dark patterns -- Copy to clipboard knop -- Betere mobile responsive -- Footer met versie + changelog link - -βœ… **Community Features** -- GitHub Issue templates (3 types) -- CONTRIBUTING.md (hoe bij te dragen) -- DEPLOYMENT.md (how to update) -- CHANGELOG.md (version tracking) -- Bug report instructies - ---- - -## πŸš€ DEPLOYMENT INSTRUCTIES - -### **Option 1: Replace Existing Repo (Recommended)** - -```bash -# Backup current repo (optional) -cd ~/path/to/nl-data-optout -cp -r . ../nl-data-optout-backup - -# Replace all files -rm -rf * # WARNING: This deletes everything! -rm -rf .github .gitignore # Hidden files too - -# Copy new files from downloaded folder -cp -r /path/to/downloaded/github-repo-v2/* . -cp -r /path/to/downloaded/github-repo-v2/.github . -cp /path/to/downloaded/github-repo-v2/.gitignore . - -# Check everything -ls -la - -# Commit -git add . -git commit -m "Release v1.1.0 - Meta fix + 60 brokers + community features" -git push origin main - -# Wait 1-2 minutes, then check: -# https://apolloccrypt.github.io/nl-data-optout/ -``` - ---- - -### **Option 2: Fresh Clone (If Starting Fresh)** - -```bash -# If you want to start completely fresh -cd ~/Desktop -mv nl-data-optout nl-data-optout-old -mkdir nl-data-optout -cd nl-data-optout - -# Copy all files from downloaded folder -cp -r /path/to/downloaded/github-repo-v2/* . -cp -r /path/to/downloaded/github-repo-v2/.github . -cp /path/to/downloaded/github-repo-v2/.gitignore . - -# Initialize Git -git init -git add . -git commit -m "Initial commit - v1.1.0" - -# Connect to GitHub -git remote add origin https://github.com/Apolloccrypt/nl-data-optout.git -git branch -M main -git push -u origin main --force # CAREFUL: Overwrites remote! -``` - ---- - -## πŸ§ͺ TESTING CHECKLIST - -**Before pushing to GitHub:** - -- [ ] Open `index.html` in browser (locally) -- [ ] Test 3-5 brokers (select + generate email) -- [ ] Test Meta (should show formulier warning) -- [ ] Test "Andere" option (manual entry) -- [ ] Check mobile (resize to 375px width) -- [ ] All links work (GitHub, Medium, LinkedIn) -- [ ] No JavaScript errors (F12 console) - -**After pushing:** - -- [ ] Wait 1-2 minutes (GitHub Pages rebuild) -- [ ] Visit https://apolloccrypt.github.io/nl-data-optout/ -- [ ] Hard refresh (Ctrl+F5 / Cmd+Shift+R) -- [ ] Test 1-2 brokers to confirm live -- [ ] Check broker count shows "60+" -- [ ] Test Meta β†’ should show form warning - ---- - -## πŸ“§ REPLY TO TOBIAS - -**Once deployed, reply on LinkedIn:** - -``` -βœ… Fixed, Tobias! - -Tool is updated (v1.1.0): -β€’ Meta contact form geΓ―mplementeerd -β€’ Dark pattern waarschuwing toegevoegd -β€’ 60+ brokers (was 25) -β€’ Issue templates voor toekomstige reports - -Live: apolloccrypt.github.io/nl-data-optout - -Refresh de pagina, selecteer Meta/Facebook, je ziet nu een formulier-instructie ipv mailto link. - -Bedankt voor je waardevolle feedback - dit helpt iedereen! πŸ™ - -PS: GitHub repo heeft nu ook Issue templates, dus toekomstige -contact-wijzigingen kunnen direct gerapporteerd worden: -github.com/Apolloccrypt/nl-data-optout/issues -``` - ---- - -## πŸ“Š FILE DETAILS - -### **index.html** (Main Tool) -- Lines: ~430 -- Brokers: 60 -- Features: Meta fix, notes, clipboard copy, dark pattern warnings -- Size: ~18 KB - -### **README.md** (Documentation) -- Sections: 12 -- Links: 15+ -- Badges: 3 -- Size: ~11 KB - -### **CHANGELOG.md** (Version History) -- Versions: 2 (v1.0.0, v1.1.0) -- Format: Keep a Changelog -- Includes: Meta contact change documentation - -### **CONTRIBUTING.md** (Contribution Guide) -- Sections: 9 -- Includes: Code style, PR process, priority issues -- Size: ~4 KB - -### **DEPLOYMENT.md** (Update Guide) -- Sections: 10 -- Includes: Git commands, testing checklist, rollback -- Size: ~4 KB - -### **LICENSE** (MIT) -- Standard MIT License -- Copyright: 2026 Mick Beer - -### **.gitignore** -- Ignores: OS files, editor files, logs, temp files - -### **Issue Templates** (3) -- broken-contact.md (report email changes) -- feature-request.md (add new brokers) -- bug-report.md (technical issues) -- config.yml (template configuration) - ---- - -## 🎯 NEXT STEPS - -**Immediately:** -1. [ ] Deploy to GitHub (replace or fresh clone) -2. [ ] Test live site (wait 1-2 min) -3. [ ] Reply to Tobias on LinkedIn -4. [ ] Update LinkedIn post (optional: "Tool updated v1.1.0") - -**This Week:** -1. [ ] Monitor GitHub issues (watch for new reports) -2. [ ] Check LinkedIn for tool feedback -3. [ ] Screenshot new version (for future Medium update) - -**Week 2:** -1. [ ] AP melding (with "10k+ views" enhancement) -2. [ ] Media outreach (if tool >5k users) - ---- - -## βœ… WHAT YOU HAVE NOW - -**Complete, production-ready GitHub repo with:** - -βœ… 60+ Dutch data brokers -βœ… Meta formulier fix -βœ… AP boete notes (€3.9M total precedents) -βœ… Dark pattern detection -βœ… Community contribution system -βœ… Professional documentation -βœ… Issue templates -βœ… Deployment guides -βœ… MIT License -βœ… Mobile responsive -βœ… 100% local (no tracking) -βœ… Version 1.1.0 (production ready) - -**STATUS:** 🟒 READY TO DEPLOY - ---- - -## πŸ“ž SUPPORT - -If you need help deploying: -- DM me details -- Or: I can walk through Git commands step-by-step -- Or: Share screen (if needed) - -**This is complete and tested** - ready to go live! πŸš€ - ---- - -

    KLAAR OM TE DEPLOYEN? πŸ’ͺ

    From 25065bd26d174c961b0573ffa4f6576024ad4027 Mon Sep 17 00:00:00 2001 From: Sten Tijhuis <102481635+Stensel8@users.noreply.github.com> Date: Wed, 1 Apr 2026 00:32:13 +0200 Subject: [PATCH 11/24] fix: implement suggested fixes from @Copilot --- CHANGELOG.md | 2 +- index.html | 6 +- script.js | 199 ++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 155 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9bbb33..7ca3018 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ en commit-berichten volgen grotendeels de stijl van [Conventional Commits](https ### Fixed - Microsoft: privacy@microsoft.com bouncet, vervangen door formulier ([#1](https://github.com/Apolloccrypt/nl-data-optout/issues/1)) - Pinterest: privacy@pinterest.com bouncet, vervangen door formulier ([#2](https://github.com/Apolloccrypt/nl-data-optout/issues/2)) -- DPG Media: info@dpgmedia.nl bouncet, vervangen door privacy-rights formulier ([#3](https://github.com/Apolloccrypt/nl-data-optout/issues/3)) +- DPG Media: privacy@dpgmedia.nl bouncet, vervangen door privacy-rights formulier ([#3](https://github.com/Apolloccrypt/nl-data-optout/issues/3)) - Bol.com: privacy@bol.com bouncet, ingesteld als login-only ([#4](https://github.com/Apolloccrypt/nl-data-optout/issues/4)) - broken Medium URLs vervangen door https://medium.com/@mick.ronan.beer - LinkedIn URL gecorrigeerd naar https://www.linkedin.com/in/mick-beer/ diff --git a/index.html b/index.html index a85d94f..de25ead 100644 --- a/index.html +++ b/index.html @@ -3,8 +3,8 @@ - NL Data Brokers Opt-Out Tool - GDPR Art. 21 & 17 - + NL Data Brokers Opt-Out Tool - GDPR Art. 21, 17 & 15 + @@ -94,7 +94,7 @@

    Over dit project

    Made voor privacy door Mick Beer

    Broncode op GitHub - Open Source - MIT License

    v1.2.0 - Laatste update: 31 maart 2026 - Changelog

    -

    Dit project is onafhankelijk en gratis. Buy me a coffee als je het nuttig vond.

    +

    Dit project is onafhankelijk en gratis. Buy me a coffee als je het nuttig vond.

    diff --git a/script.js b/script.js index dd91da1..fa4d435 100644 --- a/script.js +++ b/script.js @@ -8,7 +8,7 @@ const brokers = [ { name: "Bisnode (Dun & Bradstreet)", email: "privacy@bisnode.nl", category: "Credit Bureaus" }, // === AD-TECH & TRACKING === - { name: "Google (Ads/Analytics)", email: "privacy@google.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 100% van geteste NL nieuwssites. Bron: Onderzoek Volkskrant & Telegraaf (Medium)" }, + { name: "Google (Ads/Analytics)", email: "privacy@google.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 100% van geteste NL nieuwssites. Bron: Onderzoek Volkskrant & Telegraaf (Medium)" }, { name: "Criteo", email: "privacy@criteo.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, { name: "Index Exchange", email: "privacy@indexexchange.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, { @@ -155,8 +155,8 @@ extraInput.type = 'text'; extraInput.id = 'extra-company'; extraInput.placeholder = 'Bijv. Bedrijfsnaam - privacy@bedrijf.nl'; extraInput.style.display = 'none'; -companySelect.parentNode.insertBefore(extraLabel, companySelect.nextSibling.nextSibling); -companySelect.parentNode.insertBefore(extraInput, extraLabel.nextSibling); +companySelect.insertAdjacentElement('afterend', extraInput); +companySelect.insertAdjacentElement('afterend', extraLabel); companySelect.addEventListener('change', () => { const show = companySelect.value === 'other'; @@ -201,9 +201,25 @@ function generateMail() { alert('Vul aub naam (en liefst email) van het bedrijf in!'); return; } - const parts = extra.split('-').map(p => p.trim()); - companyName = parts[0]; - recipient = parts[1] || `privacy@${companyName.toLowerCase().replace(/[^a-z0-9]/g,'')}.nl`; + // Split only on the first spaced dash (including en/em dashes) to preserve hyphens in company names + const separators = [' - ', ' – ', ' β€” ']; + let sepIndex = -1; + let sepLength = 0; + for (const sep of separators) { + const i = extra.indexOf(sep); + if (i !== -1 && (sepIndex === -1 || i < sepIndex)) { + sepIndex = i; + sepLength = sep.length; + } + } + if (sepIndex !== -1) { + companyName = extra.slice(0, sepIndex).trim(); + const recipientPart = extra.slice(sepIndex + sepLength).trim(); + recipient = recipientPart || `privacy@${companyName.toLowerCase().replace(/[^a-z0-9]/g,'')}.nl`; + } else { + companyName = extra; + recipient = `privacy@${companyName.toLowerCase().replace(/[^a-z0-9]/g,'')}.nl`; + } } else { const selected = brokers.find(b => b.name === company); if (selected) { @@ -255,62 +271,149 @@ ${name}`; const selected = brokers.find(b => b.name === companyName) || brokers.find(b => b.name === company); const loginOnly = selected && selected.loginOnly; + const resultEl = document.getElementById('result'); + if (isForm) { if (loginOnly) { - document.getElementById('result').innerHTML = ` -

    Geen publiek contactkanaal beschikbaar

    -
    -

    ${companyName} heeft geen publiek e-mailadres of formulier voor GDPR-verzoeken.

    -

    Verzoeken verlopen alleen via de ingelogde account-omgeving op hun website.

    -
    - `; + resultEl.innerHTML = ''; + const h3 = document.createElement('h3'); + h3.textContent = 'Geen publiek contactkanaal beschikbaar'; + resultEl.appendChild(h3); + const warningDiv = document.createElement('div'); + warningDiv.className = 'warning'; + const p1 = document.createElement('p'); + const strong1 = document.createElement('strong'); + strong1.textContent = companyName; + p1.appendChild(strong1); + p1.appendChild(document.createTextNode(' heeft geen publiek e-mailadres of formulier voor GDPR-verzoeken.')); + warningDiv.appendChild(p1); + const p2 = document.createElement('p'); + p2.textContent = 'Verzoeken verlopen alleen via de ingelogde account-omgeving op hun website.'; + warningDiv.appendChild(p2); + resultEl.appendChild(warningDiv); return; } + const renderFormResult = (copied) => { + resultEl.innerHTML = ''; + const h3 = document.createElement('h3'); + h3.textContent = copied ? 'Let op: Dit bedrijf vereist een formulier' : 'Formulier vereist'; + resultEl.appendChild(h3); + + if (copied) { + const warningDiv = document.createElement('div'); + warningDiv.className = 'warning'; + const p1 = document.createElement('p'); + const strong1 = document.createElement('strong'); + strong1.textContent = companyName; + p1.appendChild(strong1); + p1.appendChild(document.createTextNode(' accepteert geen email meer voor GDPR-verzoeken.')); + warningDiv.appendChild(p1); + const p2 = document.createElement('p'); + p2.textContent = 'Je moet hun contact formulier gebruiken. De tekst is gekopieerd naar je clipboard.'; + warningDiv.appendChild(p2); + resultEl.appendChild(warningDiv); + const h4 = document.createElement('h4'); + h4.textContent = 'Template (gekopieerd):'; + resultEl.appendChild(h4); + } else { + const p = document.createElement('p'); + p.textContent = 'Kopieer onderstaande tekst en plak in het formulier:'; + resultEl.appendChild(p); + } + + const pre = document.createElement('pre'); + pre.style.cssText = 'background:#f5f5f5; padding:1rem; border-radius:6px; overflow:auto; max-height:300px; border:1px solid #ddd;'; + pre.textContent = body; + resultEl.appendChild(pre); + + const btn = document.createElement('button'); + btn.textContent = 'Open Contact Formulier'; + btn.addEventListener('click', () => window.open(formUrl, '_blank', 'noopener,noreferrer')); + resultEl.appendChild(btn); + + if (copied) { + const infoDiv = document.createElement('div'); + infoDiv.className = 'info'; + infoDiv.style.marginTop = '1rem'; + const strong2 = document.createElement('strong'); + strong2.textContent = 'Dark Pattern Alert:'; + infoDiv.appendChild(strong2); + infoDiv.appendChild(document.createTextNode(' Dit is een voorbeeld van een "dark pattern" - bedrijven maken GDPR-verzoeken moeilijker door email te vervangen met formulieren. Dit verhoogt friction en vermindert het aantal opt-outs. Overweeg dit te melden bij de ')); + const link = document.createElement('a'); + link.href = 'https://autoriteitpersoonsgegevens.nl/nl/zelf-doen/privacyrechten/melden'; + link.textContent = 'Autoriteit Persoonsgegevens'; + infoDiv.appendChild(link); + infoDiv.appendChild(document.createTextNode('.')); + resultEl.appendChild(infoDiv); + } + }; + navigator.clipboard.writeText(body).then(() => { - document.getElementById('result').innerHTML = ` -

    Let op: Dit bedrijf vereist een formulier

    -
    -

    ${companyName} accepteert geen email meer voor GDPR-verzoeken.

    -

    Je moet hun contact formulier gebruiken. De tekst is gekopieerd naar je clipboard.

    -
    -

    Template (gekopieerd):

    -
    ${body}
    - -
    - Dark Pattern Alert: Dit is een voorbeeld van een "dark pattern" - bedrijven maken GDPR-verzoeken moeilijker door email te vervangen met formulieren. - Dit verhoogt friction en vermindert het aantal opt-outs. Overweeg dit te melden bij de - Autoriteit Persoonsgegevens. -
    - `; + renderFormResult(true); }).catch(() => { alert('Kon tekst niet kopieren naar clipboard. Kopieer handmatig uit onderstaand vak.'); - document.getElementById('result').innerHTML = ` -

    Formulier vereist

    -

    Kopieer onderstaande tekst en plak in het formulier:

    -
    ${body}
    - - `; + renderFormResult(false); }); } else { const mailto = `mailto:${recipient}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`; - document.getElementById('result').innerHTML = ` -

    Klaar! Open de mail:

    -

    Naar: ${recipient}

    -

    Onderwerp: ${subject}

    -

    Template:

    -
    ${body}
    - - -

    - Tip: Werkt "mailto:" niet? Gebruik "Kopieer Tekst" en plak in je mail-app. -

    - `; + resultEl.innerHTML = ''; + const h3 = document.createElement('h3'); + h3.textContent = 'Klaar! Open de mail:'; + resultEl.appendChild(h3); + + const pTo = document.createElement('p'); + const strongTo = document.createElement('strong'); + strongTo.textContent = 'Naar:'; + pTo.appendChild(strongTo); + pTo.appendChild(document.createTextNode(' ' + recipient)); + resultEl.appendChild(pTo); + + const pSubject = document.createElement('p'); + const strongSubject = document.createElement('strong'); + strongSubject.textContent = 'Onderwerp:'; + pSubject.appendChild(strongSubject); + pSubject.appendChild(document.createTextNode(' ' + subject)); + resultEl.appendChild(pSubject); + + const h4 = document.createElement('h4'); + h4.textContent = 'Template:'; + resultEl.appendChild(h4); + + const pre = document.createElement('pre'); + pre.style.cssText = 'background:#f5f5f5; padding:1rem; border-radius:6px; overflow:auto; max-height:300px; border:1px solid #ddd;'; + pre.textContent = body; + resultEl.appendChild(pre); + + const openBtn = document.createElement('button'); + openBtn.textContent = 'Open in mailprogramma'; + openBtn.addEventListener('click', () => { window.location = mailto; }); + resultEl.appendChild(openBtn); + + const copyBtn = document.createElement('button'); + copyBtn.className = 'secondary'; + copyBtn.textContent = 'Kopieer Tekst'; + copyBtn.addEventListener('click', () => { + navigator.clipboard.writeText(body).then(() => alert('Tekst gekopieerd naar clipboard!')); + }); + resultEl.appendChild(copyBtn); + + const tip = document.createElement('p'); + tip.style.cssText = 'margin-top:1rem; font-size:0.9rem; color:#666;'; + const tipStrong = document.createElement('strong'); + tipStrong.textContent = 'Tip:'; + tip.appendChild(tipStrong); + tip.appendChild(document.createTextNode(' Werkt "mailto:" niet? Gebruik "Kopieer Tekst" en plak in je mail-app.')); + resultEl.appendChild(tip); } } window.addEventListener('DOMContentLoaded', () => { - document.getElementById('broker-count').innerHTML = - `${brokers.length} Nederlandse data brokers beschikbaar`; + const brokerCountEl = document.getElementById('broker-count'); + brokerCountEl.innerHTML = ''; + const strong = document.createElement('strong'); + strong.textContent = `${brokers.length} Nederlandse data brokers`; + brokerCountEl.appendChild(strong); + brokerCountEl.appendChild(document.createTextNode(' beschikbaar')); }); From ca8067f3eccc9415a8fa0077dfcd49086ee0abf3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Apr 2026 13:31:10 +0000 Subject: [PATCH 12/24] feat: add Wayback Machine / Internet Archive contact Agent-Logs-Url: https://github.com/Stensel8/nl-data-optout/sessions/c1508b09-bd86-4528-af66-956bce50c99c Co-authored-by: Stensel8 <102481635+Stensel8@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ script.js | 1 + 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ca3018..1513b17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ en commit-berichten volgen grotendeels de stijl van [Conventional Commits](https --- +## [Unreleased] + +### Added +- Wayback Machine / Internet Archive toegevoegd met contactadres info@archive.org + +--- + ## [1.2.0] - 2026-03-31 ### Added diff --git a/script.js b/script.js index fa4d435..ba913dc 100644 --- a/script.js +++ b/script.js @@ -65,6 +65,7 @@ const brokers = [ { name: "NPO / NOS", email: "privacy@npo.nl", category: "Media & Publishers", note: "Pre-consent tracking gedetecteerd (cookies voor banner)" }, { name: "Mediahuis (Telegraaf, NHD)", email: "privacy@mediahuis.nl", category: "Media & Publishers" }, { name: "Talpa Network", email: "privacy@talpanetwork.com", category: "Media & Publishers" }, + { name: "Wayback Machine / Internet Archive", email: "info@archive.org", category: "Media & Publishers" }, // === TELECOM === { name: "KPN", email: "privacy@kpn.com", category: "Telecom" }, From 699284efc781514934225b676ecd2814b282d944 Mon Sep 17 00:00:00 2001 From: Sten Tijhuis <102481635+Stensel8@users.noreply.github.com> Date: Mon, 6 Apr 2026 01:01:38 +0200 Subject: [PATCH 13/24] feat: enhance email generation with language toggle and update changelog --- CHANGELOG.md | 12 ++++++++++- index.html | 15 ++++++++------ script.js | 58 ++++++++++++++++++++++++++++++++++++++-------------- style.css | 7 +++++++ 4 files changed, 70 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1513b17..2c835b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,18 @@ en commit-berichten volgen grotendeels de stijl van [Conventional Commits](https ## [Unreleased] +--- + +## [1.2.1] - 2026-04-06 + ### Added -- Wayback Machine / Internet Archive toegevoegd met contactadres info@archive.org +- Wayback Machine / Internet Archive toegevoegd als data broker (info@archive.org) +- Nederlands / Engels taalschakelaar bij de e-mail generatieknop + +### Changed +- Broker-teller gewijzigd van "Nederlandse" naar "Europese" data brokers +- Kleine verbeteringen aan teksten +- Ongebruikte code verwijderd (dead assignments, dubbele `.find()`, overbodige `DOMContentLoaded` wrapper, gedupliceerde stijl) --- diff --git a/index.html b/index.html index de25ead..d771dca 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - NL Data Brokers Opt-Out Tool - GDPR Art. 21, 17 & 15 + EU Data Brokers Opt-Out Tool - GDPR Art. 21, 17 & 15 @@ -15,11 +15,11 @@

    Belangrijke Disclaimer

    Dit is GEEN juridisch advies. Deze tool helpt bij het uitoefenen van GDPR-rechten (Art. 21, 17, 15). Raadpleeg een privacy-advocaat of autoriteitpersoonsgegevens.nl bij twijfel. Maker niet aansprakelijk. Eigen verantwoordelijkheid. Volledige disclaimer onderaan.

    -

    NL Data Brokers Opt-Out Tool

    -

    Genereer snel GDPR Art. 21 (bezwaar), Art. 17 (wissen) of Art. 15 (inzage) mails naar Nederlandse data brokers, ad-tech, telecom, retail en media bedrijven. Alles lokaal in je browser - geen data-opslag.

    +

    EU Data Brokers Opt-Out Tool

    +

    Genereer snel GDPR Art. 21 (bezwaar), Art. 17 (wissen) of Art. 15 (inzage) mails naar Europese data brokers, ad-tech, telecom, retail en media bedrijven. Alles lokaal in je browser - geen data-opslag.

    - 50+ Nederlandse data brokers beschikbaar + 50+ Data brokers beschikbaar
    @@ -47,7 +47,10 @@

    NL Data Brokers Opt-Out Tool

    - +
    + + +
    @@ -93,7 +96,7 @@

    Over dit project

    diff --git a/script.js b/script.js index ba913dc..eca6c28 100644 --- a/script.js +++ b/script.js @@ -1,3 +1,10 @@ +let emailLang = 'nl'; + +function toggleEmailLang() { + emailLang = emailLang === 'nl' ? 'en' : 'nl'; + document.getElementById('lang-toggle').textContent = `Email: ${emailLang.toUpperCase()}`; +} + const brokers = [ // === CREDIT BUREAUS & DATA ENRICHMENT === { name: "Experian Nederland", email: "privacy@experian.nl", category: "Credit Bureaus", note: "AP boete 2.7M (2025) voor onvoldoende vendor disclosure" }, @@ -99,7 +106,6 @@ const brokers = [ { name: "SmartOcto", email: "dpo@smartocto.com", - altEmail: "info@smartocto.com", category: "Analytics", note: "DPO verified from official privacy policy. NL-based, GDPR compliant." }, @@ -180,6 +186,8 @@ companySelect.addEventListener('change', () => { } }); +const PRE_STYLE = 'background:#f5f5f5; padding:1rem; border-radius:6px; overflow:auto; max-height:300px; border:1px solid #ddd;'; + function generateMail() { const name = document.getElementById('name').value.trim(); const email = document.getElementById('email').value.trim(); @@ -227,7 +235,6 @@ function generateMail() { if (selected.isForm) { isForm = true; formUrl = selected.formUrl; - recipient = formUrl; } else { recipient = selected.email; } @@ -236,7 +243,12 @@ function generateMail() { } } - const subjectMap = { + const subjectMap = emailLang === 'en' ? { + objection: 'Objection to personal data processing (GDPR Art. 21)', + erase: 'Request for erasure of personal data (GDPR Art. 17)', + access: 'Request for access to personal data (GDPR Art. 15)', + both: 'Objection + erasure of personal data (GDPR Art. 21 & 17)' + } : { objection: 'Bezwaar tegen verwerking persoonsgegevens (GDPR Art. 21)', erase: 'Verzoek tot wissen persoonsgegevens (GDPR Art. 17)', access: 'Verzoek tot inzage persoonsgegevens (GDPR Art. 15)', @@ -244,7 +256,31 @@ function generateMail() { }; const subject = subjectMap[type]; - const body = `Geachte heer/mevrouw, + const body = emailLang === 'en' + ? `Dear Sir/Madam, + +My name is ${name} and my email address is ${email}. + +I hereby formally exercise my rights under the GDPR: + +${ + (type === 'objection' || type === 'both') + ? `- Objection to the processing of my personal data for marketing, profiling, tracking, etc. (Art. 21 GDPR). I request that ${companyName} ceases all such processing.\n` + : '' +}${ + (type === 'erase' || type === 'both') + ? `- Request for erasure of all my personal data (Art. 17 GDPR, right to be forgotten).\n` + : '' +}${ + type === 'access' + ? `- Request for access to all personal data you process about me (Art. 15 GDPR), including a copy.\n` + : '' +} +Please confirm within 1 month and provide proof of action. In case of refusal: a reasoned explanation. + +Kind regards, +${name}` + : `Geachte heer/mevrouw, Mijn naam is ${name} en mijn email is ${email}. @@ -263,13 +299,12 @@ ${ ? `- Verzoek tot inzage in alle persoonsgegevens die u van mij verwerkt (Art. 15 GDPR), inclusief een kopie.\n` : '' } - Graag ontvang ik binnen 1 maand bevestiging en bewijs van actie. Bij weigering: gemotiveerde uitleg. Met vriendelijke groet, ${name}`; - const selected = brokers.find(b => b.name === companyName) || brokers.find(b => b.name === company); + const selected = brokers.find(b => b.name === company); const loginOnly = selected && selected.loginOnly; const resultEl = document.getElementById('result'); @@ -324,7 +359,7 @@ ${name}`; } const pre = document.createElement('pre'); - pre.style.cssText = 'background:#f5f5f5; padding:1rem; border-radius:6px; overflow:auto; max-height:300px; border:1px solid #ddd;'; + pre.style.cssText = PRE_STYLE; pre.textContent = body; resultEl.appendChild(pre); @@ -410,11 +445,4 @@ ${name}`; } } -window.addEventListener('DOMContentLoaded', () => { - const brokerCountEl = document.getElementById('broker-count'); - brokerCountEl.innerHTML = ''; - const strong = document.createElement('strong'); - strong.textContent = `${brokers.length} Nederlandse data brokers`; - brokerCountEl.appendChild(strong); - brokerCountEl.appendChild(document.createTextNode(' beschikbaar')); -}); +document.getElementById('broker-count').innerHTML = `${brokers.length} Europese data brokers beschikbaar`; diff --git a/style.css b/style.css index 6b1ec42..b9d537a 100644 --- a/style.css +++ b/style.css @@ -75,6 +75,13 @@ button.secondary { button.secondary:hover { background: #616161; } +button.lang { + background: #1565c0; + margin-left: 0; +} + +button.lang:hover { background: #0d47a1; } + #result:empty { display: none; } From e2a7ec4957ae1eb86c11ab051f7196040e3f7363 Mon Sep 17 00:00:00 2001 From: Sten Tijhuis <102481635+Stensel8@users.noreply.github.com> Date: Mon, 6 Apr 2026 01:03:21 +0200 Subject: [PATCH 14/24] Update CHANGELOG.md --- CHANGELOG.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c835b2..e56d48e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,6 @@ en commit-berichten volgen grotendeels de stijl van [Conventional Commits](https --- -## [Unreleased] - ---- - ## [1.2.1] - 2026-04-06 ### Added @@ -21,7 +17,7 @@ en commit-berichten volgen grotendeels de stijl van [Conventional Commits](https ### Changed - Broker-teller gewijzigd van "Nederlandse" naar "Europese" data brokers - Kleine verbeteringen aan teksten -- Ongebruikte code verwijderd (dead assignments, dubbele `.find()`, overbodige `DOMContentLoaded` wrapper, gedupliceerde stijl) +- Ongebruikte code verwijderd --- From 3df8954def01ff3c09603037504ea72cbffeee33 Mon Sep 17 00:00:00 2001 From: Sten Tijhuis <102481635+Stensel8@users.noreply.github.com> Date: Mon, 6 Apr 2026 01:08:10 +0200 Subject: [PATCH 15/24] Update index.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index d771dca..393a54a 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ EU Data Brokers Opt-Out Tool - GDPR Art. 21, 17 & 15 - + From 0980edc8ffa2fbe2b67a98f9c994f48335f4e8a6 Mon Sep 17 00:00:00 2001 From: Sten Tijhuis <102481635+Stensel8@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:57:06 +0200 Subject: [PATCH 16/24] feat: Re-work and transition to Hugo Beginning the transitioning to Hugo static pages --- .github/workflows/hugo.yml | 47 ++++ .gitignore | 6 + content/_index.md | 4 + content/nl/_index.md | 4 + hugo.toml | 26 ++ i18n/en.yaml | 64 +++++ i18n/nl.yaml | 64 +++++ index.html | 105 -------- layouts/_default/baseof.html | 108 +++++++++ layouts/_default/list.html | 1 + layouts/index.html | 224 ++++++++++++++++++ script.js | 448 ----------------------------------- static/CNAME | 1 + static/js/script.js | 374 +++++++++++++++++++++++++++++ static/js/theme.js | 41 ++++ style.css | 125 ---------- 16 files changed, 964 insertions(+), 678 deletions(-) create mode 100644 .github/workflows/hugo.yml create mode 100644 content/_index.md create mode 100644 content/nl/_index.md create mode 100644 hugo.toml create mode 100644 i18n/en.yaml create mode 100644 i18n/nl.yaml delete mode 100644 index.html create mode 100644 layouts/_default/baseof.html create mode 100644 layouts/_default/list.html create mode 100644 layouts/index.html delete mode 100644 script.js create mode 100644 static/CNAME create mode 100644 static/js/script.js create mode 100644 static/js/theme.js delete mode 100644 style.css diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml new file mode 100644 index 0000000..e6dca79 --- /dev/null +++ b/.github/workflows/hugo.yml @@ -0,0 +1,47 @@ +name: Deploy Hugo to GitHub Pages + +on: + push: + branches: [dev] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Hugo + uses: peaceiris/actions-hugo@v3 + with: + hugo-version: latest + extended: false + + - name: Build + run: hugo --minify + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./public + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deploy.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deploy + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index d3046e7..15fff20 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,9 @@ package-lock.json # Personal notes notes.md TODO.md + +# Hugo build output +/public/ +/resources/ +.hugo_build.lock +/.claude diff --git a/content/_index.md b/content/_index.md new file mode 100644 index 0000000..7352e3e --- /dev/null +++ b/content/_index.md @@ -0,0 +1,4 @@ +--- +title: "EU Data Broker Opt-Out Tool" +description: "Generate GDPR requests to 60+ European data brokers in minutes. Runs 100% locally β€” no data stored." +--- diff --git a/content/nl/_index.md b/content/nl/_index.md new file mode 100644 index 0000000..6a6837a --- /dev/null +++ b/content/nl/_index.md @@ -0,0 +1,4 @@ +--- +title: "EU Data Broker Opt-Out Tool" +description: "Genereer GDPR-verzoeken naar 60+ Europese data brokers in minuten. 100% lokaal β€” geen data opgeslagen." +--- diff --git a/hugo.toml b/hugo.toml new file mode 100644 index 0000000..f0d79a9 --- /dev/null +++ b/hugo.toml @@ -0,0 +1,26 @@ +baseURL = "https://data-optout.stensel.nl/" +defaultContentLanguage = "en" +defaultContentLanguageInSubdir = false +enableRobotsTXT = true +disableKinds = ["taxonomy", "term"] + +[languages] + [languages.en] + languageCode = "en" + languageName = "English" + title = "OptOut EU" + weight = 1 + [languages.en.params] + description = "Generate GDPR requests to 60+ European data brokers in minutes. Runs 100% locally β€” no data stored." + + [languages.nl] + languageCode = "nl" + languageName = "Nederlands" + title = "OptOut EU" + weight = 2 + [languages.nl.params] + description = "Genereer GDPR-verzoeken naar 60+ Europese data brokers in minuten. 100% lokaal β€” geen data opgeslagen." + +[params] + github = "https://github.com/Stensel8/data-optout" + version = "2.0.0" diff --git a/i18n/en.yaml b/i18n/en.yaml new file mode 100644 index 0000000..e6ae23f --- /dev/null +++ b/i18n/en.yaml @@ -0,0 +1,64 @@ +disclaimer_short: "Not legal advice. This tool helps you exercise GDPR rights (Art. 15, 17 & 21). When in doubt, consult your" +disclaimer_dpa: "national Data Protection Authority" +disclaimer_full_link: "Full disclaimer" + +hero_title: "EU Data Broker\nOpt-Out Tool" +hero_description: "Generate GDPR objection, erasure or access emails to European data brokers, ad-tech, telecom, retail and media companies. Everything runs locally in your browser. No data stored." + +form_title: "Generate your request" +label_name: "Full name" +label_email: "Email address" +label_company: "Data broker / company" +label_type: "Request type" +label_other_company: "Company name and privacy email" +placeholder_name: "John Smith" +placeholder_email: "john@example.com" +placeholder_company: "Select a company" +placeholder_other: "e.g. Acme Corp | privacy@acme.com" +placeholder_other_hint: "Format: Company Name | privacy@company.com" +btn_generate: "Generate email" +type_objection: "Object to processing (Art. 21)" +type_erase: "Erasure of data (Art. 17)" +type_access: "Access to my data (Art. 15)" +type_both: "Object + erasure (Art. 21 & 17)" + +rights_title: "Your GDPR rights" +rights_official_text: "Official text" +rights_ap_page: "NL authority" +rights_eurlex: "EUR-Lex full regulation" + +art15_title: "Art. 15 β€” Right of access" +art15_text: "You have the right to know whether a company processes your personal data and, if so, to receive a complete copy of that data." +art15_url_info: "https://gdpr-info.eu/art-15-gdpr/" +art15_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-op-inzage" + +art17_title: "Art. 17 β€” Right to erasure" +art17_text: "You have the right to request deletion of all personal data a company holds about you, without undue delay. Also known as the \"right to be forgotten\"." +art17_url_info: "https://gdpr-info.eu/art-17-gdpr/" +art17_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-op-vergetelheid" + +art21_title: "Art. 21 β€” Right to object" +art21_text: "You have the right to object at any time to the processing of your personal data for marketing, profiling or tracking. The controller must stop unless it can demonstrate compelling legitimate grounds." +art21_url_info: "https://gdpr-info.eu/art-21-gdpr/" +art21_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-van-bezwaar" + +disclaimer_title: "Full disclaimer" +disclaimer_1: "No legal advice. Tool by an independent researcher, not a lawyer." +disclaimer_2: "No guarantees. Companies do not always respond. If refused, file a complaint with your national DPA." +disclaimer_3: "Personal responsibility. You decide how to use this tool and its content." +disclaimer_4: "Privacy. 100% local processing. No data storage, no server calls, no analytics." +disclaimer_5: "Legal use only. Only for your own legitimate GDPR requests." +disclaimer_6: "Updates. Companies change contact methods. Report issues via" +disclaimer_issues: "GitHub Issues" +disclaimer_accept: "By generating an email you accept these terms." + +about_title: "About this project" +about_intro: "This tool collects and analyses public data to show how European companies handle personal data." +about_goals_title: "Goals" +about_goal1: "Provide transparency about cookie tracking, dark patterns and unnecessary data storage" +about_goal2: "Support legislative efforts for stronger data protection (e.g. Check Don't Store)" +about_goal3: "Give citizens practical tools to exercise their GDPR rights" +about_footer: "Everything is based on reproducible technical research. No data is retained or distributed after analysis." + +footer_text: "OptOut EU Β· Open source Β· MIT License" +footer_legal: "Not legal advice Β· All processing is local" diff --git a/i18n/nl.yaml b/i18n/nl.yaml new file mode 100644 index 0000000..75fc7ab --- /dev/null +++ b/i18n/nl.yaml @@ -0,0 +1,64 @@ +disclaimer_short: "Dit is geen juridisch advies. Deze tool helpt je GDPR-rechten uit te oefenen (Art. 15, 17 & 21). Raadpleeg bij twijfel de" +disclaimer_dpa: "Autoriteit Persoonsgegevens" +disclaimer_full_link: "Volledige disclaimer" + +hero_title: "EU Data Broker\nOpt-Out Tool" +hero_description: "Genereer GDPR-bezwaar-, wis- of inzage-e-mails naar Europese data brokers, ad-tech, telecom, retail en mediabedrijven. Alles draait lokaal in je browser. Geen data opgeslagen." + +form_title: "Genereer je verzoek" +label_name: "Volledige naam" +label_email: "E-mailadres" +label_company: "Data broker / bedrijf" +label_type: "Type verzoek" +label_other_company: "Bedrijfsnaam en privacy-e-mailadres" +placeholder_name: "Jan Jansen" +placeholder_email: "jan@voorbeeld.nl" +placeholder_company: "Selecteer een bedrijf" +placeholder_other: "bijv. Bedrijf BV | privacy@bedrijf.nl" +placeholder_other_hint: "Formaat: Bedrijfsnaam | privacy@bedrijf.nl" +btn_generate: "Genereer e-mail" +type_objection: "Bezwaar tegen verwerking (Art. 21)" +type_erase: "Wissen van gegevens (Art. 17)" +type_access: "Inzage in mijn gegevens (Art. 15)" +type_both: "Bezwaar + wissen (Art. 21 & 17)" + +rights_title: "Jouw AVG-rechten" +rights_official_text: "OfficiΓ«le tekst" +rights_ap_page: "Autoriteit Persoonsgegevens" +rights_eurlex: "EUR-Lex volledige verordening" + +art15_title: "Art. 15 β€” Recht op inzage" +art15_text: "Je hebt het recht om te weten of een bedrijf jouw persoonsgegevens verwerkt en, zo ja, een volledige kopie van die gegevens te ontvangen." +art15_url_info: "https://gdpr-info.eu/art-15-gdpr/" +art15_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-op-inzage" + +art17_title: "Art. 17 β€” Recht op vergetelheid" +art17_text: "Je hebt het recht te eisen dat een bedrijf al jouw persoonsgegevens zonder onnodig uitstel verwijdert. Ook wel het \"recht om vergeten te worden\" genoemd." +art17_url_info: "https://gdpr-info.eu/art-17-gdpr/" +art17_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-op-gegevens-verwijderen" + +art21_title: "Art. 21 β€” Recht van bezwaar" +art21_text: "Je hebt het recht om te allen tijde bezwaar te maken tegen de verwerking van jouw persoonsgegevens voor marketing, profilering of tracking. De verwerkingsverantwoordelijke moet stoppen, tenzij hij dwingende gerechtvaardigde gronden kan aantonen." +art21_url_info: "https://gdpr-info.eu/art-21-gdpr/" +art21_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-van-bezwaar" + +disclaimer_title: "Volledige disclaimer" +disclaimer_1: "Geen juridisch advies. Tool van een onafhankelijk onderzoeker, geen advocaat." +disclaimer_2: "Geen garanties. Bedrijven reageren niet altijd. Bij weigering: klacht indienen bij de AP." +disclaimer_3: "Eigen verantwoordelijkheid. Jij beslist hoe je deze tool en de inhoud gebruikt." +disclaimer_4: "Privacy. 100% lokale verwerking. Geen dataopslag, geen servercalls, geen analytics." +disclaimer_5: "Legaal gebruik. Alleen voor eigen legitieme GDPR-verzoeken." +disclaimer_6: "Updates. Bedrijven veranderen contactmethoden. Meld problemen via" +disclaimer_issues: "GitHub Issues" +disclaimer_accept: "Door een e-mail te genereren accepteer je deze voorwaarden." + +about_title: "Over dit project" +about_intro: "Dit project verzamelt en analyseert openbare data om te laten zien hoe Europese bedrijven omgaan met persoonsgegevens." +about_goals_title: "Doelen" +about_goal1: "Transparantie bieden over cookie-tracking, dark patterns en onnodige dataopslag" +about_goal2: "Bewijs leveren voor wetgevingsinitiatieven voor betere gegevensbescherming (bijv. Check Don't Store)" +about_goal3: "Burgers praktische tools geven om hun AVG-rechten uit te oefenen" +about_footer: "Alles is gebaseerd op reproduceerbaar technisch onderzoek. Na analyse wordt alles permanent verwijderd." + +footer_text: "OptOut EU Β· Open source Β· MIT Licentie" +footer_legal: "Geen juridisch advies Β· Alle verwerking is lokaal" diff --git a/index.html b/index.html deleted file mode 100644 index 393a54a..0000000 --- a/index.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - EU Data Brokers Opt-Out Tool - GDPR Art. 21, 17 & 15 - - - - - - -
    -

    Belangrijke Disclaimer

    -

    Dit is GEEN juridisch advies. Deze tool helpt bij het uitoefenen van GDPR-rechten (Art. 21, 17, 15). Raadpleeg een privacy-advocaat of autoriteitpersoonsgegevens.nl bij twijfel. Maker niet aansprakelijk. Eigen verantwoordelijkheid. Volledige disclaimer onderaan.

    -
    - -

    EU Data Brokers Opt-Out Tool

    -

    Genereer snel GDPR Art. 21 (bezwaar), Art. 17 (wissen) of Art. 15 (inzage) mails naar Europese data brokers, ad-tech, telecom, retail en media bedrijven. Alles lokaal in je browser - geen data-opslag.

    - -
    - 50+ Data brokers beschikbaar -
    - - - - -
    - - - - - - - - - - - - -
    - - -
    -
    - -
    - - -
    -

    Volledige Disclaimer

    -
      -
    1. Geen juridisch advies - Tool door burger/security expert, geen advocaat.
    2. -
    3. Geen garanties - Bedrijven reageren niet altijd; bij weigering, klacht bij AP.
    4. -
    5. Persoonlijke verantwoordelijkheid - Jij beslist gebruik en inhoud.
    6. -
    7. Privacy - 100% lokaal, geen data-opslag of server-calls.
    8. -
    9. Legaal gebruik - Alleen eigen legitieme GDPR-verzoeken.
    10. -
    11. Updates - Bedrijven veranderen contact methoden; meld bugs via GitHub Issues.
    12. -
    -

    Door te genereren accepteer je deze voorwaarden.

    - -

    Bug Melden?

    -

    Als een contact email niet meer werkt of je vindt fouten, open een GitHub Issue of tag @mick-beer op LinkedIn.

    - -

    Meer Info

    -

    - Volledig onderzoek (Medium)
    - Autoriteit Persoonsgegevens
    - GitHub Repository -

    -
    - - -
    -

    Over dit project

    -

    Dit project verzamelt en analyseert openbare en gelekte data om te laten zien hoe Nederlandse bedrijven en media omgaan met persoonsgegevens.

    -

    Doel:

    - -

    Alles wat ik publiceer is gebaseerd op reproduceerbaar technisch onderzoek. Geen data wordt bewaard of verspreid. Na analyse wordt alles permanent verwijderd (responsible disclosure).

    -

    Dank je wel
    Mick Beer - Security Architect & onafhankelijk onderzoeker

    -
    - - - - - - diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html new file mode 100644 index 0000000..b4e936f --- /dev/null +++ b/layouts/_default/baseof.html @@ -0,0 +1,108 @@ + + + + + + {{ if .IsHome }}{{ site.Title }}{{ else }}{{ .Title }} Β· {{ site.Title }}{{ end }} + + {{ range .Translations }} + + {{ end }} + + + + + + {{ block "head" . }}{{ end }} + + + + + +
    + {{ block "main" . }}{{ end }} +
    + + + + + {{ block "scripts" . }}{{ end }} + + diff --git a/layouts/_default/list.html b/layouts/_default/list.html new file mode 100644 index 0000000..806bcec --- /dev/null +++ b/layouts/_default/list.html @@ -0,0 +1 @@ +{{ define "main" }}{{ end }} diff --git a/layouts/index.html b/layouts/index.html new file mode 100644 index 0000000..00f8709 --- /dev/null +++ b/layouts/index.html @@ -0,0 +1,224 @@ +{{ define "main" }} + + + + + +
    +

    + EU Data Broker
    Opt-Out Tool +

    +

    + {{ i18n "hero_description" }} +

    + 62 European data brokers +
    + + +
    + +
    + + +
    + +
    + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    {{ i18n "placeholder_other_hint" }}
    +
    + +
    + + +
    + +
    + + +
    + +
    +
    + +
    +
    +
    + +
    + + +
    + +
    + +
    +
    + Art. 15 +

    + {{ if eq .Lang "nl" }}Recht op inzage{{ else }}Right of access{{ end }} +

    +

    + {{ i18n "art15_text" }} +

    + +
    +
    + +
    +
    + Art. 17 +

    + {{ if eq .Lang "nl" }}Recht op vergetelheid{{ else }}Right to erasure{{ end }} +

    +

    + {{ i18n "art17_text" }} +

    + +
    +
    + +
    +
    + Art. 21 +

    + {{ if eq .Lang "nl" }}Recht van bezwaar{{ else }}Right to object{{ end }} +

    +

    + {{ i18n "art21_text" }} +

    + +
    +
    + +
    +

    + + + {{ i18n "rights_eurlex" }} (Regulation (EU) 2016/679) + +

    +
    + + +
    + +
      +
    1. {{ i18n "disclaimer_1" | safeHTML }}
    2. +
    3. {{ i18n "disclaimer_2" | safeHTML }}
    4. +
    5. {{ i18n "disclaimer_3" | safeHTML }}
    6. +
    7. {{ i18n "disclaimer_4" | safeHTML }}
    8. +
    9. {{ i18n "disclaimer_5" | safeHTML }}
    10. +
    11. + {{ i18n "disclaimer_6" | safeHTML }} + + {{ i18n "disclaimer_issues" }}. +
    12. +
    +

    {{ i18n "disclaimer_accept" }}

    +
    + + +
    + +
    +

    {{ i18n "about_intro" }}

    +

    {{ i18n "about_goals_title" }}

    +
      +
    • {{ i18n "about_goal1" }}
    • +
    • {{ i18n "about_goal2" }}
    • +
    • {{ i18n "about_goal3" }}
    • +
    +

    {{ i18n "about_footer" }}

    +
    +
    + +{{ end }} + +{{ define "scripts" }} + + +{{ end }} diff --git a/script.js b/script.js deleted file mode 100644 index eca6c28..0000000 --- a/script.js +++ /dev/null @@ -1,448 +0,0 @@ -let emailLang = 'nl'; - -function toggleEmailLang() { - emailLang = emailLang === 'nl' ? 'en' : 'nl'; - document.getElementById('lang-toggle').textContent = `Email: ${emailLang.toUpperCase()}`; -} - -const brokers = [ - // === CREDIT BUREAUS & DATA ENRICHMENT === - { name: "Experian Nederland", email: "privacy@experian.nl", category: "Credit Bureaus", note: "AP boete 2.7M (2025) voor onvoldoende vendor disclosure" }, - { name: "Graydon", email: "privacy@graydon.nl", category: "Credit Bureaus" }, - { name: "Creditsafe", email: "privacy@creditsafe.com", category: "Credit Bureaus" }, - { name: "Focum BV", email: "privacy@focum.nl", category: "Credit Bureaus" }, - { name: "Dun & Bradstreet", email: "privacy@dnb.com", category: "Credit Bureaus" }, - { name: "Bisnode (Dun & Bradstreet)", email: "privacy@bisnode.nl", category: "Credit Bureaus" }, - - // === AD-TECH & TRACKING === - { name: "Google (Ads/Analytics)", email: "privacy@google.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 100% van geteste NL nieuwssites. Bron: Onderzoek Volkskrant & Telegraaf (Medium)" }, - { name: "Criteo", email: "privacy@criteo.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, - { name: "Index Exchange", email: "privacy@indexexchange.com", category: "Ad-Tech & Tracking", note: "Aanwezig op 80% van geteste NL nieuwssites" }, - { - name: "Xandr (Microsoft Advertising)", - email: "FORM_REQUIRED", - formUrl: "https://account.microsoft.com/privacy/privacy-request-signedout", - category: "Ad-Tech & Tracking", - note: "E-mail privacy@microsoft.com bouncet; dit adres is niet ingericht voor privacyverzoeken. Gebruik het Microsoft privacy formulier (vereist Microsoft-account). 0% GDPR response rate (noyb 2024).", - isForm: true - }, - { - name: "Meta (Facebook/Instagram)", - email: "FORM_REQUIRED", - formUrl: "https://www.facebook.com/help/contact/540977946302970", - category: "Ad-Tech & Tracking", - note: "Email werkt niet meer sinds maart 2026. Verplicht formulier (dark pattern).", - isForm: true - }, - { name: "Outbrain", email: "privacy@outbrain.com", category: "Ad-Tech & Tracking" }, - { name: "Taboola", email: "privacy@taboola.com", category: "Ad-Tech & Tracking" }, - { name: "Magnite (Rubicon)", email: "privacy@magnite.com", category: "Ad-Tech & Tracking" }, - { name: "PubMatic", email: "privacy@pubmatic.com", category: "Ad-Tech & Tracking" }, - { name: "OpenX", email: "privacy@openx.com", category: "Ad-Tech & Tracking" }, - { name: "LinkedIn Marketing", email: "privacy@linkedin.com", category: "Ad-Tech & Tracking" }, - { name: "TikTok", email: "privacy@tiktok.com", category: "Ad-Tech & Tracking" }, - { name: "Snap Inc. (Snapchat)", email: "privacy@snap.com", category: "Ad-Tech & Tracking" }, - { name: "Twitter / X Corp", email: "privacy@twitter.com", category: "Ad-Tech & Tracking" }, - { - name: "Pinterest", - email: "FORM_REQUIRED", - formUrl: "https://help.pinterest.com/nl/contact?current_page=about_you_page&personal_data=personal_data_adjust#no-back", - category: "Ad-Tech & Tracking", - note: "E-mail privacy@pinterest.com bouncet; dit adres is niet ingericht voor privacyverzoeken. Gebruik het contactformulier.", - isForm: true - }, - { name: "Amazon Ads", email: "privacy@amazon.com", category: "Ad-Tech & Tracking" }, - { name: "AppNexus (Xandr)", email: "privacy@xandr.com", category: "Ad-Tech & Tracking" }, - { name: "AdForm", email: "privacy@adform.com", category: "Ad-Tech & Tracking" }, - { name: "Sizmek (Amazon)", email: "privacy@sizmek.com", category: "Ad-Tech & Tracking" }, - { name: "The Trade Desk", email: "privacy@thetradedesk.com", category: "Ad-Tech & Tracking" }, - { name: "MediaMath", email: "privacy@mediamath.com", category: "Ad-Tech & Tracking" }, - - // === MEDIA & PUBLISHERS === - { - name: "DPG Media (NU.nl, AD.nl, Qmusic)", - email: "FORM_REQUIRED", - formUrl: "https://privacy.dpgmedia.nl/nl/privacy-rights", - category: "Media & Publishers", - note: "E-mail privacy@dpgmedia.nl bouncet; dit adres is niet ingericht voor privacyverzoeken. Gebruik het DPG Media formulier voor inzage, correctie, verwijdering en bezwaar. 104 van 121 partners niet genoemd in cookie banner.", - isForm: true - }, - { name: "RTL Nederland", email: "privacy@rtl.nl", category: "Media & Publishers" }, - { name: "Sanoma Media", email: "privacy@sanoma.com", category: "Media & Publishers" }, - { name: "NPO / NOS", email: "privacy@npo.nl", category: "Media & Publishers", note: "Pre-consent tracking gedetecteerd (cookies voor banner)" }, - { name: "Mediahuis (Telegraaf, NHD)", email: "privacy@mediahuis.nl", category: "Media & Publishers" }, - { name: "Talpa Network", email: "privacy@talpanetwork.com", category: "Media & Publishers" }, - { name: "Wayback Machine / Internet Archive", email: "info@archive.org", category: "Media & Publishers" }, - - // === TELECOM === - { name: "KPN", email: "privacy@kpn.com", category: "Telecom" }, - { name: "VodafoneZiggo", email: "privacy@vodafoneziggo.nl", category: "Telecom" }, - { name: "T-Mobile / Odido", email: "dpo@odido.nl", category: "Telecom", note: "Data lek januari 2026 (mogelijk betrokken)" }, - { name: "Tele2", email: "privacy@tele2.nl", category: "Telecom" }, - { name: "Youfone", email: "privacy@youfone.nl", category: "Telecom" }, - { name: "Simyo", email: "privacy@simyo.nl", category: "Telecom" }, - { name: "Lebara", email: "privacy@lebara.nl", category: "Telecom" }, - - // === RETAIL & E-COMMERCE === - { name: "Kruidvat Loyalty", email: "vragen@klantenservice.kruidvat.nl", category: "Retail & E-Commerce", note: "AP boete 600k voor cookie wall" }, - { name: "Albert Heijn Bonus", email: "dpo@aholddelhaize.com", category: "Retail & E-Commerce" }, - { - name: "Bol.com", - email: "FORM_REQUIRED", - category: "Retail & E-Commerce", - note: "E-mail privacy@bol.com bouncet; dit adres is niet ingericht voor privacyverzoeken. Verzoeken verlopen alleen via de ingelogde account-omgeving; geen publiek e-mail of formulier beschikbaar. Gegevens zijn 7 dagen inzichtelijk en worden daarna verwijderd. Best practice: 100% vendor disclosure (13/13).", - isForm: true, - loginOnly: true - }, - { name: "Coolblue", email: "privacy@coolblue.nl", category: "Retail & E-Commerce", note: "AP boete 40k voor pre-consent tracking" }, - { name: "Wehkamp", email: "privacy@wehkamp.nl", category: "Retail & E-Commerce" }, - { name: "Zalando", email: "mijngegevens@zalando.nl", category: "Retail & E-Commerce" }, - { name: "HEMA", email: "hemaklantenservice@hema.nl", category: "Retail & E-Commerce" }, - { name: "Action", email: "privacy@action.nl", category: "Retail & E-Commerce" }, - { name: "MediaMarkt", email: "privacy@mediamarkt.nl", category: "Retail & E-Commerce" }, - { name: "Jumbo Supermarkten", email: "privacy@jumbo.com", category: "Retail & E-Commerce" }, - - // === ANALYTICS & DATA PLATFORMS === - { - name: "SmartOcto", - email: "dpo@smartocto.com", - category: "Analytics", - note: "DPO verified from official privacy policy. NL-based, GDPR compliant." - }, - { name: "Content Insights", email: "privacy@contentinsights.com", category: "Analytics" }, - { name: "Piano Analytics", email: "privacy@piano.io", category: "Analytics" }, - { name: "Comscore", email: "privacy@comscore.com", category: "Analytics" }, - { name: "Nielsen", email: "privacy@nielsen.com", category: "Analytics" }, - { name: "Chartbeat", email: "privacy@chartbeat.com", category: "Analytics" }, - - // === MARKETING CLOUDS === - { name: "Salesforce Marketing Cloud", email: "privacy@salesforce.com", category: "Marketing" }, - { name: "Adobe Marketing Cloud", email: "privacy@adobe.com", category: "Marketing" }, - { name: "Oracle Marketing Cloud", email: "privacy@oracle.com", category: "Marketing" }, - { name: "HubSpot", email: "privacy@hubspot.com", category: "Marketing" }, - { name: "Mailchimp", email: "privacy@mailchimp.com", category: "Marketing" } -]; - -// Populate the with optgroups --- +const companySelect = document.getElementById('company'); +const categories = {}; + +brokers.forEach(b => { + if (!categories[b.category]) categories[b.category] = []; + categories[b.category].push(b); +}); + +Object.keys(categories).sort().forEach(cat => { + const group = document.createElement('optgroup'); + group.label = `${cat} (${categories[cat].length})`; + categories[cat].forEach(b => { + const opt = document.createElement('option'); + opt.value = b.name; + opt.textContent = b.name; + group.appendChild(opt); + }); + companySelect.appendChild(group); +}); + +const otherOpt = document.createElement('option'); +otherOpt.value = 'other'; +otherOpt.textContent = 'Other company (enter manually)'; +companySelect.appendChild(otherOpt); + +// Update broker count badge +document.getElementById('broker-count').textContent = `${brokers.length} European data brokers available`; + +// --- Company select: toggle "other" input + per-company notice --- +companySelect.addEventListener('change', () => { + document.getElementById('other-company-group').classList.toggle('d-none', companySelect.value !== 'other'); + + const selected = brokers.find(b => b.name === companySelect.value); + const banner = document.getElementById('update-banner'); + const text = document.getElementById('update-text'); + + if (selected && (selected.note || selected.isForm)) { + let msg = selected.note || ''; + if (selected.isForm) { + msg = `${escapeHtml(selected.name)} requires a web form (no email). ${msg}`; + } + text.innerHTML = msg; + banner.classList.remove('d-none'); + } else { + banner.classList.add('d-none'); + } +}); + +// --- Main generator --- +function generateMail() { + const name = document.getElementById('fullname').value.trim(); + const email = document.getElementById('email').value.trim(); + const company = companySelect.value; + const extra = document.getElementById('extra-company').value.trim(); + const type = document.getElementById('type').value; + const resultEl = document.getElementById('result'); + + if (!name || !email || !company) { + alert('Please fill in your name, email and select a company.'); + return; + } + + let recipient = ''; + let companyName = company; + let isForm = false; + let formUrl = ''; + let loginOnly = false; + + if (company === 'other') { + if (!extra) { + alert('Please enter the company name (and preferably its privacy email).'); + return; + } + // Split on first dash separator to allow hyphens in company names + const separators = [' | ', ' β€” ', ' – ', ' - ']; + let sepIdx = -1, sepLen = 0; + for (const sep of separators) { + const i = extra.indexOf(sep); + if (i !== -1 && (sepIdx === -1 || i < sepIdx)) { sepIdx = i; sepLen = sep.length; } + } + if (sepIdx !== -1) { + companyName = extra.slice(0, sepIdx).trim(); + recipient = extra.slice(sepIdx + sepLen).trim() || `privacy@${companyName.toLowerCase().replace(/[^a-z0-9]/g, '')}.com`; + } else { + companyName = extra; + recipient = `privacy@${companyName.toLowerCase().replace(/[^a-z0-9]/g, '')}.com`; + } + } else { + const sel = brokers.find(b => b.name === company); + if (sel) { + isForm = !!sel.isForm; + formUrl = sel.formUrl || ''; + loginOnly = !!sel.loginOnly; + if (!isForm) recipient = sel.email; + } else { + recipient = `privacy@${company.toLowerCase().replace(/[^a-z0-9]/g, '')}.com`; + } + } + + const subjects = emailLang === 'en' ? { + objection: 'Objection to personal data processing (GDPR Art. 21)', + erase: 'Request for erasure of personal data (GDPR Art. 17)', + access: 'Request for access to personal data (GDPR Art. 15)', + both: 'Objection + erasure of personal data (GDPR Art. 21 & 17)' + } : { + objection: 'Bezwaar tegen verwerking persoonsgegevens (AVG Art. 21)', + erase: 'Verzoek tot wissen persoonsgegevens (AVG Art. 17)', + access: 'Verzoek tot inzage persoonsgegevens (AVG Art. 15)', + both: 'Bezwaar + wissen persoonsgegevens (AVG Art. 21 & 17)' + }; + const subject = subjects[type]; + + const objLine = (type === 'objection' || type === 'both'); + const eraseLine = (type === 'erase' || type === 'both'); + const accessLine = type === 'access'; + + const body = emailLang === 'en' + ? `Dear Sir/Madam, + +My name is ${name} and my email address is ${email}. + +I hereby formally exercise my rights under the GDPR: + +${objLine ? `- Objection to the processing of my personal data for marketing, profiling, tracking, etc. (Art. 21 GDPR). I request that ${companyName} ceases all such processing.\n` : ''}${eraseLine ? `- Request for erasure of all my personal data (Art. 17 GDPR, right to be forgotten).\n` : ''}${accessLine ? `- Request for access to all personal data you process about me (Art. 15 GDPR), including a copy.\n` : ''} +Please confirm within 1 month and provide proof of action. In case of refusal: a reasoned explanation. + +Kind regards, +${name}` + : `Geachte heer/mevrouw, + +Mijn naam is ${name} en mijn e-mailadres is ${email}. + +Ik oefen hierbij formeel mijn rechten uit onder de AVG/GDPR: + +${objLine ? `- Bezwaar tegen verwerking van mijn persoonsgegevens voor marketing, profiling, tracking e.d. (Art. 21 AVG). Ik verzoek ${companyName} alle verdere verwerking te staken.\n` : ''}${eraseLine ? `- Verzoek tot wissen van al mijn persoonsgegevens (Art. 17 AVG, recht om vergeten te worden).\n` : ''}${accessLine ? `- Verzoek tot inzage in alle persoonsgegevens die u van mij verwerkt (Art. 15 AVG), inclusief een kopie.\n` : ''} +Graag ontvang ik binnen 1 maand bevestiging en bewijs van actie. Bij weigering: een gemotiveerde uitleg. + +Met vriendelijke groet, +${name}`; + + lastGeneratedBody = body; + + // Case 1: company only accepts logged-in requests + if (loginOnly) { + resultEl.innerHTML = ` +
    +

    No public contact channel

    +

    + ${escapeHtml(companyName)} has no public email or form for GDPR requests. + Requests can only be made through the logged-in account area on their website. +

    +
    `; + return; + } + + // Case 2: form required instead of email + if (isForm) { + const renderFormResult = (copied) => { + resultEl.innerHTML = ` +
    +

    + ${copied ? 'Form required β€” text copied to clipboard' : 'Form required'} +

    + ${copied + ? `

    + ${escapeHtml(companyName)} no longer accepts email for GDPR requests. + Use their contact form. The request text has been copied to your clipboard. +

    ` + : `

    + Copy the text below and paste it into the form. +

    ` + } +
    
    +          
    +          ${copied
    +            ? `

    + Replacing email with forms is a friction tactic that reduces GDPR opt-outs. + Consider reporting this to your national DPA. +

    ` + : '' + } +
    `; + document.getElementById('form-body-pre').textContent = body; + }; + + navigator.clipboard.writeText(body) + .then(() => renderFormResult(true)) + .catch(() => renderFormResult(false)); + return; + } + + // Case 3: normal email + const mailto = `mailto:${recipient}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`; + + resultEl.innerHTML = ` +
    +

    Ready to send

    +

    To: ${escapeHtml(recipient)}

    +

    Subject: ${escapeHtml(subject)}

    +
    
    +      
    + + Open in email client + + +
    +

    + If "Open in email client" doesn't work, use "Copy text" and paste into your mail app. +

    +
    `; + document.getElementById('email-body-pre').textContent = body; +} diff --git a/static/js/theme.js b/static/js/theme.js new file mode 100644 index 0000000..55c528a --- /dev/null +++ b/static/js/theme.js @@ -0,0 +1,41 @@ +'use strict'; +(function () { + const KEY = 'optout-theme'; + const root = document.documentElement; + + function applyTheme(theme) { + root.setAttribute('data-bs-theme', theme); + const btn = document.getElementById('theme-toggle'); + if (btn) { + btn.innerHTML = theme === 'dark' + ? '' + : ''; + btn.title = theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'; + } + } + + function saved() { + return localStorage.getItem(KEY); + } + + function preferred() { + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + } + + const initial = saved() || preferred(); + + // Apply immediately (before render) to prevent flash + applyTheme(initial); + + // Re-apply after DOM ready to sync button icon/title + document.addEventListener('DOMContentLoaded', function () { + applyTheme(root.getAttribute('data-bs-theme') || initial); + }); + + window.toggleTheme = function () { + const current = root.getAttribute('data-bs-theme') || 'light'; + const next = current === 'dark' ? 'light' : 'dark'; + localStorage.setItem(KEY, next); + applyTheme(next); + }; +})(); diff --git a/style.css b/style.css deleted file mode 100644 index b9d537a..0000000 --- a/style.css +++ /dev/null @@ -1,125 +0,0 @@ -body { - font-family: system-ui, sans-serif; - max-width: 900px; - margin: 0 auto; - padding: 1.5rem; - line-height: 1.6; - color: #333; - background: #f9f9f9; -} - -h1, h2, h3 { color: #d32f2f; } - -.disclaimer { - background: #fff3cd; - border-left: 5px solid #ffc107; - padding: 1.2rem; - margin: 1.5rem 0; - color: #856404; -} - -.warning { - background: #ffebee; - border-left: 5px solid #f44336; - padding: 1rem; - margin: 1rem 0; - color: #c62828; -} - -.info { - background: #e3f2fd; - border-left: 5px solid #2196f3; - padding: 1rem; - margin: 1rem 0; - color: #1565c0; -} - -form { - background: white; - padding: 1.5rem; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0,0,0,0.1); -} - -label { - display: block; - margin: 1rem 0 0.4rem; - font-weight: bold; -} - -input, select, textarea { - width: 100%; - padding: 0.6rem; - border: 1px solid #ccc; - border-radius: 4px; - box-sizing: border-box; -} - -button { - background: #d32f2f; - color: white; - border: none; - padding: 0.9rem 1.5rem; - font-size: 1.1rem; - border-radius: 6px; - cursor: pointer; - margin-top: 1rem; -} - -button:hover { background: #b71c1c; } - -button.secondary { - background: #757575; - margin-left: 0.5rem; -} - -button.secondary:hover { background: #616161; } - -button.lang { - background: #1565c0; - margin-left: 0; -} - -button.lang:hover { background: #0d47a1; } - -#result:empty { - display: none; -} - -#result { - margin-top: 2rem; - padding: 1rem; - background: #e8f5e9; - border-left: 5px solid #4caf50; -} - -footer { - margin-top: 3rem; - text-align: center; - font-size: 0.9rem; - color: #666; - border-top: 1px solid #ddd; - padding-top: 2rem; -} - -select optgroup { - font-weight: bold; - color: #333; -} - -.broker-count { - background: #e3f2fd; - padding: 0.8rem 1rem; - border-radius: 6px; - margin: 1.5rem 0; - text-align: center; - font-weight: bold; -} - -.update-banner { - background: #fff3cd; - border: 2px solid #ffc107; - padding: 1rem; - border-radius: 6px; - margin: 1rem 0; -} From fd1a5088f4d60db1cbdc8daf1bb2f7bcfcafa083 Mon Sep 17 00:00:00 2001 From: Sten Tijhuis <102481635+Stensel8@users.noreply.github.com> Date: Fri, 10 Apr 2026 19:26:29 +0200 Subject: [PATCH 17/24] feat: Match layout and styles with mickbeer website for improved UI/UX --- .github/workflows/hugo.yml | 2 +- CHANGELOG.md | 103 +++++------ CONTRIBUTING.md | 7 +- README.md | 21 ++- content/_index.md | 3 +- content/nl/_index.md | 3 +- hugo.toml | 34 ++-- i18n/en.yaml | 34 ++-- i18n/nl.yaml | 34 ++-- layouts/_default/baseof.html | 330 ++++++++++++++++++++++++++++++----- layouts/index.html | 96 +++++----- preview.avif | Bin 0 -> 154877 bytes preview.png | Bin 0 -> 719010 bytes static/CNAME | 1 - static/js/script.js | 175 ++++++++++++++----- 15 files changed, 577 insertions(+), 266 deletions(-) create mode 100644 preview.avif create mode 100644 preview.png delete mode 100644 static/CNAME diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index e6dca79..0f42333 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -2,7 +2,7 @@ name: Deploy Hugo to GitHub Pages on: push: - branches: [dev] + branches: [main] workflow_dispatch: permissions: diff --git a/CHANGELOG.md b/CHANGELOG.md index e56d48e..6c117ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,92 +8,67 @@ en commit-berichten volgen grotendeels de stijl van [Conventional Commits](https --- -## [1.2.1] - 2026-04-06 - -### Added -- Wayback Machine / Internet Archive toegevoegd als data broker (info@archive.org) -- Nederlands / Engels taalschakelaar bij de e-mail generatieknop +## [2.0.1] - 2026-04-10 ### Changed -- Broker-teller gewijzigd van "Nederlandse" naar "Europese" data brokers -- Kleine verbeteringen aan teksten -- Ongebruikte code verwijderd +- visuele stijl gelijkgetrokken met [mickbeer.com](https://mickbeer.com) +- contrast en kleurproblemen opgelost: donate-knop, dark mode kleurtokens, taalschakelaar separator +- footer ingekort: toont nu alleen versienummer en datum --- -## [1.2.0] - 2026-03-31 - -### Added -- bronlink voor Google in de update-banner (onderzoek Volkskrant & Telegraaf) +## [2.0.0] - 2026-04-10 ### Changed -- code uitgesplitst in aparte bestanden: script.js, style.css -- alle code-identifiers omgezet naar Engels met consistente conventies - (camelCase voor JS, kebab-case voor HTML IDs en CSS) -- interne form-values omgezet naar Engels (bezwaar/wissen/inzage/beide vervallen) -- donatie-knop verplaatst naar footer, minder prominent -- UI rustigere kleuren, geen emoji -- documentatie herschreven: README, CONTRIBUTING, DEPLOYMENT en CHANGELOG ingekort - en opgeschoond; veel herhaalde, lange en overbodige tekst verwijderd -- REPO-OVERVIEW.md verwijderd +- volledige herbouw als Hugo statische site (van losse index.html naar Hugo-template systeem) +- meertalige ondersteuning: Nederlands (standaard) en Engels via Hugo i18n +- nieuwe visuele stijl geïnspireerd op [mickbeer.com](https://mickbeer.com): crème achtergrond, Playfair Display serif headings, amber accenten +- GitHub Pages URL: `https://apolloccrypt.github.io/nl-data-optout/` +- footer uitgebreid: changelog-link, versienummer, donatie-knop, LinkedIn en Medium links +- donatie-knop (Buy me a coffee) in footer van elke pagina +- GitHub Actions workflow bijgewerkt voor Hugo deploy op push naar `main` +- "Over dit project" sectie uitgebreid met toelichting over reikwijdte: NL-markt + buitenlandse partijen actief in Nederland +- alle UI-strings in script.js tweetalig (Nederlands/Engels) via `window.SITE_LANG` ### Fixed -- Microsoft: privacy@microsoft.com bouncet, vervangen door formulier ([#1](https://github.com/Apolloccrypt/nl-data-optout/issues/1)) -- Pinterest: privacy@pinterest.com bouncet, vervangen door formulier ([#2](https://github.com/Apolloccrypt/nl-data-optout/issues/2)) -- DPG Media: privacy@dpgmedia.nl bouncet, vervangen door privacy-rights formulier ([#3](https://github.com/Apolloccrypt/nl-data-optout/issues/3)) -- Bol.com: privacy@bol.com bouncet, ingesteld als login-only ([#4](https://github.com/Apolloccrypt/nl-data-optout/issues/4)) -- broken Medium URLs vervangen door https://medium.com/@mick.ronan.beer -- LinkedIn URL gecorrigeerd naar https://www.linkedin.com/in/mick-beer/ -- lege result-div werd getoond als groene balk (#result:empty hidden) -- CHANGELOG liep tot v1.1.0 terwijl de site al v1.1.1 toonde -- links naar CHANGELOG.md en LICENSE in footer zijn nu relatief +- broker-teller toont correct "Nederlandse data brokers" --- -## [1.1.1] - 2026-03-22 +## [1.2.1] - 2026-04-06 -### Fixed -- Xandr: privacy@xandr.com bouncet, vervangen door Microsoft privacy formulier -- SmartOcto: privacy@smartocto.com bouncet, vervangen door dpo@smartocto.com -- ontbrekende komma's in de brokers array veroorzaakten parse-fouten -- Xandr en SmartOcto misten een category-veld -- diverse contactadressen bijgewerkt +- Wayback Machine / Internet Archive toegevoegd als data broker +- NL/EN taalschakelaar bij e-mail generatieknop +- Broker-teller gecorrigeerd naar "Nederlandse data brokers" + +--- -### Added -- notitie bij Xandr: 0% GDPR response rate (noyb 2024) +## [1.2.0] - 2026-03-31 + +- Code uitgesplitst in script.js en style.css +- Identifiers omgezet naar Engels (camelCase JS, kebab-case HTML/CSS) +- Microsoft ([#1](https://github.com/Apolloccrypt/nl-data-optout/issues/1)), Pinterest ([#2](https://github.com/Apolloccrypt/nl-data-optout/issues/2)), DPG Media ([#3](https://github.com/Apolloccrypt/nl-data-optout/issues/3)) omgezet naar formulier; Bol.com ([#4](https://github.com/Apolloccrypt/nl-data-optout/issues/4)) login-only +- Documentatie (README, CONTRIBUTING, DEPLOYMENT, CHANGELOG) ingekort --- -## [1.1.0] - 2026-03-21 +## [1.1.1] - 2026-03-22 -### Added -- detectie van bedrijven die geen email meer accepteren, met formulier-instructies -- waarschuwingsbanner voor bedrijven met speciale instructies -- 60+ brokers (was 25) -- categorieteller in de dropdown -- dark pattern waarschuwing bij formulier-vereiste bedrijven -- kopieer-naar-clipboard knop -- GitHub Issue templates (broken contact, feature request) +- Xandr en SmartOcto contactadressen gecorrigeerd (bouncende e-mails) +- Xandr: 0% GDPR response rate toegevoegd (noyb 2024) +- Parse-fouten in brokers array opgelost -### Changed -- broker objectstructuur uitgebreid met note, isForm en formUrl velden -- email template opmaak verbeterd -- footer met versienummer en changelog link +--- -### Fixed -- Meta: datarequests@support.facebook.com vervangen door formulier -- JavaScript escaping voor backticks en dollar signs in clipboard copy -- weergave op kleine schermen +## [1.1.0] - 2026-03-21 + +- 60+ brokers (was 25), verdeeld in categorieen met teller +- Formulierdetectie met waarschuwingsbanner en dark pattern notitie +- Kopieer-naar-klembord knop +- Meta omgezet naar formulier --- ## [1.0.0] - 2026-03-20 -### Added -- eerste release met 25 Nederlandse data brokers -- GDPR Art. 21 (bezwaar), Art. 17 (wissen), Art. 15 (inzage) -- categorieen: Credit Bureaus, Ad-Tech, Media, Telecom, Retail -- "ander bedrijf" optie voor handmatige invoer -- alles lokaal, geen server -- MIT licentie -- GitHub Pages hosting +- Eerste release: 25 NL data brokers, Art. 15/17/21, lokaal, MIT diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a593dd..0793da8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,11 +14,10 @@ verwerkt van Nederlandse burgers, en een publiek privacycontact heeft. ## Code bijdragen -HTML, CSS en vanilla JavaScript. Geen frameworks, geen build stap. -Fork de repo, maak je wijzigingen, test lokaal door index.html te openen in de browser, -en open een pull request. Voeg een regel toe aan CHANGELOG.md. +De site gebruikt [Hugo](https://gohugo.io/). Fork de repo, installeer Hugo en run +`hugo server` om lokaal te testen. Open een pull request en voeg een regel toe aan CHANGELOG.md. -Geen externe dependencies, geen server-side code, geen tracking. +Geen server-side code, geen tracking. ## Vragen diff --git a/README.md b/README.md index 27c8f82..8792ffa 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,18 @@ Tool voor het versturen van GDPR-verzoeken naar Nederlandse data brokers. -Live: https://apolloccrypt.github.io/nl-data-optout/ +**Live: [apolloccrypt.github.io/nl-data-optout](https://apolloccrypt.github.io/nl-data-optout/)** + +[![Preview](preview.avif)](https://apolloccrypt.github.io/nl-data-optout/) ## Gebruik 1. Vul naam en emailadres in 2. Selecteer een bedrijf 3. Kies het type verzoek (bezwaar, wissen, inzage, of beide) -4. Klik "Genereer bezwaarmail" +4. Klik "Genereer e-mail" -Lokaal: clone de repo en open index.html in je browser. Geen server nodig. +Lokaal: clone de repo, installeer Hugo en voer `hugo server` uit. Geen externe server nodig. ## Achtergrond @@ -21,12 +23,21 @@ Onderzoek: https://medium.com/@mick.ronan.beer ## Ondersteunde bedrijven -60+ bedrijven verdeeld over credit bureaus, ad-tech, media, telecom, retail, analytics en marketing clouds. Zie script.js voor de volledige lijst. Er is ook een "ander bedrijf" optie voor handmatige invoer. +60+ bedrijven verdeeld over credit bureaus, ad-tech, media, telecom, retail, analytics en marketing clouds. Zie `static/js/script.js` voor de volledige lijst. Er is ook een "ander bedrijf" optie voor handmatige invoer. ## Privacy Alles draait lokaal. Geen server, geen opslag, geen tracking. De tool genereert alleen tekst, jij verstuurt de mail zelf. +## v2.0.0 — Hugo rebuild + +Vanaf v2.0.0 is de site gebouwd met [Hugo](https://gohugo.io/): + +- Meertalig (NL standaard, EN beschikbaar) +- Nieuw visueel ontwerp geïnspireerd op [mickbeer.com](https://mickbeer.com) +- GitHub Actions deploy op push naar `main` +- Uitgebreide footer met changelog, donatie en contact links + ## Bijdragen Zie [CONTRIBUTING.md](CONTRIBUTING.md). Verouderd contactadres of bug? Open een [issue](https://github.com/Apolloccrypt/nl-data-optout/issues). @@ -37,4 +48,4 @@ MIT. Zie [LICENSE](LICENSE). ## Contact -Mick Beer — https://www.linkedin.com/in/mick-beer/ +Mick Beer — https://mickbeer.com — https://www.linkedin.com/in/mick-beer/ diff --git a/content/_index.md b/content/_index.md index 7352e3e..3a4481b 100644 --- a/content/_index.md +++ b/content/_index.md @@ -1,4 +1,3 @@ --- -title: "EU Data Broker Opt-Out Tool" -description: "Generate GDPR requests to 60+ European data brokers in minutes. Runs 100% locally — no data stored." +title: "NL Data Brokers Opt-Out Tool" --- diff --git a/content/nl/_index.md b/content/nl/_index.md index 6a6837a..3a4481b 100644 --- a/content/nl/_index.md +++ b/content/nl/_index.md @@ -1,4 +1,3 @@ --- -title: "EU Data Broker Opt-Out Tool" -description: "Genereer GDPR-verzoeken naar 60+ Europese data brokers in minuten. 100% lokaal — geen data opgeslagen." +title: "NL Data Brokers Opt-Out Tool" --- diff --git a/hugo.toml b/hugo.toml index f0d79a9..70ca3bc 100644 --- a/hugo.toml +++ b/hugo.toml @@ -1,26 +1,30 @@ -baseURL = "https://data-optout.stensel.nl/" -defaultContentLanguage = "en" +baseURL = "https://apolloccrypt.github.io/nl-data-optout/" +defaultContentLanguage = "nl" defaultContentLanguageInSubdir = false enableRobotsTXT = true disableKinds = ["taxonomy", "term"] [languages] - [languages.en] - languageCode = "en" - languageName = "English" - title = "OptOut EU" - weight = 1 - [languages.en.params] - description = "Generate GDPR requests to 60+ European data brokers in minutes. Runs 100% locally — no data stored." - [languages.nl] languageCode = "nl" languageName = "Nederlands" - title = "OptOut EU" - weight = 2 + title = "NL Data Opt-Out" + weight = 1 [languages.nl.params] - description = "Genereer GDPR-verzoeken naar 60+ Europese data brokers in minuten. 100% lokaal — geen data opgeslagen." + description = "Genereer gratis GDPR-verzoeken naar 60+ Nederlandse data brokers. 100% lokaal — geen data opgeslagen." + + [languages.en] + languageCode = "en" + languageName = "English" + title = "NL Data Opt-Out" + weight = 2 + [languages.en.params] + description = "Generate free GDPR requests to 60+ Dutch data brokers. Runs 100% locally — no data stored." [params] - github = "https://github.com/Stensel8/data-optout" - version = "2.0.0" + github = "https://github.com/Apolloccrypt/nl-data-optout" + version = "2.0.1" + author = "Mick Beer" + authorUrl = "https://mickbeer.com" + linkedin = "https://www.linkedin.com/in/mick-beer/" + donate = "https://www.buymeacoffee.com/mickbeer" diff --git a/i18n/en.yaml b/i18n/en.yaml index e6ae23f..5906414 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -1,9 +1,10 @@ -disclaimer_short: "Not legal advice. This tool helps you exercise GDPR rights (Art. 15, 17 & 21). When in doubt, consult your" +disclaimer_short: "Not legal advice. This tool helps you exercise your GDPR rights (Art. 15, 17 and 21). When in doubt, consult your" disclaimer_dpa: "national Data Protection Authority" disclaimer_full_link: "Full disclaimer" -hero_title: "EU Data Broker\nOpt-Out Tool" -hero_description: "Generate GDPR objection, erasure or access emails to European data brokers, ad-tech, telecom, retail and media companies. Everything runs locally in your browser. No data stored." +hero_title: "NL Data Brokers
    Opt-Out Tool" +hero_description: "Generate free GDPR requests to Dutch data brokers, ad-tech, telecom, retail and media companies. Everything runs locally in your browser. No data stored." +hero_broker_label: "Dutch data brokers" form_title: "Generate your request" label_name: "Full name" @@ -20,31 +21,31 @@ btn_generate: "Generate email" type_objection: "Object to processing (Art. 21)" type_erase: "Erasure of data (Art. 17)" type_access: "Access to my data (Art. 15)" -type_both: "Object + erasure (Art. 21 & 17)" +type_both: "Object and erasure (Art. 21 and 17)" rights_title: "Your GDPR rights" rights_official_text: "Official text" rights_ap_page: "NL authority" rights_eurlex: "EUR-Lex full regulation" -art15_title: "Art. 15 β€” Right of access" -art15_text: "You have the right to know whether a company processes your personal data and, if so, to receive a complete copy of that data." +art15_title: "Art. 15: Right of access" +art15_text: "You have the right to know whether a company processes your personal data, and if so, to receive a complete copy of that data." art15_url_info: "https://gdpr-info.eu/art-15-gdpr/" art15_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-op-inzage" -art17_title: "Art. 17 β€” Right to erasure" -art17_text: "You have the right to request deletion of all personal data a company holds about you, without undue delay. Also known as the \"right to be forgotten\"." +art17_title: "Art. 17: Right to erasure" +art17_text: "You have the right to request that a company deletes your personal data without undue delay." art17_url_info: "https://gdpr-info.eu/art-17-gdpr/" art17_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-op-vergetelheid" -art21_title: "Art. 21 β€” Right to object" -art21_text: "You have the right to object at any time to the processing of your personal data for marketing, profiling or tracking. The controller must stop unless it can demonstrate compelling legitimate grounds." +art21_title: "Art. 21: Right to object" +art21_text: "You have the right to object to the processing of your personal data for marketing, profiling or tracking. The company must stop, unless it can demonstrate compelling legitimate grounds." art21_url_info: "https://gdpr-info.eu/art-21-gdpr/" art21_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-van-bezwaar" disclaimer_title: "Full disclaimer" disclaimer_1: "No legal advice. Tool by an independent researcher, not a lawyer." -disclaimer_2: "No guarantees. Companies do not always respond. If refused, file a complaint with your national DPA." +disclaimer_2: "No guarantees. Companies do not always respond. If refused, you can file a complaint with your national DPA." disclaimer_3: "Personal responsibility. You decide how to use this tool and its content." disclaimer_4: "Privacy. 100% local processing. No data storage, no server calls, no analytics." disclaimer_5: "Legal use only. Only for your own legitimate GDPR requests." @@ -53,12 +54,11 @@ disclaimer_issues: "GitHub Issues" disclaimer_accept: "By generating an email you accept these terms." about_title: "About this project" -about_intro: "This tool collects and analyses public data to show how European companies handle personal data." +about_intro: "This project maps how Dutch companies and international parties active in the Netherlands handle personal data." +about_scope_title: "Scope" +about_scope: "The tool focuses on the Dutch market and the GDPR as enforced by the Dutch Data Protection Authority (AP). The list also includes foreign companies (such as Google, Meta and Amazon) that process data of people in the Netherlands. If you live in the Netherlands, you fall under the Dutch AP, regardless of where the company is based. This means you can send a valid GDPR request to foreign parties as well." about_goals_title: "Goals" about_goal1: "Provide transparency about cookie tracking, dark patterns and unnecessary data storage" -about_goal2: "Support legislative efforts for stronger data protection (e.g. Check Don't Store)" +about_goal2: "Support legislative efforts for stronger data protection, including Check Don't Store (2026Z04148)" about_goal3: "Give citizens practical tools to exercise their GDPR rights" -about_footer: "Everything is based on reproducible technical research. No data is retained or distributed after analysis." - -footer_text: "OptOut EU Β· Open source Β· MIT License" -footer_legal: "Not legal advice Β· All processing is local" +about_footer: "The project is free, independent and based on publicly reproducible research." diff --git a/i18n/nl.yaml b/i18n/nl.yaml index 75fc7ab..2490cd3 100644 --- a/i18n/nl.yaml +++ b/i18n/nl.yaml @@ -1,9 +1,10 @@ -disclaimer_short: "Dit is geen juridisch advies. Deze tool helpt je GDPR-rechten uit te oefenen (Art. 15, 17 & 21). Raadpleeg bij twijfel de" +disclaimer_short: "Dit is geen juridisch advies. Deze tool helpt je AVG-rechten uit te oefenen (Art. 15, 17 en 21). Raadpleeg bij twijfel de" disclaimer_dpa: "Autoriteit Persoonsgegevens" disclaimer_full_link: "Volledige disclaimer" -hero_title: "EU Data Broker\nOpt-Out Tool" -hero_description: "Genereer GDPR-bezwaar-, wis- of inzage-e-mails naar Europese data brokers, ad-tech, telecom, retail en mediabedrijven. Alles draait lokaal in je browser. Geen data opgeslagen." +hero_title: "NL Data Brokers
    Opt-Out Tool" +hero_description: "Genereer gratis GDPR-verzoeken naar Nederlandse data brokers, ad-tech, telecom, retail en mediabedrijven. Alles draait lokaal in je browser. Geen data opgeslagen." +hero_broker_label: "Nederlandse data brokers" form_title: "Genereer je verzoek" label_name: "Volledige naam" @@ -20,31 +21,31 @@ btn_generate: "Genereer e-mail" type_objection: "Bezwaar tegen verwerking (Art. 21)" type_erase: "Wissen van gegevens (Art. 17)" type_access: "Inzage in mijn gegevens (Art. 15)" -type_both: "Bezwaar + wissen (Art. 21 & 17)" +type_both: "Bezwaar en wissen (Art. 21 en 17)" rights_title: "Jouw AVG-rechten" rights_official_text: "OfficiΓ«le tekst" rights_ap_page: "Autoriteit Persoonsgegevens" rights_eurlex: "EUR-Lex volledige verordening" -art15_title: "Art. 15 β€” Recht op inzage" -art15_text: "Je hebt het recht om te weten of een bedrijf jouw persoonsgegevens verwerkt en, zo ja, een volledige kopie van die gegevens te ontvangen." +art15_title: "Art. 15: Recht op inzage" +art15_text: "Je hebt het recht om te weten of een bedrijf jouw persoonsgegevens verwerkt, en zo ja, een volledige kopie van die gegevens te ontvangen." art15_url_info: "https://gdpr-info.eu/art-15-gdpr/" art15_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-op-inzage" -art17_title: "Art. 17 β€” Recht op vergetelheid" -art17_text: "Je hebt het recht te eisen dat een bedrijf al jouw persoonsgegevens zonder onnodig uitstel verwijdert. Ook wel het \"recht om vergeten te worden\" genoemd." +art17_title: "Art. 17: Recht op gegevens verwijderen" +art17_text: "Je hebt het recht te eisen dat een bedrijf jouw persoonsgegevens zonder onnodig uitstel verwijdert." art17_url_info: "https://gdpr-info.eu/art-17-gdpr/" art17_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-op-gegevens-verwijderen" -art21_title: "Art. 21 β€” Recht van bezwaar" -art21_text: "Je hebt het recht om te allen tijde bezwaar te maken tegen de verwerking van jouw persoonsgegevens voor marketing, profilering of tracking. De verwerkingsverantwoordelijke moet stoppen, tenzij hij dwingende gerechtvaardigde gronden kan aantonen." +art21_title: "Art. 21: Recht van bezwaar" +art21_text: "Je hebt het recht om bezwaar te maken tegen de verwerking van jouw persoonsgegevens voor marketing, profilering of tracking. Het bedrijf moet daarmee stoppen, tenzij het dwingende gerechtvaardigde gronden kan aantonen." art21_url_info: "https://gdpr-info.eu/art-21-gdpr/" art21_url_ap: "https://autoriteitpersoonsgegevens.nl/themas/basis-avg/privacyrechten-avg/recht-van-bezwaar" disclaimer_title: "Volledige disclaimer" disclaimer_1: "Geen juridisch advies. Tool van een onafhankelijk onderzoeker, geen advocaat." -disclaimer_2: "Geen garanties. Bedrijven reageren niet altijd. Bij weigering: klacht indienen bij de AP." +disclaimer_2: "Geen garanties. Bedrijven reageren niet altijd. Bij weigering kun je een klacht indienen bij de AP." disclaimer_3: "Eigen verantwoordelijkheid. Jij beslist hoe je deze tool en de inhoud gebruikt." disclaimer_4: "Privacy. 100% lokale verwerking. Geen dataopslag, geen servercalls, geen analytics." disclaimer_5: "Legaal gebruik. Alleen voor eigen legitieme GDPR-verzoeken." @@ -53,12 +54,11 @@ disclaimer_issues: "GitHub Issues" disclaimer_accept: "Door een e-mail te genereren accepteer je deze voorwaarden." about_title: "Over dit project" -about_intro: "Dit project verzamelt en analyseert openbare data om te laten zien hoe Europese bedrijven omgaan met persoonsgegevens." +about_intro: "Dit project brengt in kaart hoe Nederlandse bedrijven en internationale partijen die in Nederland actief zijn omgaan met persoonsgegevens." +about_scope_title: "Reikwijdte" +about_scope: "De tool richt zich op de Nederlandse markt en de AVG zoals gehandhaafd door de Autoriteit Persoonsgegevens. De lijst bevat ook buitenlandse bedrijven (zoals Google, Meta en Amazon) die gegevens verwerken van mensen in Nederland. Als je in Nederland woont, val je onder de Nederlandse AP, ongeacht waar het bedrijf gevestigd is. Je kunt dus ook naar buitenlandse partijen een geldig GDPR-verzoek sturen." about_goals_title: "Doelen" about_goal1: "Transparantie bieden over cookie-tracking, dark patterns en onnodige dataopslag" -about_goal2: "Bewijs leveren voor wetgevingsinitiatieven voor betere gegevensbescherming (bijv. Check Don't Store)" +about_goal2: "Bewijs leveren voor wetgevingsinitiatieven voor betere gegevensbescherming, waaronder Check Don't Store (2026Z04148)" about_goal3: "Burgers praktische tools geven om hun AVG-rechten uit te oefenen" -about_footer: "Alles is gebaseerd op reproduceerbaar technisch onderzoek. Na analyse wordt alles permanent verwijderd." - -footer_text: "OptOut EU Β· Open source Β· MIT Licentie" -footer_legal: "Geen juridisch advies Β· Alle verwerking is lokaal" +about_footer: "Het project is gratis, onafhankelijk en gebaseerd op openbaar reproduceerbaar onderzoek." diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index b4e936f..e85954c 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -1,5 +1,5 @@ - + @@ -8,80 +8,266 @@ {{ range .Translations }} {{ end }} + + + - + {{ block "head" . }}{{ end }} -