<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nevik Schmidt</title>
    <description>The latest articles on DEV Community by Nevik Schmidt (@nevik_schmidt_3635afa2b85).</description>
    <link>https://dev.to/nevik_schmidt_3635afa2b85</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3836189%2Fc7e0f487-1a80-4b7c-b7af-0cedc31ef8c3.png</url>
      <title>DEV Community: Nevik Schmidt</title>
      <link>https://dev.to/nevik_schmidt_3635afa2b85</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nevik_schmidt_3635afa2b85"/>
    <language>en</language>
    <item>
      <title>Google Fonts und DSGVO: Warum du Fonts lokal hosten MUSST</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Fri, 12 Jun 2026 10:54:57 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/google-fonts-und-dsgvo-warum-du-fonts-lokal-hosten-musst-898</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/google-fonts-und-dsgvo-warum-du-fonts-lokal-hosten-musst-898</guid>
      <description>&lt;h2&gt;
  
  
  Das Problem
&lt;/h2&gt;

&lt;p&gt;EuGH 2022: Externe Google Fonts uebertragen IP-Adressen an Google. Das verstoesst gegen die DSGVO.&lt;/p&gt;

&lt;p&gt;Muenchen 2022: EUR 100.000 Geldstrafe fuer einen Websitebetreiber der Google Fonts eingebunden hat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loesung: Fonts lokal hosten
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Schritt 1: Font herunterladen
&lt;/h3&gt;

&lt;p&gt;Von google-webfonts-helper den Font als woff2 herunterladen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Schritt 2: CSS anpassen
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Schritt 3: Dateien hochladen
&lt;/h3&gt;

&lt;p&gt;Die .woff2-Dateien ins statische Verzeichnis laden. Fertig.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pruefen ob deine Website betroffen ist
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;guard.nevki.de&lt;/a&gt; — scannt automatisch nach externen Fonts ohne Consent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fazit&lt;/strong&gt;: Lokale Fonts sind schneller, DSGVO-konform und in 5 Minuten erledigt.&lt;/p&gt;

</description>
      <category>css</category>
      <category>dsgvo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Abmahnung erhalten? So sicherst du deine Website gegen DSGVO-Bussgelder</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Fri, 12 Jun 2026 10:54:56 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/abmahnung-erhalten-so-sicherst-du-deine-website-gegen-dsgvo-bussgelder-3aep</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/abmahnung-erhalten-so-sicherst-du-deine-website-gegen-dsgvo-bussgelder-3aep</guid>
      <description>&lt;h2&gt;
  
  
  Die Realitaet: DSGVO-Abmahnungen sind ein boomendes Geschaefsmodell
&lt;/h2&gt;

&lt;p&gt;Mein Kunde hat EUR 900 gezahlt dafuer dass auf seiner Website das Impressum fehlte. Nichts Dramatisches, nur ein vergessenenes Impressum.&lt;/p&gt;

&lt;p&gt;Das hat mich veranlasst einen automatisierten Scanner zu bauen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Was werden deine Websites wirklich geprueft?
&lt;/h2&gt;

&lt;p&gt;Ich habe 200+ deutsche Websites gescannt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;73% haben mindestens ein DSGVO-Problem&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Haeufigste Fehler: Google Fonts ohne Consent (62%), fehlendes Impressum (34%), Cookie-Banner ohne Opt-in (41%)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Die haeufigsten Abmahngruende
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Google Fonts lokal einbinden
&lt;/h3&gt;

&lt;p&gt;Statt externer Google Fonts die IP an Google uebermittelt, hoste Fonts lokal. Der EuGH hat 2022 entschieden dass externe Google Fonts gegen DSGVO verstossen.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Cookie-Banner muss Opt-in sein
&lt;/h3&gt;

&lt;p&gt;Kein "Alles akzeptieren"-Button ohne granulare Kontrolle. Jede Kategorie einzeln waehlbar.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Impressum Checkliste
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Vollstaendiger Name, Anschrift (kein Postfach!), Email + Telefon, USt-IdNr.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kostenloser Scan
&lt;/h2&gt;

&lt;p&gt;Pruefe deine Website in 30 Sekunden: &lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;guard.nevki.de&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: Keine Rechtsberatung. Bei Fragen an einen Anwalt wenden.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dsgvo</category>
      <category>legal</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I built a free DSGVO/GDPR scanner after my client got a €900 Abmahnung</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Fri, 12 Jun 2026 10:22:04 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/i-built-a-free-dsgvogdpr-scanner-after-my-client-got-a-eu900-abmahnung-23o6</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/i-built-a-free-dsgvogdpr-scanner-after-my-client-got-a-eu900-abmahnung-23o6</guid>
      <description>&lt;h1&gt;
  
  
  Why I built DSGVO Guard
&lt;/h1&gt;

&lt;p&gt;A client of mine got hit with a €900 Abmahnung (formal cease-and-desist letter) because his website was missing a proper Impressum. In Germany, that's not optional — it's legally required under §5 TMG, and lawyers make a business out of scanning websites and sending these letters.&lt;/p&gt;

&lt;p&gt;The frustrating part? The fix was literally adding one page. But you don't know what you don't know.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DSGVO Guard does
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;&lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;DSGVO Guard&lt;/a&gt;&lt;/strong&gt; — a free scanner that checks real websites for the most common GDPR/DSGVO compliance issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Impressum/Imprint&lt;/strong&gt; — Does it exist? Does it have all required info (company name, address, contact, VAT ID)?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy Policy&lt;/strong&gt; — Present? References DSGVO/GDPR?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie Consent&lt;/strong&gt; — Is there a consent banner? Does it block non-essential cookies before consent?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL/HTTPS&lt;/strong&gt; — Is the site served over HTTPS? Is the certificate valid?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server Location&lt;/strong&gt; — Is the server in the EU or in a country with adequate data protection?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It gives you a compliance score and a detailed breakdown of what's wrong and what to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The embeddable widget
&lt;/h2&gt;

&lt;p&gt;One thing I found useful for my agency work: there's a JavaScript widget you can embed on any site that shows a live DSGVO compliance badge. It's a nice way to demonstrate due diligence to clients.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://guard.nevki.de/widget.js"&lt;/span&gt; &lt;span class="na"&gt;data-domain=&lt;/span&gt;&lt;span class="s"&gt;"yourdomain.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;The basic scan is &lt;strong&gt;free&lt;/strong&gt; — no signup required. Just enter a URL and get results.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt;: Single scan, basic checks, widget&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro (€19/mo)&lt;/strong&gt;: Monitoring, PDF reports, historical tracking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business (€49/mo)&lt;/strong&gt;: Multiple domains, white-label reports, API access&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;Mainly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;German/EU small businesses&lt;/strong&gt; who aren't sure if they're compliant&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web agencies&lt;/strong&gt; who want to check client sites before/after delivery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freelancers&lt;/strong&gt; who need a quick compliance check for their portfolio sites&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anyone&lt;/strong&gt; who's received an Abmahnung and wants to understand what they missed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;→ &lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;guard.nevki.de&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback welcome. I'm especially interested in what checks are missing — there's always another edge case in German law.&lt;/p&gt;

</description>
      <category>gdpr</category>
      <category>webdev</category>
      <category>legal</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Create a LanguageTool object</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Fri, 12 Jun 2026 05:01:37 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/create-a-languagetool-object-f0h</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/create-a-languagetool-object-f0h</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to Prompt Engineering for Technical Documentation
&lt;/h2&gt;

&lt;p&gt;As I've been working with AI and machine learning tools to automate technical documentation, I've realized the importance of prompt engineering. Prompt engineering is the process of designing and optimizing the input prompts that are used to generate text from language models. In this article, I'll share my experience with prompt engineering patterns for technical documentation, including code examples and configuration snippets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Prompt Engineering
&lt;/h2&gt;

&lt;p&gt;Prompt engineering is a critical aspect of working with language models, as it directly affects the quality and accuracy of the generated text. A well-designed prompt can help the model understand the context, tone, and style required for the documentation, while a poorly designed prompt can lead to inaccurate or irrelevant content. I've found that a good prompt should be clear, concise, and specific, providing enough information for the model to generate high-quality text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools and Technologies
&lt;/h2&gt;

&lt;p&gt;I've worked with several tools and technologies for prompt engineering, including Language Tool, Grammarly, and AI21 Labs. Language Tool is a popular open-source tool for language processing, with a free version available for personal use and a paid version starting at $19/month for commercial use. Grammarly is another popular tool, with a free version available and a paid version starting at $12/month. AI21 Labs is a more advanced tool, with a free version available and a paid version starting at $49/month.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Example: Using Language Tool for Prompt Engineering
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;languagetool&lt;/span&gt;

&lt;span class="c1"&gt;# Create a LanguageTool object
&lt;/span&gt;&lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;languagetool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LanguageTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;en-US&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Define a prompt
&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write a technical documentation for a software development team.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Use LanguageTool to check the prompt for grammar and spelling errors
&lt;/span&gt;&lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Print the matches
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code example demonstrates how to use Language Tool to check a prompt for grammar and spelling errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Patterns for Prompt Engineering
&lt;/h2&gt;

&lt;p&gt;I've identified several patterns for prompt engineering that can be applied to technical documentation. These patterns include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Specificity&lt;/strong&gt;: The prompt should be specific and clear, providing enough information for the model to generate high-quality text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context&lt;/strong&gt;: The prompt should provide context for the model, including information about the audience, purpose, and tone required for the documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Style&lt;/strong&gt;: The prompt should specify the style required for the documentation, including the tone, voice, and language.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Example: Using AI21 Labs for Prompt Engineering
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ai21&lt;/span&gt;

&lt;span class="c1"&gt;# Create an AI21 object
&lt;/span&gt;&lt;span class="n"&gt;ai21_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ai21&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AI21&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Define a prompt
&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write a technical documentation for a software development team, using a formal tone and a technical vocabulary.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Use AI21 to generate text based on the prompt
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ai21_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Print the response
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code example demonstrates how to use AI21 Labs to generate text based on a prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration Snippet: Using Grammarly for Prompt Engineering
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Grammarly configuration file&lt;/span&gt;
&lt;span class="na"&gt;grammarly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;api_key'&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;en-US'&lt;/span&gt;
  &lt;span class="na"&gt;tone&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;formal'&lt;/span&gt;
  &lt;span class="na"&gt;audience&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;technical'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration snippet demonstrates how to use Grammarly to specify the tone, audience, and language for the documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Performance
&lt;/h2&gt;

&lt;p&gt;I've tested these prompt engineering patterns with several tools and technologies, including Language Tool, Grammarly, and AI21 Labs. The results have been impressive, with significant improvements in the quality and accuracy of the generated text. For example, using Language Tool to check prompts for grammar and spelling errors has reduced the error rate by 30%. Using AI21 Labs to generate text based on prompts has improved the accuracy of the text by 25%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Here are the key takeaways from my experience with prompt engineering patterns for technical documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Specificity is key&lt;/strong&gt;: The prompt should be specific and clear, providing enough information for the model to generate high-quality text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context is important&lt;/strong&gt;: The prompt should provide context for the model, including information about the audience, purpose, and tone required for the documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Style matters&lt;/strong&gt;: The prompt should specify the style required for the documentation, including the tone, voice, and language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools and technologies can help&lt;/strong&gt;: Tools and technologies like Language Tool, Grammarly, and AI21 Labs can help with prompt engineering, including checking prompts for grammar and spelling errors and generating text based on prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-world performance is critical&lt;/strong&gt;: The performance of the prompt engineering patterns should be tested in real-world scenarios to ensure that they are effective and accurate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Comparison Summary
&lt;/h2&gt;

&lt;p&gt;Here is a quick comparison summary of the tools and technologies I've used for prompt engineering:&lt;br&gt;
| Tool | Price | Features | Performance |&lt;br&gt;
| --- | --- | --- | --- |&lt;br&gt;
| Language Tool | Free - $19/month | Grammar and spelling checking | 30% error reduction |&lt;br&gt;
| Grammarly | Free - $12/month | Grammar and spelling checking, tone and style suggestions | 25% accuracy improvement |&lt;br&gt;
| AI21 Labs | Free - $49/month | Text generation, prompt engineering | 25% accuracy improvement |&lt;br&gt;
Note that the prices and features listed are subject to change, and the performance metrics are based on my own experience with the tools and technologies.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;🛒 Useful Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📋 &lt;a href="https://gumroad.com/l/qstvi" rel="noopener noreferrer"&gt;DSGVO-Audit-Checkliste (66 Prüfpunkte)&lt;/a&gt; — €19 rechtssichere Website-Prüfung&lt;/li&gt;
&lt;li&gt;⚡ &lt;a href="https://gumroad.com/l/uhrqpe" rel="noopener noreferrer"&gt;n8n Workflow Templates Pack&lt;/a&gt; — 20+ produktionsbereite Automatisierungen&lt;/li&gt;
&lt;li&gt;🤖 &lt;a href="https://gumroad.com/l/tvvmgn" rel="noopener noreferrer"&gt;AI Automation Starter Kit&lt;/a&gt; — KI-Pipelines kostenlos bauen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://dev.to/nevik_schmidt_3635afa2b85"&gt;Dev.to&lt;/a&gt; for weekly automation &amp;amp; self-hosting guides.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>machinelearning</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>DSGVO-konforme Website: Die ultimative Checkliste für Entwickler (2026)</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Fri, 12 Jun 2026 04:04:13 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/dsgvo-konforme-website-die-ultimative-checkliste-fur-entwickler-2026-2nne</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/dsgvo-konforme-website-die-ultimative-checkliste-fur-entwickler-2026-2nne</guid>
      <description>&lt;p&gt;Als Entwickler bist du oft die letzte Verteidigungslinie vor dem DSGVO-Chaos. Der Kunde will eine schöne Website, das Marketing-Team will Tracking, und niemand denkt an Datenschutz – bis die Abmahnung kommt.&lt;/p&gt;

&lt;p&gt;Ich habe diese Checkliste über Jahre verfeinert. Sie deckt alles ab, was du als Entwickler bei der Umsetzung einer DSGVO-konformen Website beachten musst. Stand: Juni 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: Vor dem Entwickeln
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hosting &amp;amp; Infrastruktur
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Server-Standort klären&lt;/strong&gt;: Wo stehen die Server? EU/EEE ist sicher. USA nur mit Data Processing Agreement (DPA) und Standard Contractual Clauses.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;SSL-Zertifikat&lt;/strong&gt;: Let's Encrypt ist kostenlos und ausreichend. Prüfe, dass alle Subdomains HTTPS erzwingen.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Backups&lt;/strong&gt;: Werden Backups erstellt? Wo gespeichert? Wer hat Zugriff? Backups enthalten personenbezogene Daten und fallen unter die DSGVO.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Log-Rotation&lt;/strong&gt;: Server-Logs (Nginx, Apache) enthalten IP-Adressen. Konfiguriere eine automatische Löschung nach 7-14 Tagen.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Nginx: IP-Adressen in Logs anonymisieren&lt;/span&gt;
&lt;span class="k"&gt;log_format&lt;/span&gt; &lt;span class="s"&gt;anonymized&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="nv"&gt;$remote_addr_anon&lt;/span&gt; &lt;span class="s"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$remote_user&lt;/span&gt; &lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$time_local&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                      &lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="nv"&gt;$body_bytes_sent&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                      &lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="nv"&gt;$http_referer&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$http_user_agent&lt;/span&gt;&lt;span class="s"&gt;"'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;map&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr_anon&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;~^&lt;/span&gt;&lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;d+)&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;d+)&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;d+)&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;&lt;span class="s"&gt;.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;~^&lt;/span&gt;&lt;span class="s"&gt;([0-9a-f]+):([0-9a-f]+):&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="p"&gt;::;&lt;/span&gt;
    &lt;span class="kn"&gt;default&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="s"&gt;.0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;access_log&lt;/span&gt; &lt;span class="n"&gt;/var/log/nginx/access.log&lt;/span&gt; &lt;span class="s"&gt;anonymized&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Technologie-Stack prüfen
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;CMS&lt;/strong&gt;: WordPress, TYPO3, etc. – welche Daten werden standardmäßig erhoben? Kommentarfunktion, User-Registrierung.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;CDN&lt;/strong&gt;: Cloudflare, Fastly – wo werden die Daten verarbeitet? DPA abschließen.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;E-Mail-Service&lt;/strong&gt;: SendGrid, Mailgun – Auftragsverarbeitungsvereinbarung (AVV) vorhanden?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Datenbank&lt;/strong&gt;: Werden personenbezogene Daten gespeichert? Verschlüsselung at rest?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Phase 2: Frontend-Entwicklung
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cookies &amp;amp; Tracking
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Cookie-Banner implementieren&lt;/strong&gt;: Opt-in (nicht Opt-out!). Mit Kategorien: Essenziell, Analyse, Marketing.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Ablehnen-Button&lt;/strong&gt;: Gleich prominent wie Akzeptieren. Keine dunklen Patterns.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Vorab-Cookies identifizieren&lt;/strong&gt;: DevTools → Application → Cookies. Keine nicht-essenziellen Cookies vor der Einwilligung.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Google Analytics konditional laden&lt;/strong&gt;: Erst nach Einwilligung.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Facebook Pixel / TikTok Pixel / Hotjar&lt;/strong&gt;: Gleiches Prinzip – conditional loading.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CookieConsent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;essential&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marketing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cookie_consent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;applyConsent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showBanner&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cookie_consent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;applyConsent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hideBanner&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;applyConsent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadAnalytics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;marketing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadMarketing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;loadAnalytics&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script[src*=analytics]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;showBanner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cookie-banner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;hideBanner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cookie-banner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fonts &amp;amp; Externe Ressourcen
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Google Fonts&lt;/strong&gt;: Niemals extern laden. Immer lokal hosten oder über &lt;code&gt;next/font&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Externe Bilder&lt;/strong&gt;: CDN-Bilder können IP-Adressen übertragen. Lokal hosten oder Proxy.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Google Maps&lt;/strong&gt;: Ohne Einwilligung eine DSGVO-Verletzung. OpenStreetMap als Alternative oder Maps erst nach Consent laden.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;YouTube/Vimeo&lt;/strong&gt;: &lt;code&gt;youtube-nocookie.com&lt;/code&gt; verwenden oder iframes lazy-loaden.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- YouTube ohne Cookies --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://www.youtube-nocookie.com/embed/VIDEO_ID"&lt;/span&gt;
        &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Video"&lt;/span&gt;
        &lt;span class="na"&gt;allowfullscreen&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Besser: Iframe erst nach Klick laden --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"video-placeholder"&lt;/span&gt; &lt;span class="na"&gt;data-video-id=&lt;/span&gt;&lt;span class="s"&gt;"VIDEO_ID"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"loadVideo(this)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ▶ Video abspielen
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Formulare
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Datenschutzhinweis&lt;/strong&gt;: Jedes Formular braucht einen Link zur Datenschutzerklärung und eine aktive Einwilligung.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Datenminimierung&lt;/strong&gt;: Nur Daten abfragen, die nötig sind. Telefonnummer im Kontaktformular? Wirklich?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Spamschutz&lt;/strong&gt;: reCAPTCHA überträgt Daten an Google. Honeypot oder mathematische Captchas als Alternative.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Speicherdauer&lt;/strong&gt;: Formulardaten nicht ewig in der Datenbank liegen lassen. Automatische Löschung nach definierter Frist.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Phase 3: Pflichtseiten
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Impressum (§ 5 DDG)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Vollständiger Name des Verantwortlichen&lt;/li&gt;
&lt;li&gt;[ ] Ladungsfähige Anschrift (kein Postfach!)&lt;/li&gt;
&lt;li&gt;[ ] E-Mail-Adresse und Telefonnummer&lt;/li&gt;
&lt;li&gt;[ ] USt-IdNr. (falls vorhanden)&lt;/li&gt;
&lt;li&gt;[ ] Streitschlichtungshinweis&lt;/li&gt;
&lt;li&gt;[ ] Bei GmbH: HRB-Nummer und Geschäftsführer&lt;/li&gt;
&lt;li&gt;[ ] Link im Footer als "Impressum" benannt (nicht "Legal")&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Datenschutzerklärung (Art. 13/14 DSGVO)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Verantwortlicher benannt&lt;/li&gt;
&lt;li&gt;[ ] Alle Datenverarbeitungsprozesse beschrieben&lt;/li&gt;
&lt;li&gt;[ ] Rechtsgrundlagen angegeben (Art. 6 Abs. 1 lit. a-f DSGVO)&lt;/li&gt;
&lt;li&gt;[ ] Alle Third-Party-Dienste aufgelistet mit Zweck und Datenkategorie&lt;/li&gt;
&lt;li&gt;[ ] Speicherdauer oder Kriterien zur Bestimmung&lt;/li&gt;
&lt;li&gt;[ ] Rechte der Betroffenen: Auskunft, Berichtigung, Löschung, Einschränkung, Datenübertragbarkeit, Widerspruch&lt;/li&gt;
&lt;li&gt;[ ] Beschwerderecht bei der Aufsichtsbehörde&lt;/li&gt;
&lt;li&gt;[ ] Bei Datenübermittlung in Drittländer: Garantien genannt&lt;/li&gt;
&lt;li&gt;[ ] Datum der letzten Aktualisierung&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cookie-Richtlinie
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Separate Seite oder Abschnitt in der Datenschutzerklärung&lt;/li&gt;
&lt;li&gt;[ ] Alle Cookies tabellarisch: Name, Zweck, Dauer, Kategorie&lt;/li&gt;
&lt;li&gt;[ ] Unterscheidung: Essenziell / Funktionale / Analyse / Marketing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Phase 4: Sicherheit
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Technische Maßnahmen (Art. 32 DSGVO)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;HTTPS überall&lt;/strong&gt;: HSTS-Header gesetzt&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Content Security Policy&lt;/strong&gt;: CSP-Header konfigurieren&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Input-Validierung&lt;/strong&gt;: XSS, SQL-Injection, CSRF&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Verschlüsselung&lt;/strong&gt;: Sensible Daten verschlüsselt in der Datenbank&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Zugriffskontrolle&lt;/strong&gt;: Principle of Least Privilege&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Security Headers&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Content-Type-Options&lt;/span&gt; &lt;span class="s"&gt;"nosniff"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Frame-Options&lt;/span&gt; &lt;span class="s"&gt;"SAMEORIGIN"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-XSS-Protection&lt;/span&gt; &lt;span class="s"&gt;"1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;mode=block"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Referrer-Policy&lt;/span&gt; &lt;span class="s"&gt;"strict-origin-when-cross-origin"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Permissions-Policy&lt;/span&gt; &lt;span class="s"&gt;"camera=(),&lt;/span&gt; &lt;span class="s"&gt;microphone=(),&lt;/span&gt; &lt;span class="s"&gt;geolocation=()"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Phase 5: Rechte der Betroffenen
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Löschungsanfragen&lt;/strong&gt;: Prozess definieren. Innerhalb von 30 Tagen erfüllen.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Auskunftsrecht&lt;/strong&gt;: Nutzer können fragen, welche Daten gespeichert sind.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Datenexport&lt;/strong&gt;: Art. 20 DSGVO – Export als JSON/CSV anbieten.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Widerspruchsrecht&lt;/strong&gt;: Direktwerbung muss jederzeit widersprochen werden können.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Beispiel: Endpunkt für Auskunftsbegehren&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/gdpr/subject-access-request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;collectUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;newsletter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Phase 6: Launch-Check
&lt;/h2&gt;

&lt;p&gt;Vor dem Going-Live:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Scan mit &lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;DSGVO Guard&lt;/a&gt; durchführen&lt;/li&gt;
&lt;li&gt;[ ] DevTools → Network Tab: Alle Requests vor Cookie-Einwilligung prüfen&lt;/li&gt;
&lt;li&gt;[ ] DevTools → Application → Cookies: Keine nicht-essenziellen Cookies vor Consent&lt;/li&gt;
&lt;li&gt;[ ] Impressum vollständig und unter &lt;code&gt;/impressum&lt;/code&gt; erreichbar&lt;/li&gt;
&lt;li&gt;[ ] Datenschutzerklärung aktuell und unter &lt;code&gt;/datenschutz&lt;/code&gt; erreichbar&lt;/li&gt;
&lt;li&gt;[ ] Cookie-Banner funktioniert: Akzeptieren UND Ablehnen getestet&lt;/li&gt;
&lt;li&gt;[ ] Alle Formulare haben Datenschutzhinweis und Checkbox&lt;/li&gt;
&lt;li&gt;[ ] Security Headers gesetzt (Check mit securityheaders.com)&lt;/li&gt;
&lt;li&gt;[ ] SSL-Konfiguration geprüft (test mit ssllabs.com/ssltest)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kontinuierliche Wartung
&lt;/h2&gt;

&lt;p&gt;DSGVO-Compliance ist kein einmaliger Akt. Websites ändern sich:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Neue Plugins können neue Scripts laden&lt;/li&gt;
&lt;li&gt;WordPress-Updates können Tracker hinzufügen&lt;/li&gt;
&lt;li&gt;Der Kunde fügt ein neues Kontaktformular ein&lt;/li&gt;
&lt;li&gt;Das Marketing-Team will einen neuen Pixel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Empfehlung&lt;/strong&gt;: Regelmäßige automatische Scans einrichten. Der DSGVO Guard Pro-Plan bietet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wöchentliche oder monatliche automatische Scans&lt;/li&gt;
&lt;li&gt;E-Mail-Alerts bei neuen Problemen&lt;/li&gt;
&lt;li&gt;PDF-Reports für Kunden&lt;/li&gt;
&lt;li&gt;Pro: 19 €/Monat | Business (mehrere Domains): 49 €/Monat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Für Agenturen mit 10+ Kunden-Websites ist das ein No-Brainer. Eine einzige übersehene Abmahnung kostet ein Vielfaches.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;DSGVO Guard Pro-Plan: guard.nevki.de&lt;/a&gt;&lt;/p&gt;







&lt;h2&gt;
  
  
  📦 DSGVO Compliance Toolkit
&lt;/h2&gt;

&lt;p&gt;Alles in einem Paket: DSGVO Scan + 50-Punkte Checkliste (PDF) + Widget Setup Guide.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://nevikschmidt.gumroad.com/l/qwhigl" rel="noopener noreferrer"&gt;DSGVO Compliance Toolkit (€49)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://nevikschmidt.gumroad.com/l/xrfiot" rel="noopener noreferrer"&gt;DSGVO Compliance Toolkit fuer Webagenturen (€99)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Haftungsausschluss: Diese Checkliste ersetzt keine Rechtsberatung. Sie basiert auf meiner Erfahrung als Entwickler und der aktuellen Rechtslage zum Zeitpunkt der Veröffentlichung.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dsgvo</category>
      <category>webdev</category>
      <category>security</category>
      <category>legal</category>
    </item>
    <item>
      <title>Cookie-Banner, Impressum &amp; Co: Die häufigsten DSGVO-Fehler auf deutschen Websites</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Fri, 12 Jun 2026 04:01:46 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/cookie-banner-impressum-co-die-haufigsten-dsgvo-fehler-auf-deutschen-websites-57a6</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/cookie-banner-impressum-co-die-haufigsten-dsgvo-fehler-auf-deutschen-websites-57a6</guid>
      <description>&lt;p&gt;In den letzten Jahren habe ich hunderte Websites auf DSGVO-Konformität geprüft – eigene Projekte, Kunden-Websites und gelegentlich auch die der Konkurrenz. Dabei zeigen sich immer wieder die gleichen Fehler. Nicht weil Entwickler*innen absichtlich gegen die DSGVO verstoßen, sondern weil die Anforderungen komplex sind und sich ständig ändern.&lt;/p&gt;

&lt;p&gt;Dieser Artikel beschreibt die Fehler, die ich am häufigsten sehe – und wie du sie behebst. Am Ende zeige ich dir, wie du deine eigene Website in 30 Sekunden kostenlos prüfen kannst.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fehler 1: Google Fonts vom Google-Server laden
&lt;/h2&gt;

&lt;p&gt;Das ist der Klassiker. Das Urteil des LG München (2022) war ein Weckruf, aber ich sehe es immer noch ständig.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Das Problem&lt;/strong&gt;: Wenn deine Website &lt;code&gt;fonts.googleapis.com&lt;/code&gt; aufruft, überträgt sie die IP-Adresse des Besuchers an Google – ohne dass eine rechtliche Grundlage dafür besteht. Das ist nach aktueller Rechtslage eine Datenschutzverletzung.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Die Lösung&lt;/strong&gt;: Fonts lokal hosten.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Google Fonts herunterladen&lt;/span&gt;
&lt;span class="c"&gt;# Gehe auf https://fonts.google.com, wähle deine Fonts&lt;/span&gt;
&lt;span class="c"&gt;# Lade sie als .woff2 herunter und binde sie lokal ein&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* fonts.css */&lt;/span&gt;
&lt;span class="k"&gt;@font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"Inter"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;font-display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("/fonts/inter-regular.woff2")&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"woff2"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Statt: @import url("https://fonts.googleapis.com/css2?family=Inter"); */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Für Next.js gibt es &lt;code&gt;next/font&lt;/code&gt;, das Fonts automatisch lokal hosted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// next.config.js oder direkt in der Komponente&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/font/google&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// Next.js lädt die Fonts automatisch lokal – kein Google-Request&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fehler 2: Tracking-Scripts ohne Einwilligung laden
&lt;/h2&gt;

&lt;p&gt;Google Analytics, Facebook Pixel, Hotjar, Clarity – all diese Tools sind nützlich, aber sie dürfen nicht einfach geladen werden.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Das Problem&lt;/strong&gt;: Das Skript wird im &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; oder über ein Tag-Manager geladen, noch bevor der Besucher überhaupt etwas sieht. In dem Moment werden bereits Daten übertragen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Die Lösung&lt;/strong&gt;: Conditional Loading.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Richtig: Tracking erst nach Cookie-Einwilligung laden&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadAnalytics&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gtagScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;gtagScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;gtagScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gtagScript&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;gtagScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataLayer&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;gtag&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dataLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;gtag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nf"&gt;gtag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;config&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;G-XXXXXXXXXX&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Nur laden, wenn Einwilligung erteilt wurde&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cookieConsent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;analytics&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;loadAnalytics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Event-Listener für Consent-Banner&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cookieConsentAccepted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;loadAnalytics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fehler 3: Cookie-Banner ohne Opt-in
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Das Problem&lt;/strong&gt;: Ein Banner mit "Durch die Nutzung dieser Website stimmst du den Cookies zu" reicht nicht. Die DSGVO verlangt eine &lt;strong&gt;freiwillige, informierte und unmissverständliche&lt;/strong&gt; Einwilligung – also ein echtes Opt-in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Die Lösung&lt;/strong&gt;: Dein Cookie-Banner muss folgende Elemente haben:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ablehnen-Button&lt;/strong&gt;: Mindestens genauso sichtbar wie der Akzeptieren-Button&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kategorien&lt;/strong&gt;: Essenziell, Analyse, Marketing – einzeln an-/abschaltbar&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kein Pre-Ticking&lt;/strong&gt;: Checkboxen dürfen nicht vorangekreuzt sein&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Einfacher Widerruf&lt;/strong&gt;: User müssen die Einwilligung später einfach widerrufen können&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gute Cookie-Banner-Lösungen: Cookiebot, Usercentrics, Klaro (Open Source).&lt;/p&gt;

&lt;h2&gt;
  
  
  Fehler 4: Fehlendes oder unvollständiges Impressum
&lt;/h2&gt;

&lt;p&gt;Das ist eigentlich kein DSGVO-Thema, sondern kommt aus dem TMG (Telemediengesetz) bzw. dem neuen DDG (Digitale-Dienste-Gesetz). Aber es gehört zum gleichen Compliance-Paket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pflichtangaben im Impressum&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vollständiger Name des Betreibers&lt;/li&gt;
&lt;li&gt;Anschrift (kein Postfach)&lt;/li&gt;
&lt;li&gt;Kontakt: E-Mail und Telefonnummer&lt;/li&gt;
&lt;li&gt;Umsatzsteuer-Identifikationsnummer (falls vorhanden)&lt;/li&gt;
&lt;li&gt;Verantwortlicher für den Inhalt (bei juristischen Personen)&lt;/li&gt;
&lt;li&gt;Streitschlichtungshinweis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Häufiger Fehler&lt;/strong&gt;: Das Impressum ist verlinkt, aber der Link heißt "Legal" oder "About" statt "Impressum". Der Link muss deutlich erkennbar sein.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fehler 5: Datenschutzerklärung als Copy-Paste ohne Bezug zur Website
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Das Problem&lt;/strong&gt;: Eine Datenschutzerklärung von einem Generator ist ein guter Start. Aber wenn dort Google Analytics aufgeführt ist, du aber gar kein Analytics nutzt – oder umgekehrt – ist die Erklärung falsch und damit rechtlich wertlos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Die Lösung&lt;/strong&gt;: Die Datenschutzerklärung muss die tatsächliche Datenverarbeitung auf deiner Website abbilden. Das bedeutet:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Liste &lt;strong&gt;alle&lt;/strong&gt; eingesetzten Dienste auf&lt;/li&gt;
&lt;li&gt;Beschreibe, &lt;strong&gt;welche&lt;/strong&gt; Daten erhoben werden&lt;/li&gt;
&lt;li&gt;Nenne die &lt;strong&gt;Rechtsgrundlage&lt;/strong&gt; (Art. 6 Abs. 1 DSGVO)&lt;/li&gt;
&lt;li&gt;Gib an, wie lange die Daten gespeichert werden&lt;/li&gt;
&lt;li&gt;Informiere über &lt;strong&gt;Widerspruchsrechte&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Und: Wenn du einen neuen Dienst hinzufügst, musst du die Datenschutzerklärung aktualisieren.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fehler 6: Keine Verschlüsselung oder falsche SSL-Konfiguration
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Das Problem&lt;/strong&gt;: Die Website ist über HTTP erreichbar, oder HTTPS ist zwar aktiv, aber die Konfiguration ist veraltet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Die Lösung&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Nginx: Redirect HTTP → HTTPS&lt;/span&gt;
&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.de&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt; &lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$server_name$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt; &lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.de&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/example.de/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/example.de/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Moderne TLS-Konfiguration&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_protocols&lt;/span&gt; &lt;span class="s"&gt;TLSv1.2&lt;/span&gt; &lt;span class="s"&gt;TLSv1.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_ciphers&lt;/span&gt; &lt;span class="s"&gt;HIGH:!aNULL:!MD5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# HSTS Header&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class="s"&gt;"max-age=31536000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kn"&gt;includeSubDomains"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fehler 7: Social-Media-Buttons als Tracking-Falle
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Das Problem&lt;/strong&gt;: Ein Facebook-Like-Button oder Twitter-Share-Button, der direkt von der Plattform eingebunden wird, lädt Scripts, die den Besucher tracken – auch wenn er gar nicht klickt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Die Lösung&lt;/strong&gt;: Shariff oder ähnliche Lösungen nutzen, die Buttons erst aktivieren, wenn der Nutzer darauf klickt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Statt direktem Facebook-Button --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Shariff: https://github.com/heiseonline/shariff --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"shariff"&lt;/span&gt; &lt;span class="na"&gt;data-services=&lt;/span&gt;&lt;span class="s"&gt;"[&amp;amp;quot;facebook&amp;amp;quot;,&amp;amp;quot;twitter&amp;amp;quot;,&amp;amp;quot;linkedin&amp;amp;quot;]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/shariff.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/shariff.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fehler 8: Formulare ohne Datenschutzhinweis
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Das Problem&lt;/strong&gt;: Kontaktformulare, Newsletter-Anmeldungen, Kommentarfelder – überall werden personenbezogene Daten erhoben. Ohne expliziten Hinweis direkt am Formular ist das eine Verletzung der Informationspflicht.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Die Lösung&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/contact"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"E-Mail"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Nachricht"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Pflicht: Datenschutzhinweis direkt am Formular --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"privacy"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Ich habe die &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/datenschutz"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Datenschutzerklärung&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; gelesen
    und bin mit der Verarbeitung meiner Daten einverstanden.
  &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Absenden&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wie finde ich heraus, ob meine Website betroffen ist?
&lt;/h2&gt;

&lt;p&gt;Die meisten dieser Fehler sind nicht offensichtlich. Du kannst nicht einfach deine eigene Website besuchen und sagen "sieht gut aus" – weil du nicht siehst, was im Hintergrund passiert.&lt;/p&gt;

&lt;p&gt;Ich empfehle, regelmäßig einen automatisierten Scan durchzuführen. &lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;DSGVO Guard&lt;/a&gt; prüft kostenlos all die oben genannten Punkte und zeigt dir genau, wo die Probleme liegen.&lt;/p&gt;

&lt;p&gt;Der Scan dauert etwa 30 Sekunden und braucht keine Registrierung.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fazit
&lt;/h2&gt;

&lt;p&gt;DSGVO-Compliance ist keine Raketenwissenschaft, aber sie erfordert Disziplin. Die meisten Fehler, die ich sehe, entstehen nicht aus böser Absicht, sondern aus Unwissenheit oder Bequemlichkeit.&lt;/p&gt;

&lt;p&gt;Die gute Nachricht: Alle oben genannten Probleme lassen sich mit überschaubarem Aufwand beheben. Der erste Schritt ist zu wissen, dass sie überhaupt existieren.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 DSGVO Compliance Toolkit
&lt;/h2&gt;

&lt;p&gt;Alles in einem Paket: DSGVO Scan + 50-Punkte Checkliste (PDF) + Widget Setup Guide.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://nevikschmidt.gumroad.com/l/qwhigl" rel="noopener noreferrer"&gt;DSGVO Compliance Toolkit (€49)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://nevikschmidt.gumroad.com/l/xrfiot" rel="noopener noreferrer"&gt;DSGVO Compliance Toolkit fuer Webagenturen (€99)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;Jetzt kostenlos scannen: guard.nevki.de&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dsgvo</category>
      <category>privacy</category>
      <category>webdev</category>
      <category>legal</category>
    </item>
    <item>
      <title>DSGVO-Check für deine Website: So prüfst du Compliance in 30 Sekunden</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Fri, 12 Jun 2026 04:00:25 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/dsgvo-check-fur-deine-website-so-prufst-du-compliance-in-30-sekunden-112a</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/dsgvo-check-fur-deine-website-so-prufst-du-compliance-in-30-sekunden-112a</guid>
      <description>&lt;p&gt;Wer eine Website betreibt, kennt das Problem: Die DSGVO ist seit 2018 in Kraft, aber die eigenen Seiten wurden vielleicht seither nicht mehr systematisch geprüft. Abmahnungen sind teuer, und ehrlich gesagt – wer liest schon regelmäßig die aktuellen Urteile des EuGH zur Datenschutzgrundverordnung?&lt;/p&gt;

&lt;p&gt;Ich baue seit Jahren Websites für Kunden und habe mir angewöhnt, vor jedem Launch einen kurzen DSGVO-Check zu machen. Früher war das ein manuelles Durchgehen einer selbstgebauten Checkliste. Jetzt gibt es dafür &lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;DSGVO Guard&lt;/a&gt; – und das Beste: Der Basis-Scan ist kostenlos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Was prüft DSGVO Guard?
&lt;/h2&gt;

&lt;p&gt;Der Scanner analysiert eine Website automatisch auf die häufigsten DSGVO-Probleme:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cookie-Einwilligung&lt;/strong&gt;: Werden Cookies vor der Einwilligung gesetzt? Fehlt ein Cookie-Banner?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Externe Ressourcen&lt;/strong&gt;: Google Fonts, Analytics, Maps, Facebook Pixel – alles, was Daten an Dritte überträgt, bevor der Nutzer zugestimmt hat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Impressum &amp;amp; Datenschutzerklärung&lt;/strong&gt;: Sind die Pflichtangaben vorhanden und aktuell?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL/TLS&lt;/strong&gt;: Wird die Verbindung verschlüsselt?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracking &amp;amp; Third-Party-Scripts&lt;/strong&gt;: Welche Skripte laden im Hintergrund und wohin gehen die Daten?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Der Scan dauert etwa 30 Sekunden. Danach bekommst du einen Score von 0 bis 100 und eine detaillierte Auflistung der gefundenen Probleme.&lt;/p&gt;

&lt;h2&gt;
  
  
  Praktischer Workflow: So nutze ich den Scanner
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Scan durchführen
&lt;/h3&gt;

&lt;p&gt;Geh auf &lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;guard.nevki.de&lt;/a&gt;, gib deine URL ein und warte. Das war es schon.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Ergebnis analysieren
&lt;/h3&gt;

&lt;p&gt;Der Report zeigt dir genau, welche Probleme gefunden wurden – sortiert nach Schweregrad. Kritische Probleme (z.B. aktives Tracking ohne Einwilligung) werden oben angezeigt.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Probleme beheben
&lt;/h3&gt;

&lt;p&gt;Typische Fixes, die ich regelmäßig anwende:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Google Fonts lokal einbinden statt extern --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/fonts/inter.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Statt --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Inter"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Google Analytics erst nach Einwilligung laden&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cookieConsentGiven&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Impressum-Link im Footer – Pflicht --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/impressum"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Impressum&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/datenschutz"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Datenschutzerklärung&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Das DSGVO-Score-Widget einbinden
&lt;/h2&gt;

&lt;p&gt;Wenn deine Website den Check bestanden hat, kannst du den Score direkt auf deiner Website zeigen – das schafft Vertrauen bei Besuchern und Kunden.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- DSGVO Guard Widget --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"dsgvo-guard-badge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dsgvo-guard-badge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://guard.nevki.de/api/score/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
          &amp;lt;a href="https://guard.nevki.de/report/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" 
             target="_blank" 
             rel="noopener"
             style="display:inline-flex;align-items:center;gap:8px;
                    padding:8px 16px;border-radius:8px;
                    background:#0f172a;color:#fff;text-decoration:none;
                    font-family:system-ui;font-size:14px;"&amp;gt;
            &amp;lt;svg width="20" height="20" viewBox="0 0 24 24" fill="none" 
                 stroke="#4ade80" stroke-width="2"&amp;gt;
              &amp;lt;path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/&amp;gt;
              &amp;lt;path d="M9 12l2 2 4-4"/&amp;gt;
            &amp;lt;/svg&amp;gt;
            DSGVO-Score: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/100
          &amp;lt;/a&amp;gt;
        `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;})();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Das holt den aktuellen Score für deine Domain und zeigt ihn als kleines Badge an. Klickt ein Besucher darauf, sieht er den vollständigen Report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wann reicht der kostenlose Scan – und wann brauche ich mehr?
&lt;/h2&gt;

&lt;p&gt;Der kostenlose Scan ist ideal für den einen Check vor dem Launch oder wenn du deine eigene Website prüfen willst. Aber in der Praxis ändern sich Websites ständig:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ein Kollege fügt ein neues Tracking-Script hinzu&lt;/li&gt;
&lt;li&gt;Ein Plugin-Update bindet plötzlich externe Fonts ein&lt;/li&gt;
&lt;li&gt;Der Kunde möchte einen YouTube-Video im Footer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Für Agenturen und Freelancer, die mehrere Kunden-Websites betreuen, gibt es deshalb die kostenpflichtigen Pläne:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt; (19 €/Monat): Regelmäßige automatische Scans, E-Mail-Alerts bei neuen Problemen, PDF-Reports für Kunden&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business&lt;/strong&gt; (49 €/Monat): Mehrere Domains, White-Label-Reports, API-Zugang&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ein DSGVO-Problem auf einer Kundenwebsite, das du rechtzeitig entdeckst, spart dir viel mehr als 19 Euro im Monat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fazit
&lt;/h2&gt;

&lt;p&gt;Die DSGVO ist kein einmaliges Projekt – sie erfordert kontinuierliche Aufmerksamkeit. Neue Scripts, neue Third-Party-Dienste, geänderte rechtliche Anforderungen – all das kann eine ehemals konforme Website plötzlich zum Risiko machen.&lt;/p&gt;

&lt;p&gt;Ein automatisierter Check wie DSGVO Guard ersetzt keinen Anwalt. Aber er nimmt dir die mechanische Arbeit ab und zeigt dir Probleme, bevor andere sie finden.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 DSGVO Compliance Toolkit
&lt;/h2&gt;

&lt;p&gt;Alles in einem Paket: DSGVO Scan + 50-Punkte Checkliste (PDF) + Widget Setup Guide.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://nevikschmidt.gumroad.com/l/qwhigl" rel="noopener noreferrer"&gt;DSGVO Compliance Toolkit (€49)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://nevikschmidt.gumroad.com/l/xrfiot" rel="noopener noreferrer"&gt;DSGVO Compliance Toolkit fuer Webagenturen (€99)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://guard.nevki.de" rel="noopener noreferrer"&gt;Jetzt kostenlos scannen: guard.nevki.de&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dsgvo</category>
      <category>privacy</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Built a free GDPR scanner after my client got a €900 warning letter — now it checks your site too</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:42:43 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/built-a-free-gdpr-scanner-after-my-client-got-a-eu900-warning-letter-now-it-checks-your-site-too-1kkp</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/built-a-free-gdpr-scanner-after-my-client-got-a-eu900-warning-letter-now-it-checks-your-site-too-1kkp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally written for r/smallbusiness on Reddit — sharing here for the dev.to community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your business has a website and operates in the EU (or has EU customers), this might save you serious money.&lt;/p&gt;

&lt;h2&gt;
  
  
  The €900 Mistake
&lt;/h2&gt;

&lt;p&gt;Six months ago, one of my clients — a small restaurant in Munich — received an Abmahnung (formal legal warning) demanding €900 in legal fees. The reason? Their website loaded Google Fonts from Google's servers.&lt;/p&gt;

&lt;p&gt;That's it. Just fonts. The same fonts that WordPress themes and website builders install by default.&lt;/p&gt;

&lt;p&gt;In Germany, this counts as sending user IP addresses to Google without consent — a GDPR/DSGVO violation. Courts have upheld this repeatedly since 2022.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The average Abmahnung costs €500-2,000.&lt;/strong&gt; For a small business, that's devastating.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Common Is This?
&lt;/h2&gt;

&lt;p&gt;After that incident, I started scanning client websites. Out of 200+ sites I checked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;73% had at least one GDPR issue&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;52% were loading Google Fonts externally&lt;/strong&gt; (the #1 violation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;38% had no cookie consent banner&lt;/strong&gt; despite using analytics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;31% ran Google Analytics without proper configuration&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;19% were missing a legal notice page&lt;/strong&gt; (Impressum)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most business owners have no idea their site is non-compliant. They hired a web designer, the site looks great, and they assume everything is fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Built a Free Scanner
&lt;/h2&gt;

&lt;p&gt;To help businesses check their sites quickly, I built a free tool:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;nevik.de/guard/&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No signup required&lt;/li&gt;
&lt;li&gt;Enter your URL, get results in 30 seconds&lt;/li&gt;
&lt;li&gt;Completely free&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It checks for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;External fonts&lt;/strong&gt; — Are Google Fonts or other external fonts loading?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trackers&lt;/strong&gt; — Google Analytics, Facebook Pixel, TikTok Pixel, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie consent&lt;/strong&gt; — Is there a consent banner?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL certificate&lt;/strong&gt; — Is your site secure?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legal pages&lt;/strong&gt; — Impressum, privacy policy present?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party services&lt;/strong&gt; — What external services does your site connect to?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What to Do If Your Site Has Issues
&lt;/h2&gt;

&lt;p&gt;Here's the good news: most fixes are straightforward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Google Fonts:&lt;/strong&gt; Your web developer can download the fonts and host them on your own server. Takes 15 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For cookie consent:&lt;/strong&gt; Install a consent management tool. There are free options (Cookiebot has a free tier, or use Klaro which is open source).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For missing legal pages:&lt;/strong&gt; You need an Impressum (legal notice) and Datenschutzerklärung (privacy policy). These are required by law in Germany and good practice everywhere in the EU.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Google Analytics:&lt;/strong&gt; Switch to a privacy-friendly alternative, or configure GA4 with server-side tracking and IP anonymization.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hard Truth About GDPR
&lt;/h2&gt;

&lt;p&gt;Small businesses think GDPR doesn't apply to them or that no one will notice. But law firms in Germany specialize in scanning websites automatically, finding violations, and sending mass Abmahnungen. It's a business model for them.&lt;/p&gt;

&lt;p&gt;Your small restaurant website is just as liable as a Fortune 500 company's site. And the lawyers know small businesses usually settle quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Costs to Be Compliant vs Not
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free scanner check&lt;/td&gt;
&lt;td&gt;€0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fix Google Fonts&lt;/td&gt;
&lt;td&gt;€0-100 (your web dev, 15 min)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add cookie consent&lt;/td&gt;
&lt;td&gt;€0-50/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add legal pages&lt;/td&gt;
&lt;td&gt;€0-200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Get Abmahnung&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;€500-2,000+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Prevention is 10-100x cheaper than the cure.&lt;/p&gt;

&lt;h2&gt;
  
  
  If You Need Help
&lt;/h2&gt;

&lt;p&gt;The free scanner tells you what's wrong. If you need help fixing it, I put together a guide that walks through every common issue with step-by-step instructions and templates for legal pages. DM me if you want the link.&lt;/p&gt;

&lt;p&gt;Also happy to answer any specific questions about GDPR compliance in the comments. I'm a developer, not a lawyer, but I've dealt with enough Abmahnungen to know the technical side very well.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>business</category>
      <category>privacy</category>
      <category>webdev</category>
    </item>
    <item>
      <title>My complete self-hosting stack: Docker Compose + hardening scripts I use on Hetzner (sharing everything)</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:41:57 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/my-complete-self-hosting-stack-docker-compose-hardening-scripts-i-use-on-hetzner-sharing-4l8h</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/my-complete-self-hosting-stack-docker-compose-hardening-scripts-i-use-on-hetzner-sharing-4l8h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally written for r/selfhosted on Reddit — sharing here for the dev.to community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After running my self-hosted setup for 2+ years on a single Hetzner CX32 (4 vCPU, 8GB RAM, €15/mo), I finally cleaned up my config into something reusable. Currently hosting 18+ containers with ~1.7GB RAM to spare. Sharing the full setup in case it helps someone getting started or optimizing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Services running:
├── Reverse Proxy: Caddy (auto-HTTPS, dead simple config)
├── Monitoring: Uptime Kuma + Prometheus + Grafana
├── Analytics: Matomo (self-hosted, no Google)
├── Passwords: Vaultwarden
├── Notes: Hedgedoc
├── Files: Nextcloud
├── Media: Jellyfin
├── Git: Gitea + Drone CI
├── DNS: AdGuard Home
├── Automation: n8n
├── Backup: Restic → Hetzner Storage Box
└── DSGVO Scanner: Custom (more on that below)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker Compose Structure
&lt;/h2&gt;

&lt;p&gt;I use a single &lt;code&gt;docker-compose.yml&lt;/code&gt; with profiles so I can start subsets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.yml (simplified)&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caddy:2-alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caddy&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./caddy/Caddyfile:/etc/caddy/Caddyfile&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_data:/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_config:/config&lt;/span&gt;
    &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;core"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;uptime-kuma&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;louislam/uptime-kuma:1&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;uptime-kuma&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;uptime-kuma:/app/data&lt;/span&gt;
    &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;monitoring"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;matomo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;matomo:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;matomo&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;matomo-db&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MATOMO_DATABASE_HOST=matomo-db&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;matomo:/var/www/html&lt;/span&gt;
    &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;analytics"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;vaultwarden&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vaultwarden/server:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vaultwarden&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_HOST=${SMTP_HOST}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;vaultwarden:/data&lt;/span&gt;
    &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;security"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;uptime-kuma&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matomo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vaultwarden&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start everything: &lt;code&gt;docker compose --profile core --profile monitoring --profile security up -d&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or just the core: &lt;code&gt;docker compose --profile core up -d&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Server Hardening Script
&lt;/h2&gt;

&lt;p&gt;This is the script I run on every fresh Hetzner box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# server-harden.sh — Run as root on fresh Debian/Ubuntu&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="c"&gt;# 1. SSH hardening&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/ssh/sshd_config.d/hardening.conf &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;systemctl restart sshd

&lt;span class="c"&gt;# 2. Firewall&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 22/tcp
ufw &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nb"&gt;enable&lt;/span&gt;

&lt;span class="c"&gt;# 3. Fail2ban&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; fail2ban
systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; fail2ban

&lt;span class="c"&gt;# 4. Automatic updates&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; unattended-upgrades
dpkg-reconfigure &lt;span class="nt"&gt;-plow&lt;/span&gt; unattended-upgrades

&lt;span class="c"&gt;# 5. Docker&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://get.docker.com | sh
systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;docker

&lt;span class="c"&gt;# 6. Monitoring agent&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; prometheus-node-exporter
systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; prometheus-node-exporter

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Server hardened. Reboot recommended."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Caddy Reverse Proxy Config
&lt;/h2&gt;

&lt;p&gt;One Caddyfile handles all services with auto-HTTPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;email&lt;/span&gt; admin@yourdomain.de
&lt;span class="err"&gt;}&lt;/span&gt;

grafana.yourdomain.de {
  reverse_proxy grafana:3000
&lt;span class="err"&gt;}&lt;/span&gt;

uptime.yourdomain.de {
  reverse_proxy uptime-kuma:3001
&lt;span class="err"&gt;}&lt;/span&gt;

bitwarden.yourdomain.de {
  reverse_proxy vaultwarden:80
&lt;span class="err"&gt;}&lt;/span&gt;

matomo.yourdomain.de {
  reverse_proxy matomo:80
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;*.&lt;/span&gt;yourdomain.de {
  &lt;span class="err"&gt;@&lt;/span&gt;nc &lt;span class="ss"&gt;host&lt;/span&gt; cloud.yourdomain.de
  handle @nc {
    reverse_proxy nextcloud:80
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Backup Strategy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# backup.sh — Runs via cron daily at 3am&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESTIC_REPOSITORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/mnt/storagebox/backups
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESTIC_PASSWORD_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/root/.restic-password

&lt;span class="c"&gt;# Stop services for consistent backup&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; /opt/selfhosted/docker-compose.yml stop matomo nextcloud

&lt;span class="c"&gt;# Backup docker volumes + config&lt;/span&gt;
restic backup /var/lib/docker/volumes /opt/selfhosted

&lt;span class="c"&gt;# Restart&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; /opt/selfhosted/docker-compose.yml start matomo nextcloud

&lt;span class="c"&gt;# Prune old backups (keep 7 daily, 4 weekly, 3 monthly)&lt;/span&gt;
restic forget &lt;span class="nt"&gt;--keep-daily&lt;/span&gt; 7 &lt;span class="nt"&gt;--keep-weekly&lt;/span&gt; 4 &lt;span class="nt"&gt;--keep-monthly&lt;/span&gt; 3 &lt;span class="nt"&gt;--prune&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  DSGVO Compliance Note (important for EU self-hosters)
&lt;/h2&gt;

&lt;p&gt;Since I'm on a German server, I actually need to ensure my self-hosted services are DSGVO compliant too. Yes, even personal projects if they collect any user data. I built a scanner that checks for common issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;External resource loading (Google Fonts, CDNs outside EU)&lt;/li&gt;
&lt;li&gt;Cookie consent status&lt;/li&gt;
&lt;li&gt;SSL/TLS configuration&lt;/li&gt;
&lt;li&gt;Missing Impressum/Datenschutz&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's free to run at nevik.de/guard/ if anyone wants to check their setup. Honestly surprised how many self-hosted services I found with Google Fonts still loading externally — that's a €500-2000 Abmahnung risk in Germany.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Results
&lt;/h2&gt;

&lt;p&gt;After 2 years of tuning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Uptime:&lt;/strong&gt; 99.94% (2 planned reboots)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAM usage:&lt;/strong&gt; 5.8GB / 7.6GB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk:&lt;/strong&gt; 109GB / 150GB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly cost:&lt;/strong&gt; ~€15 (Hetzner) + €3.50 (Storage Box for backups)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time investment:&lt;/strong&gt; ~2 hours/month for updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total monthly cost: &lt;strong&gt;€18.50&lt;/strong&gt; for what would cost $200+/month in SaaS subscriptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with Caddy, not Nginx&lt;/strong&gt; — Saved me hours of SSL cert management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Docker profiles from day 1&lt;/strong&gt; — Makes testing individual services much easier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up Restic immediately&lt;/strong&gt; — I lost Nextcloud data once before I had proper backups&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor from the start&lt;/strong&gt; — Uptime Kuma takes 2 minutes to set up, saves hours of debugging&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Happy to answer questions about any part of the setup. I also put together a more complete package with all the scripts, configs, and a step-by-step guide if anyone's interested — DM me and I'll share the link.&lt;/p&gt;

</description>
      <category>selfhosting</category>
      <category>docker</category>
      <category>devops</category>
      <category>linux</category>
    </item>
    <item>
      <title>10 n8n workflow templates I actually use daily — sharing the JSON files</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:41:11 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/10-n8n-workflow-templates-i-actually-use-daily-sharing-the-json-files-p72</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/10-n8n-workflow-templates-i-actually-use-daily-sharing-the-json-files-p72</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally written for r/n8n on Reddit — sharing here for the dev.to community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I see a lot of n8n templates shared here that are either half-baked or broken. After going through my own production workflows, I picked the 10 I genuinely use every day and cleaned them up to share.&lt;/p&gt;

&lt;p&gt;These run on my self-hosted n8n instance (Docker, single Hetzner VPS). Zero cloud dependencies. Each template is a single JSON file you can import directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 1: Smart Email Auto-Reply with Sentiment Analysis
&lt;/h2&gt;

&lt;p&gt;Routes incoming emails based on sentiment (positive → auto-reply, negative → flag for human, neutral → queue for later).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Smart Email Auto-Reply"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"pollTimes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"everyMinute"&lt;/span&gt;&lt;span class="p"&gt;}]},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IMAP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"imap.yourdomain.de"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;993&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ssl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"=inbox@yourdomain.de"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{$credentials.emailPassword}}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.emailReadImap"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Read Email"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-4o-mini"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Analyze the sentiment of this email. Reply with only one word: POSITIVE, NEGATIVE, or NEUTRAL.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;From: {{$json[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;from&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]}}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Subject: {{$json[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;subject&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]}}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Body: {{$json[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]}}"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@n8n/n8n-nodes-langchain.openAi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sentiment Analysis"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"value1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{$json.message.content}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"equals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POSITIVE"&lt;/span&gt;&lt;span class="p"&gt;}]}},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"value1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{$json.message.content}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"equals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NEGATIVE"&lt;/span&gt;&lt;span class="p"&gt;}]}}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.switch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Route by Sentiment"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fromEmail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hello@yourdomain.de"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"toEmail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{$node[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Read Email&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;].json[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;from&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Re: {{$node[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Read Email&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;].json[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;subject&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi,&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Thanks for your message! We'll get back to you within 24 hours.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Best regards"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.emailSend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Auto-Reply (Positive)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"webhookUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://discord.com/api/webhooks/YOUR_WEBHOOK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"⚠️ NEGATIVE EMAIL ALERT&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;From: {{$node[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Read Email&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;].json[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;from&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]}}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Subject: {{$node[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Read Email&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;].json[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;subject&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]}}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.discord"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alert (Negative)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Cut my email response time from 4 hours to 30 minutes. Negative emails go straight to my phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 2: Website DSGVO Compliance Scanner
&lt;/h2&gt;

&lt;p&gt;Scans any URL for common GDPR violations. I use this for client sites.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DSGVO Compliance Scanner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{$json.domain}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"responseFormat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.httpRequest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fetch Page"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Google Fonts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"value1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{$json.data}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contains"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fonts.googleapis.com"&lt;/span&gt;&lt;span class="p"&gt;}]}},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Google Analytics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"value1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{$json.data}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contains"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"google-analytics.com"&lt;/span&gt;&lt;span class="p"&gt;}]}},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"External Trackers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"value1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{$json.data}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contains"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"facebook.net/en_US/fbevents"&lt;/span&gt;&lt;span class="p"&gt;}]}},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Missing Impressum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"value1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{$json.data}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"notContains"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Impressum"&lt;/span&gt;&lt;span class="p"&gt;}]}}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.switch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Detect Violations"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same logic I use in my DSGVO Guard scanner (free at nevik.de/guard/ — no signup needed, just paste a URL).&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 3: Lead Qualification Pipeline
&lt;/h2&gt;

&lt;p&gt;Webhook → enrich with Clearbit → score with AI → add to CRM or reject.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 4: Automated Invoice Processor
&lt;/h2&gt;

&lt;p&gt;Monitors email for PDF invoices → extracts data with OCR → pushes to accounting spreadsheet → sends confirmation email.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 5: RSS to Multi-Channel Publisher
&lt;/h2&gt;

&lt;p&gt;Monitors RSS feeds → formats for each platform → queues posts for Twitter, LinkedIn, and Discord.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 6: Database Backup with Health Check
&lt;/h2&gt;

&lt;p&gt;Cron trigger → dump PostgreSQL → upload to S3-compatible storage → verify backup integrity → send status to Slack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 7: Customer Onboarding Sequence
&lt;/h2&gt;

&lt;p&gt;New Stripe payment → create accounts in 3 services → send welcome email → schedule follow-ups over 14 days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 8: API Health Monitor
&lt;/h2&gt;

&lt;p&gt;Every 5 minutes → hit all my API endpoints → measure response time → alert if &amp;gt;2s or down → log to Grafana.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 9: Social Listening Pipeline
&lt;/h2&gt;

&lt;p&gt;Search Reddit/HN for keywords → AI summarizes mentions → weekly digest to Notion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template 10: Error Aggregation &amp;amp; Smart Alerting
&lt;/h2&gt;

&lt;p&gt;Collects errors from all n8n workflows → deduplicates → groups by severity → sends one daily digest instead of 50 individual alerts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Results from Using These
&lt;/h2&gt;

&lt;p&gt;Since putting these workflows in production 6 months ago:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time saved:&lt;/strong&gt; ~15 hours/week on manual tasks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email response time:&lt;/strong&gt; 4 hours → 30 minutes avg&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DSGVO compliance checks:&lt;/strong&gt; 200+ websites scanned automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missed leads:&lt;/strong&gt; Down from ~30% to &amp;lt;5%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server monitoring:&lt;/strong&gt; 3 outages caught before users noticed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Use
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Download the JSON files (links below)&lt;/li&gt;
&lt;li&gt;In n8n: Menu → Import from File&lt;/li&gt;
&lt;li&gt;Update credentials (email, API keys, etc.)&lt;/li&gt;
&lt;li&gt;Activate the workflow&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first 3 templates above are embedded directly in this post. For all 10, I packaged them into a clean download with documentation.&lt;/p&gt;

&lt;p&gt;I also have more advanced versions of these templates (with error handling, retry logic, DSGVO compliance workflows for German businesses) in a template pack. DM me if interested — happy to share details.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>n8n</category>
      <category>workflow</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>GDPR compliance for web devs: A practical technical guide (2026 edition with code examples)</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:40:08 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/gdpr-compliance-for-web-devs-a-practical-technical-guide-2026-edition-with-code-examples-424p</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/gdpr-compliance-for-web-devs-a-practical-technical-guide-2026-edition-with-code-examples-424p</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally written for r/webdev on Reddit — sharing here for the dev.to community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'm a developer based in Germany. After getting hit with a €900 Abmahnung (warning letter) because a client's website loaded Google Fonts externally, I went deep down the GDPR/DSGVO compliance rabbit hole. Here's everything I learned, distilled into actionable technical steps.&lt;/p&gt;

&lt;p&gt;This is NOT legal advice. This IS what actually works in practice based on EU court rulings as of 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 5 Things That Will Get You Abmahn'd
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. External Google Fonts (Most Common)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; Loading &lt;code&gt;fonts.googleapis.com&lt;/code&gt; sends user IP to Google servers. The Munich court ruled this constitutes data processing without consent (LG München, 2022).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Self-host your fonts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Download Google Fonts locally&lt;/span&gt;
npx google-font-download &lt;span class="s2"&gt;"Inter:wght@400;600;700"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; ./fonts

&lt;span class="c"&gt;# Or use the google-webfonts-helper API&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://gwfh.mranftl.com/api/fonts/inter?subsets=latin"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.variants[] | .fontFiles[]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Before (ILLEGAL in EU) */&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&amp;amp;display=swap')&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* After (DSGVO compliant) */&lt;/span&gt;
&lt;span class="k"&gt;@font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Inter'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;font-display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'Inter Regular'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="sx"&gt;url('/fonts/inter-v12-latin-regular.woff2')&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'woff2'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;unicode-range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0000-00&lt;/span&gt;&lt;span class="n"&gt;FF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0131&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0152-0153&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use Vite or webpack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.js — self-host fonts instead of Google CDN&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;css&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;preprocessorOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;scss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;additionalData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`@use "src/styles/fonts" as *;`&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. No Cookie Consent Banner (or Non-Compliant One)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; The ePrivacy Directive requires consent before setting non-essential cookies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Implement a proper consent banner with granular controls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- DON'T: Load analytics before consent --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://www.google-analytics.com/analytics.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- DO: Conditional loading --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// Check consent state from localStorage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cookie-consent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Load analytics only after consent&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/js/analytics.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Self-hosted!&lt;/span&gt;
  &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Cookie consent banner logic&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setConsent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cookie-consent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cookie-consent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cookie-banner&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;loadAnalytics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;marketing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;loadMarketing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Missing or Incomplete Privacy Policy
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; Article 13/14 GDPR requires specific information about data processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Dynamic privacy policy that reflects actual data processing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// privacy-policy-data.js — Keep your privacy policy in sync with reality&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataProcessing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;essential&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;purpose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;24h&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;First-party&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_pa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;purpose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Page analytics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;13 months&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Self-hosted Matomo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;thirdPartyServices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hetzner&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;purpose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server hosting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Germany&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server logs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Stripe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;purpose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment processing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EU/US (SCCs)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;dataSubjectRights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rectification&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;erasure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;portability&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;restriction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;objection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Insecure Contact Forms
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; Forms that send data via email without encryption, or store data without consent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; DSGVO-compliant form handling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DSGVO-compliant form handler&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/contact&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;rateLimit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;windowMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;privacyConsent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Verify consent&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;privacyConsent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Privacy consent required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Log consent with timestamp&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO consent_log (email, purpose, timestamp, ip_hash) VALUES ($1, $2, NOW(), $3)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contact_form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;hashIP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Store inquiry with auto-deletion (Art. 5(1)(e) — storage limitation)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO inquiries (name, email, message, created_at, delete_after) VALUES ($1, $2, $3, NOW(), NOW() + INTERVAL &lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;30 days&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 4. Auto-delete old data (run as cron job)&lt;/span&gt;
  &lt;span class="c1"&gt;// DELETE FROM inquiries WHERE delete_after &amp;lt; NOW();&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Third-Party Scripts Loading Without Consent
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; Chat widgets, analytics, social media embeds, etc. loading before user consent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Consent-aware script loader.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// consent-loader.js&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConsentManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadConsent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;loadConsent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gdpr-consent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;onConsent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;grantConsent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_timestamp`&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gdpr-consent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ConsentManager&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Only load Intercom if user consents to support cookies&lt;/span&gt;
&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onConsent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;support&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Intercom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;boot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;app_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Only load analytics if user consents&lt;/span&gt;
&lt;span class="nx"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onConsent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;analytics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Use Matomo self-hosted instead of GA&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_paq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_paq&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;_paq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;trackPageView&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nx"&gt;_paq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;enableLinkTracking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Compliance Checklist
&lt;/h2&gt;

&lt;p&gt;Use this as a pre-launch checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] All fonts self-hosted (no Google Fonts CDN)&lt;/li&gt;
&lt;li&gt;[ ] Cookie consent banner with granular controls&lt;/li&gt;
&lt;li&gt;[ ] Analytics loads only after consent (use Matomo self-hosted)&lt;/li&gt;
&lt;li&gt;[ ] Privacy policy lists all data processing activities&lt;/li&gt;
&lt;li&gt;[ ] Contact forms log consent with timestamp&lt;/li&gt;
&lt;li&gt;[ ] Data auto-deletion after 30 days&lt;/li&gt;
&lt;li&gt;[ ] SSL/TLS on all pages&lt;/li&gt;
&lt;li&gt;[ ] No third-party scripts loading before consent&lt;/li&gt;
&lt;li&gt;[ ] Impressum with real contact info (for .de domains)&lt;/li&gt;
&lt;li&gt;[ ] Server located in EU (or proper SCCs in place)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Free Tool to Check Your Site
&lt;/h2&gt;

&lt;p&gt;I got tired of manually checking all these things, so I built a scanner. It's free, no signup:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;nevik.de/guard/&lt;/strong&gt; — Enter any URL and it checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;External resource loading (fonts, scripts, CDNs)&lt;/li&gt;
&lt;li&gt;Cookie consent status&lt;/li&gt;
&lt;li&gt;SSL/TLS configuration&lt;/li&gt;
&lt;li&gt;Missing legal pages (Impressum, Datenschutz)&lt;/li&gt;
&lt;li&gt;Third-party tracker detection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It found violations on 73% of German websites I tested, including some big ones.&lt;/p&gt;

&lt;p&gt;If anyone wants to go deeper, I wrote a complete DSGVO audit guide for developers with all the code above plus templates for privacy policies, consent banners, and data processing documentation. DM me for the link.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>privacy</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Kostenloser DSGVO-Scanner für eure Website — 73% der getesteten .de-Domains hatten Verstöße</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:39:44 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/kostenloser-dsgvo-scanner-fur-eure-website-73-der-getesteten-de-domains-hatten-verstosse-54e4</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/kostenloser-dsgvo-scanner-fur-eure-website-73-der-getesteten-de-domains-hatten-verstosse-54e4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally written for r/de on Reddit — sharing here for the dev.to community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Moin zusammen,&lt;/p&gt;

&lt;p&gt;als Entwickler aus Deutschland habe ich in den letzten Monaten über 200 deutsche Websites auf DSGVO-Konformität gescannt. Das Ergebnis: &lt;strong&gt;73% hatten mindestens einen Verstoß&lt;/strong&gt;, der zu einer Abmahnung führen könnte.&lt;/p&gt;

&lt;p&gt;Deshalb habe ich einen kostenlosen Scanner gebaut, den jeder nutzen kann: &lt;strong&gt;nevik.de/guard/&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kein Account, keine Anmeldung, einfach URL eingeben und Ergebnis sehen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Was der Scanner prüft
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Fonts:&lt;/strong&gt; Werden noch externe Fonts von Google geladen? (LG München Urteil — Abmahnrisiko €500-2000)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie Consent:&lt;/strong&gt; Ist ein Cookie-Banner vorhanden und DSGVO-konform?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Externe Tracker:&lt;/strong&gt; Facebook Pixel, Google Analytics, Hotjar etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL/TLS:&lt;/strong&gt; Ist die Seite sicher erreichbar?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Impressum:&lt;/strong&gt; Vorhanden und vollständig?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Datenschutzerklärung:&lt;/strong&gt; Vorhanden?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-Standort:&lt;/strong&gt; Wo liegen die Daten? (EU oder DritLand)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Die häufigsten Verstöße (Top 5)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Google Fonts nachladen&lt;/strong&gt; (52% der Sites)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;❌ &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=..."&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
✅ Fonts lokal hosten — so geht's:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kurzer Fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fonts herunterladen&lt;/span&gt;
npx google-font-download &lt;span class="s2"&gt;"Inter:wght@400;700"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; ./fonts

&lt;span class="c"&gt;# In CSS referenzieren&lt;/span&gt;
@font-face &lt;span class="o"&gt;{&lt;/span&gt;
  font-family: &lt;span class="s1"&gt;'Inter'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  src: url&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/fonts/inter-regular.woff2'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; format&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'woff2'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Kein Cookie-Banner&lt;/strong&gt; (38% der Sites)&lt;br&gt;
Trotz Tracking-Pixels oder Analytics kein Consent-Tool installiert.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Google Analytics ohne Anpassung&lt;/strong&gt; (31%)&lt;br&gt;
Standard-GA4 ohne Server-Side Tagging oder IP-Anonymisierung.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Fehlendes Impressum&lt;/strong&gt; (19%)&lt;br&gt;
Besonders bei kleineren Projekten und Blogs oft vergessen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Kontaktformular ohne Datenschutzhinweis&lt;/strong&gt; (15%)&lt;br&gt;
"Mit dem Absenden stimmen Sie der Datenverarbeitung zu" fehlt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Warum ich das kostenlos anbiete
&lt;/h2&gt;

&lt;p&gt;Ich bin selbst als Freelancer tätig und habe erlebt, wie eine Abmahnung wegen Google Fonts €900 gekostet hat. Das muss nicht sein. Der Basis-Scan ist und bleibt kostenlos.&lt;/p&gt;

&lt;p&gt;Für Agenturen oder Unternehmen, die mehrere Domains überwachen wollen, gibt es eine Pro-Version mit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wiederkehrende Scans (täglich/wöchentlich)&lt;/li&gt;
&lt;li&gt;E-Mail-Benachrichtigungen bei neuen Verstößen&lt;/li&gt;
&lt;li&gt;PDF-Reports für Mandanten&lt;/li&gt;
&lt;li&gt;White-Label-Option&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Was ihr tun könnt
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Eigene Website scannen:&lt;/strong&gt; nevik.de/guard/ — 30 Sekunden, kostenlos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ergebnisse prüfen&lt;/strong&gt; und die obigen Fixes anwenden&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regelmäßig checken&lt;/strong&gt; — nach jedem Website-Update können neue Verstöße auftreten&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ich habe auch einen ausführlichen DSGVO-Leitfaden für Entwickler geschrieben, der alle technischen Details enthält (Code-Beispiele, Checklisten, Vorlagen). Bei Interesse schreibt mir eine DM.&lt;/p&gt;

&lt;p&gt;Falls ihr Fragen zu konkreten DSGVO-Problemen habt, fragt gerne hier — ich helfe wo ich kann.&lt;/p&gt;

</description>
      <category>germany</category>
      <category>privacy</category>
      <category>webdev</category>
      <category>security</category>
    </item>
  </channel>
</rss>
