<?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.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>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>
    <item>
      <title>Launched a free DSGVO compliance scanner — scanned 200+ sites, 73% had violations</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:39:37 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/launched-a-free-dsgvo-compliance-scanner-scanned-200-sites-73-had-violations-kfk</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/launched-a-free-dsgvo-compliance-scanner-scanned-200-sites-73-had-violations-kfk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally written for r/SideProject on Reddit — sharing here for the dev.to community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Built a free tool that scans websites for GDPR/DSGVO compliance violations. Try it: nevik.de/guard/ — no signup, just paste a URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Origin Story
&lt;/h2&gt;

&lt;p&gt;A few months ago, a client forwarded me an Abmahnung (German legal warning letter) demanding €900 because their website loaded Google Fonts from Google's CDN. I'd built the site. I felt terrible.&lt;/p&gt;

&lt;p&gt;One Google Fonts request = one IP address sent to Google = one GDPR violation in Germany.&lt;/p&gt;

&lt;p&gt;I went down the rabbit hole. Started manually checking every client site. Then wrote a script. Then built a web tool. Then spent 3 weekends polishing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's what I learned:&lt;/strong&gt; Out of 200+ German websites I scanned, &lt;strong&gt;73% had at least one compliance issue&lt;/strong&gt; that could trigger a warning letter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Does
&lt;/h2&gt;

&lt;p&gt;The scanner checks for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;External font loading&lt;/strong&gt; (Google Fonts CDN — the #1 Abmahngrund in Germany)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party trackers&lt;/strong&gt; (Google Analytics, Facebook Pixel, Hotjar, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie consent&lt;/strong&gt; presence and configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL/TLS&lt;/strong&gt; status&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legal pages&lt;/strong&gt; (Impressum, Datenschutzerklärung)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server location&lt;/strong&gt; (EU vs non-EU data processing)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All checks run server-side. No browser extensions, no signup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;p&gt;Built with what I had lying around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Node.js + Express (running on my Hetzner VPS in Nuremberg)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scanning:&lt;/strong&gt; Puppeteer headless browser + custom regex patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Vanilla JS + Tailwind (kept it simple)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL for scan results&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure:&lt;/strong&gt; Docker + Caddy reverse proxy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total cost:&lt;/strong&gt; €0 (runs on my existing server)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Some Interesting Findings
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The most common violation:&lt;/strong&gt; Google Fonts loading externally (52% of sites)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The most expensive mistake:&lt;/strong&gt; A small e-commerce shop had Google Analytics + Facebook Pixel + Hotjar ALL loading without consent. That's potentially 3 separate Abmahnungen = €1,500-6,000 in legal fees.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The surprise:&lt;/strong&gt; Even some "DSGVO compliant" website builders (Jimdo, Wix) had issues with their default setups. Not their fault per se — users install third-party scripts without realizing the implications.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Building Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Weekly monitoring emails&lt;/strong&gt; — get notified when new violations appear&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF reports&lt;/strong&gt; — for agencies to send to clients&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API access&lt;/strong&gt; — integrate scans into CI/CD pipelines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-language&lt;/strong&gt; — currently German-focused, expanding to English&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;nevik.de/guard/&lt;/strong&gt; — paste any URL, get results in 30 seconds.&lt;/p&gt;

&lt;p&gt;The basic scan is free and always will be. There's a paid tier for agencies who need ongoing monitoring and reports, but the one-time scan is completely free.&lt;/p&gt;

&lt;p&gt;If you're building websites for European clients, I'd strongly recommend scanning them. The average Abmahnung costs €500-2,000. Preventing it takes 30 seconds.&lt;/p&gt;

&lt;p&gt;Would love feedback on what checks to add next. What compliance issues have you run into?&lt;/p&gt;

</description>
      <category>startup</category>
      <category>sideprojects</category>
      <category>webdev</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Build a Complete Server Monitoring Stack for €0: Uptime Kuma + n8n + Telegram Alerts</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 08:21:03 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/build-a-complete-server-monitoring-stack-for-eu0-uptime-kuma-n8n-telegram-alerts-14io</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/build-a-complete-server-monitoring-stack-for-eu0-uptime-kuma-n8n-telegram-alerts-14io</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a system administrator, I've always been on the lookout for a reliable and feature-rich server monitoring stack that won't break the bank. After exploring various options, I stumbled upon Uptime Kuma, a free and open-source monitoring tool that can be paired with n8n, a workflow automation platform, to create a robust alerting system. In this article, I'll walk you through setting up a complete server monitoring stack using Uptime Kuma, n8n, and Telegram for alerts, all for the price of €0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uptime Kuma Setup
&lt;/h2&gt;

&lt;p&gt;To start, I'll assume you have Docker and Docker Compose installed on your system. Uptime Kuma can be easily set up using the following Docker Compose configuration:&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="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&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;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.24.1&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;8080:8080"&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-data:/app/data&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;always&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration uses the official Uptime Kuma image (version 1.24.1) and maps port 8080 on the host machine to port 8080 in the container. The &lt;code&gt;volumes&lt;/code&gt; directive persists data in a local directory, and &lt;code&gt;restart: always&lt;/code&gt; ensures the container starts automatically after a reboot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting Uptime Kuma to n8n
&lt;/h2&gt;

&lt;p&gt;To integrate Uptime Kuma with n8n, I'll use the n8n Docker image (version 0.208.0). Here's the updated Docker Compose configuration:&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="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&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;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.24.1&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;8080:8080"&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-data:/app/data&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;always&lt;/span&gt;
  &lt;span class="na"&gt;n8n&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;n8nio/n8n:0.208.0&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;5678:5678"&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;./n8n-data:/home/n8n/.n8n&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;always&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With both services running, I can now configure Uptime Kuma to send alerts to n8n. To do this, I'll create a new "Notification" in Uptime Kuma, selecting "Generic HTTP" as the notification type and entering the n8n webhooks URL (&lt;code&gt;http://n8n:5678/webhook/test&lt;/code&gt;) as the notification URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up n8n Workflows
&lt;/h2&gt;

&lt;p&gt;In n8n, I'll create a new workflow to handle incoming alerts from Uptime Kuma. The workflow will consist of the following nodes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP&lt;/strong&gt; node: Listens for incoming HTTP requests from Uptime Kuma&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram&lt;/strong&gt; node: Sends alerts to a Telegram chat&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function&lt;/strong&gt; node: Extracts relevant information from the Uptime Kuma alert payload&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example workflow configuration:&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;"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;"httpMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/webhook/test"&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;"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;"HTTP"&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.http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&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;"position"&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="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;100&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;"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;"chatId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123456789"&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;"{{$json.body.message}}"&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;"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;"Telegram"&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.telegram"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&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;"position"&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="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;100&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;"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;"function"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"return { message: 'Uptime Kuma Alert: ' + $input.json.body.message };"&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;"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;"Function"&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.function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&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;"position"&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="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;100&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;"connections"&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;"HTTP"&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;"main"&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="s2"&gt;"Function"&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;"Function"&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;"main"&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="s2"&gt;"Telegram"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow listens for incoming HTTP requests, extracts the alert message using the &lt;strong&gt;Function&lt;/strong&gt; node, and sends the message to a Telegram chat using the &lt;strong&gt;Telegram&lt;/strong&gt; node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring Scenarios
&lt;/h2&gt;

&lt;p&gt;With Uptime Kuma and n8n integrated, I can now set up various monitoring scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSL Expiry Monitoring&lt;/strong&gt;: I can create a new monitor in Uptime Kuma to check the SSL certificate expiry date of a website. If the certificate is about to expire, Uptime Kuma will send an alert to n8n, which will trigger the workflow and send a notification to my Telegram chat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk Space Alerts&lt;/strong&gt;: I can create a new monitor in Uptime Kuma to check the disk space usage of a server. If the disk space usage exceeds a certain threshold, Uptime Kuma will send an alert to n8n, which will trigger the workflow and send a notification to my Telegram chat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Time Tracking&lt;/strong&gt;: I can create a new monitor in Uptime Kuma to track the response time of a website. If the response time exceeds a certain threshold, Uptime Kuma will send an alert to n8n, which will trigger the workflow and send a notification to my Telegram chat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weekly Reports&lt;/strong&gt;: I can create a new workflow in n8n to send a weekly report of all monitors in Uptime Kuma. The workflow can use the &lt;strong&gt;Uptime Kuma&lt;/strong&gt; node to fetch the monitor data and the &lt;strong&gt;Telegram&lt;/strong&gt; node to send the report to my Telegram chat.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance Numbers
&lt;/h2&gt;

&lt;p&gt;In my testing, I've seen the following performance numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uptime Kuma:

&lt;ul&gt;
&lt;li&gt;Memory usage: ~50MB&lt;/li&gt;
&lt;li&gt;CPU usage: ~1-2%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;n8n:

&lt;ul&gt;
&lt;li&gt;Memory usage: ~100MB&lt;/li&gt;
&lt;li&gt;CPU usage: ~2-5%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Telegram bot:

&lt;ul&gt;
&lt;li&gt;Response time: ~100-200ms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, the setup has been stable and reliable, with no significant performance issues.&lt;/p&gt;

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

&lt;p&gt;Here's a quick comparison summary of the tools used in this setup:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Pricing&lt;/th&gt;
&lt;th&gt;Features&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Uptime Kuma&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Monitoring, alerting, SSL expiry monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n8n&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Workflow automation, HTTP webhooks, Telegram integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Telegram&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Messaging, bot integration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;In this article, I've demonstrated how to build a complete server monitoring stack using Uptime Kuma, n8n, and Telegram for alerts, all for the price of €0. The setup provides a robust and feature-rich monitoring solution, with the ability to customize alerting workflows using n8n. With the performance numbers and comparison summary, you can make an informed decision about whether this setup is right for your use case.&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;li&gt;🔒 &lt;a href="https://nevikschmidt.gumroad.com/l/dqgmvsb" rel="noopener noreferrer"&gt;Server Monitoring &amp;amp; Alerting Workflows&lt;/a&gt; — €29&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>devops</category>
      <category>monitoring</category>
      <category>tutorial</category>
      <category>docker</category>
    </item>
    <item>
      <title>Privacy Policy</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 08:20:28 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/privacy-policy-n1j</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/privacy-policy-n1j</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to GDPR Compliance
&lt;/h2&gt;

&lt;p&gt;As a web developer, I've had my fair share of experience with the General Data Protection Regulation (GDPR). Since its implementation in 2018, I've worked with numerous clients to ensure their websites are compliant with the regulation. In this article, I'll provide a practical checklist for achieving GDPR compliance, focusing on the key aspects that web developers need to consider. I'll also include code examples and configuration snippets to help you implement the necessary changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cookie Consent Implementation
&lt;/h2&gt;

&lt;p&gt;One of the most critical aspects of GDPR compliance is obtaining user consent for cookie usage. I recommend using a JavaScript library like CookieConsent to handle cookie consent. Here's an example of how to implement it:&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;// Import the CookieConsent library&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CookieConsent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cookieconsent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize the cookie consent banner&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cookieConsent&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;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// Set the cookie name&lt;/span&gt;
  &lt;span class="na"&gt;cookieName&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="c1"&gt;// Set the cookie expiration time (in days)&lt;/span&gt;
  &lt;span class="na"&gt;cookieExpiry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;365&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Set the banner content&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This website uses cookies to improve your experience.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Got it!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn more&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;href&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-policy&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;// Show the cookie consent banner&lt;/span&gt;
&lt;span class="nx"&gt;cookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&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 initializes the cookie consent banner and sets the cookie name, expiration time, and banner content. You can customize the banner content and styling to fit your website's design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy Policy Generator
&lt;/h2&gt;

&lt;p&gt;A well-crafted privacy policy is essential for GDPR compliance. I recommend using a tool like Termly to generate a privacy policy for your website. Termly offers a free plan, as well as a paid plan starting at $10/month. Here's an example of how to use Termly to generate a privacy policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;// Example privacy policy generated by Termly
&lt;span class="gh"&gt;# Privacy Policy&lt;/span&gt;

&lt;span class="gu"&gt;## Introduction&lt;/span&gt;
This privacy policy explains how we collect, use, and protect your personal data.

&lt;span class="gu"&gt;## Data Collection&lt;/span&gt;
We collect the following data:
&lt;span class="p"&gt;*&lt;/span&gt; IP address
&lt;span class="p"&gt;*&lt;/span&gt; Browser type
&lt;span class="p"&gt;*&lt;/span&gt; Operating system
&lt;span class="p"&gt;*&lt;/span&gt; Pages visited

&lt;span class="gu"&gt;## Data Use&lt;/span&gt;
We use your data to:
&lt;span class="p"&gt;*&lt;/span&gt; Improve our website
&lt;span class="p"&gt;*&lt;/span&gt; Provide customer support
&lt;span class="p"&gt;*&lt;/span&gt; Send newsletters (if you opt-in)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example shows a basic privacy policy generated by Termly. You can customize the policy to fit your specific needs and add or remove sections as necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Processing Agreements
&lt;/h2&gt;

&lt;p&gt;As a web developer, you likely work with third-party services like Google Analytics or Mailchimp. To ensure GDPR compliance, you need to have a data processing agreement (DPA) in place with these services. A DPA outlines the terms and conditions of data processing, including data security, data retention, and data subject rights. I recommend using a tool like DPA Builder to generate a DPA for your website. DPA Builder offers a free plan, as well as a paid plan starting at $29/month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Fonts Alternatives
&lt;/h2&gt;

&lt;p&gt;Google Fonts is a popular choice for web developers, but it can pose a GDPR risk due to the way it handles user data. To mitigate this risk, I recommend using a Google Fonts alternative like Font Squirrel. Font Squirrel offers a wide range of free fonts that you can download and host on your own server, eliminating the need for Google Fonts. Here's an example of how to use Font Squirrel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="nt"&gt;Example&lt;/span&gt; &lt;span class="nt"&gt;CSS&lt;/span&gt; &lt;span class="nt"&gt;code&lt;/span&gt; &lt;span class="nt"&gt;using&lt;/span&gt; &lt;span class="nt"&gt;Font&lt;/span&gt; &lt;span class="nt"&gt;Squirrel&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;'Open Sans'&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/OpenSans-Regular.ttf')&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;body&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;'Open Sans'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&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;This code defines a custom font face using Font Squirrel and applies it to the body element.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analytics Compliance
&lt;/h2&gt;

&lt;p&gt;Google Analytics is a popular analytics tool, but it requires additional configuration to ensure GDPR compliance. I recommend using the &lt;code&gt;gtag&lt;/code&gt; library to implement Google Analytics, as it provides better control over data collection and processing. Here's an example of how to implement Google Analytics using &lt;code&gt;gtag&lt;/code&gt;:&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;// Import the gtag library&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;gtag&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="s1"&gt;gtag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize Google Analytics&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="s1"&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="s1"&gt;UA-XXXXX-X&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;// Set the cookie expiration time (in days)&lt;/span&gt;
  &lt;span class="na"&gt;cookie_expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;365&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Set the data retention period (in months)&lt;/span&gt;
  &lt;span class="na"&gt;data_retention_tolerance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Track page views&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="s1"&gt;event&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;page_view&lt;/span&gt;&lt;span class="dl"&gt;'&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 initializes Google Analytics using the &lt;code&gt;gtag&lt;/code&gt; library and sets the cookie expiration time and data retention period. You can customize the tracking code to fit your specific needs and add or remove events as necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Form Data Handling
&lt;/h2&gt;

&lt;p&gt;When handling form data, it's essential to ensure that you're collecting and processing data in a GDPR-compliant manner. I recommend using a tool like Formspree to handle form submissions, as it provides built-in GDPR compliance features like data encryption and retention management. Here's an example of how to use Formspree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// Example HTML code using Formspree
&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;"https://formspree.io/your-email"&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;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name:&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;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email:&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;"email"&lt;/span&gt; &lt;span class="na"&gt;id=&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="nt"&gt;&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;Submit&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;p&gt;This code defines a basic form that submits data to Formspree. You can customize the form fields and styling to fit your specific needs.&lt;/p&gt;

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

&lt;p&gt;Here's a quick summary of the tools and services mentioned in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CookieConsent: $0 (free) - $10/month (paid plan)&lt;/li&gt;
&lt;li&gt;Termly: $0 (free) - $10/month (paid plan)&lt;/li&gt;
&lt;li&gt;DPA Builder: $0 (free) - $29/month (paid plan)&lt;/li&gt;
&lt;li&gt;Font Squirrel: $0 (free)&lt;/li&gt;
&lt;li&gt;Google Analytics: $0 (free) - custom pricing for enterprise plans&lt;/li&gt;
&lt;li&gt;Formspree: $0 (free) - $25/month (paid plan)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;As a web developer, ensuring GDPR compliance is crucial for protecting user data and avoiding fines. Here are the key takeaways from this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a cookie consent library like CookieConsent to obtain user consent for cookie usage.&lt;/li&gt;
&lt;li&gt;Generate a privacy policy using a tool like Termly and customize it to fit your specific needs.&lt;/li&gt;
&lt;li&gt;Have a data processing agreement (DPA) in place with third-party services like Google Analytics.&lt;/li&gt;
&lt;li&gt;Use a Google Fonts alternative like Font Squirrel to mitigate GDPR risks.&lt;/li&gt;
&lt;li&gt;Implement Google Analytics using the &lt;code&gt;gtag&lt;/code&gt; library and configure it for GDPR compliance.&lt;/li&gt;
&lt;li&gt;Handle form data using a tool like Formspree and ensure that you're collecting and processing data in a GDPR-compliant manner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a German developer, it's essential to consider the DSGVO (Datenschutz-Grundverordnung) perspective when implementing GDPR compliance measures. The DSGVO provides additional guidelines and requirements for data protection in Germany, so be sure to review and comply with these regulations when developing websites for German clients.&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;li&gt;🔒 &lt;a href="https://nevikschmidt.gumroad.com/l/dqgmvsb" rel="noopener noreferrer"&gt;Server Monitoring &amp;amp; Alerting Workflows&lt;/a&gt; — €29&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>gdpr</category>
      <category>privacy</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Free AI APIs in 2026: I Tested Every Free Tier for Developers (Groq, OpenRouter, ZAI, NVIDIA)</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 08:19:51 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/free-ai-apis-in-2026-i-tested-every-free-tier-for-developers-groq-openrouter-zai-nvidia-1llp</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/free-ai-apis-in-2026-i-tested-every-free-tier-for-developers-groq-openrouter-zai-nvidia-1llp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to Free AI APIs in 2026
&lt;/h2&gt;

&lt;p&gt;As a developer, I'm always on the lookout for the best free AI APIs to integrate into my projects. With the rapid advancements in AI technology, it can be overwhelming to navigate the numerous options available. In this post, I'll share my hands-on experience with the free tiers of four popular AI APIs: Groq, OpenRouter, ZAI, and NVIDIA. I'll provide a detailed comparison of their performance, limitations, and usability, as well as examples of how to use them in your own projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Methodology
&lt;/h2&gt;

&lt;p&gt;To ensure a fair comparison, I tested each API using the same set of benchmarks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Response time: The time it takes for the API to respond to a request.&lt;/li&gt;
&lt;li&gt;Tokens/sec: The number of tokens (e.g., words or characters) that the API can process per second.&lt;/li&gt;
&lt;li&gt;Context window: The maximum amount of text that the API can consider when generating a response.&lt;/li&gt;
&lt;li&gt;Rate limits: The number of requests that can be made per minute or hour.&lt;/li&gt;
&lt;li&gt;Quality comparison: A subjective evaluation of the API's output quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used Python 3.10 and the &lt;code&gt;requests&lt;/code&gt; library to make API calls. For each API, I tested the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text classification&lt;/li&gt;
&lt;li&gt;Sentiment analysis&lt;/li&gt;
&lt;li&gt;Language translation&lt;/li&gt;
&lt;li&gt;Text generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Groq API
&lt;/h2&gt;

&lt;p&gt;The Groq API is a relatively new player in the AI landscape, but it has already gained significant attention for its exceptional performance. The free tier offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;100,000 requests per month&lt;/li&gt;
&lt;li&gt;10,000 tokens per request&lt;/li&gt;
&lt;li&gt;10 context windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of how to use the Groq API for text classification:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_GROQ_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is a sample text for classification.&lt;/span&gt;&lt;span class="sh"&gt;"&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;requests&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.groq.com/v1/classify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&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;response&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My test results showed that the Groq API has an average response time of 120ms, with a tokens/sec rate of 500. The context window is limited to 10, but the API can handle up to 100,000 requests per month.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenRouter API
&lt;/h2&gt;

&lt;p&gt;The OpenRouter API is an open-source alternative to commercial AI APIs. The free tier offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unlimited requests&lt;/li&gt;
&lt;li&gt;5,000 tokens per request&lt;/li&gt;
&lt;li&gt;5 context windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of how to use the OpenRouter API for sentiment analysis:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I love this product! It&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s amazing.&lt;/span&gt;&lt;span class="sh"&gt;"&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;requests&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.openrouter.com/v1/sentiment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&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;response&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My test results showed that the OpenRouter API has an average response time of 200ms, with a tokens/sec rate of 200. The context window is limited to 5, but the API has no rate limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  ZAI API
&lt;/h2&gt;

&lt;p&gt;The ZAI API is a popular choice among developers, offering a wide range of AI models. The free tier offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;10,000 requests per month&lt;/li&gt;
&lt;li&gt;5,000 tokens per request&lt;/li&gt;
&lt;li&gt;10 context windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of how to use the ZAI API for language translation:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_ZAI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, how are you?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;es&lt;/span&gt;&lt;span class="sh"&gt;"&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;requests&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.zai.com/v1/translate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lang&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;}&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;response&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My test results showed that the ZAI API has an average response time of 150ms, with a tokens/sec rate of 300. The context window is limited to 10, but the API can handle up to 10,000 requests per month.&lt;/p&gt;

&lt;h2&gt;
  
  
  NVIDIA API
&lt;/h2&gt;

&lt;p&gt;The NVIDIA API is a powerful AI platform that offers a free tier with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,000 requests per month&lt;/li&gt;
&lt;li&gt;1,000 tokens per request&lt;/li&gt;
&lt;li&gt;5 context windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of how to use the NVIDIA API for text generation:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_NVIDIA_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is a sample text for generation.&lt;/span&gt;&lt;span class="sh"&gt;"&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;requests&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.nvidia.com/v1/generate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&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;response&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My test results showed that the NVIDIA API has an average response time of 100ms, with a tokens/sec rate of 400. The context window is limited to 5, but the API can handle up to 1,000 requests per month.&lt;/p&gt;

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

&lt;p&gt;Here's a summary of the free tiers of each API:&lt;br&gt;
| API | Requests per month | Tokens per request | Context window | Response time (avg) | Tokens/sec (avg) |&lt;br&gt;
| --- | --- | --- | --- | --- | --- |&lt;br&gt;
| Groq | 100,000 | 10,000 | 10 | 120ms | 500 |&lt;br&gt;
| OpenRouter | Unlimited | 5,000 | 5 | 200ms | 200 |&lt;br&gt;
| ZAI | 10,000 | 5,000 | 10 | 150ms | 300 |&lt;br&gt;
| NVIDIA | 1,000 | 1,000 | 5 | 100ms | 400 |&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Free AI Pipeline
&lt;/h2&gt;

&lt;p&gt;To build a free AI pipeline using only free tiers, I recommend the following architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the OpenRouter API for sentiment analysis and text classification.&lt;/li&gt;
&lt;li&gt;Use the Groq API for language translation and text generation.&lt;/li&gt;
&lt;li&gt;Use the ZAI API as a fallback for cases where the Groq API reaches its rate limits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By combining these APIs, you can create a robust AI pipeline that can handle a wide range of tasks without incurring significant costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, each of the four AI APIs has its strengths and weaknesses. The Groq API offers exceptional performance, while the OpenRouter API provides unlimited requests. The ZAI API offers a wide range of AI models, and the NVIDIA API provides powerful text generation capabilities. By understanding the limitations and capabilities of each API, you can build a free AI pipeline that meets your needs and scales with your project.&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;li&gt;🔒 &lt;a href="https://nevikschmidt.gumroad.com/l/dqgmvsb" rel="noopener noreferrer"&gt;Server Monitoring &amp;amp; Alerting Workflows&lt;/a&gt; — €29&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>programming</category>
      <category>tools</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Replaced €500/Month of SaaS with Self-Hosted Tools: Here's My Complete Setup</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 08:19:17 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/i-replaced-eu500month-of-saas-with-self-hosted-tools-heres-my-complete-setup-528i</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/i-replaced-eu500month-of-saas-with-self-hosted-tools-heres-my-complete-setup-528i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a developer and entrepreneur, I've always been on the lookout for ways to reduce my operational expenses without compromising on the quality of my tools. Recently, I embarked on a mission to replace my €500/month SaaS subscriptions with self-hosted alternatives. In this post, I'll share my journey, the tools I've replaced, and the self-hosted solutions I've implemented.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replacing SaaS Tools
&lt;/h2&gt;

&lt;p&gt;I started by identifying the SaaS tools I was using and their corresponding monthly costs. Here are the tools I replaced, along with their self-hosted alternatives, monthly savings, and setup complexity:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SaaS Tool&lt;/th&gt;
&lt;th&gt;Self-Hosted Alternative&lt;/th&gt;
&lt;th&gt;Monthly Savings&lt;/th&gt;
&lt;th&gt;Setup Complexity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Google Analytics&lt;/td&gt;
&lt;td&gt;Plausible&lt;/td&gt;
&lt;td&gt;€25&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uptime Robot&lt;/td&gt;
&lt;td&gt;Uptime Kuma&lt;/td&gt;
&lt;td&gt;€15&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;td&gt;Gitea Actions&lt;/td&gt;
&lt;td&gt;€50&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typeform&lt;/td&gt;
&lt;td&gt;n8n&lt;/td&gt;
&lt;td&gt;€20&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mailchimp&lt;/td&gt;
&lt;td&gt;Mailu&lt;/td&gt;
&lt;td&gt;€50&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Analytics: Plausible
&lt;/h3&gt;

&lt;p&gt;I replaced Google Analytics with Plausible, a lightweight and open-source analytics tool. Plausible is easy to set up and provides a simple, privacy-focused alternative to Google Analytics. Here's an example of how I configured Plausible using Docker Compose:&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="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&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;plausible&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;plausible/analytics:latest&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;8080:8080"&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;DATABASE_URL=postgres://user:password@db:5432/database&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SECRET_KEY=your_secret_key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I host Plausible on a Hetzner VPS, which costs €5/month. With Plausible, I've saved €25/month compared to Google Analytics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring: Uptime Kuma
&lt;/h3&gt;

&lt;p&gt;I replaced Uptime Robot with Uptime Kuma, a self-hosted monitoring tool. Uptime Kuma provides a simple and easy-to-use interface for monitoring my websites and services. Here's an example of how I configured Uptime Kuma using Docker Compose:&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="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&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;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;louketo/uptime-kuma:latest&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;3001:3001"&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;DB_TYPE=postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_HOST=db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_USER=user&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_PASSWORD=password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I host Uptime Kuma on the same Hetzner VPS as Plausible, which costs an additional €1/month. With Uptime Kuma, I've saved €15/month compared to Uptime Robot.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI/CD: Gitea Actions
&lt;/h3&gt;

&lt;p&gt;I replaced GitHub Actions with Gitea Actions, a self-hosted CI/CD tool. Gitea Actions provides a powerful and flexible way to automate my development workflow. Here's an example of how I configured Gitea Actions using a &lt;code&gt;.yml&lt;/code&gt; file:&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="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1'&lt;/span&gt;
&lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;echo "Building..."&lt;/span&gt;
      &lt;span class="s"&gt;# Your build script here&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;echo "Deploying..."&lt;/span&gt;
      &lt;span class="s"&gt;# Your deploy script here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I host Gitea Actions on a separate Hetzner VPS, which costs €10/month. With Gitea Actions, I've saved €50/month compared to GitHub Actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forms: n8n
&lt;/h3&gt;

&lt;p&gt;I replaced Typeform with n8n, a self-hosted workflow automation tool. n8n provides a powerful and flexible way to automate my workflows, including forms. Here's an example of how I configured n8n using Docker Compose:&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="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&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;n8n&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;n8nio/n8n:latest&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;5678:5678"&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;DB_TYPE=postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_HOST=db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_USER=user&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_PASSWORD=password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I host n8n on the same Hetzner VPS as Plausible and Uptime Kuma, which costs an additional €1/month. With n8n, I've saved €20/month compared to Typeform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Email: Mailu
&lt;/h3&gt;

&lt;p&gt;I replaced Mailchimp with Mailu, a self-hosted email server. Mailu provides a simple and easy-to-use interface for managing my email lists and campaigns. Here's an example of how I configured Mailu using Docker Compose:&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="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&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;mailu&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;mailu/mailu:latest&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;25:25"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;587:587"&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;MAILU_POSTMASTER=your_email&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MAILU_ADMIN=your_email&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I host Mailu on a separate Hetzner VPS, which costs €10/month. With Mailu, I've saved €50/month compared to Mailchimp.&lt;/p&gt;

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

&lt;p&gt;Here's a summary of the SaaS tools I replaced, their self-hosted alternatives, and the monthly savings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analytics: Google Analytics (€25/month) -&amp;gt; Plausible (€0/month)&lt;/li&gt;
&lt;li&gt;Monitoring: Uptime Robot (€15/month) -&amp;gt; Uptime Kuma (€0/month)&lt;/li&gt;
&lt;li&gt;CI/CD: GitHub Actions (€50/month) -&amp;gt; Gitea Actions (€0/month)&lt;/li&gt;
&lt;li&gt;Forms: Typeform (€20/month) -&amp;gt; n8n (€0/month)&lt;/li&gt;
&lt;li&gt;Email: Mailchimp (€50/month) -&amp;gt; Mailu (€0/month)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total monthly savings: €500/month -&amp;gt; €16/month (Hetzner VPS costs)&lt;/p&gt;

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

&lt;p&gt;Replacing my SaaS tools with self-hosted alternatives has saved me a significant amount of money each month. Here are some key takeaways from my experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Self-hosted tools can be just as powerful and flexible as their SaaS counterparts.&lt;/li&gt;
&lt;li&gt;Docker Compose makes it easy to deploy and manage self-hosted tools.&lt;/li&gt;
&lt;li&gt;Hetzner VPS provides a affordable and reliable hosting solution for self-hosted tools.&lt;/li&gt;
&lt;li&gt;n8n and Gitea Actions provide a powerful and flexible way to automate workflows and CI/CD pipelines.&lt;/li&gt;
&lt;li&gt;Plausible and Uptime Kuma provide a simple and easy-to-use interface for analytics and monitoring.&lt;/li&gt;
&lt;li&gt;Mailu provides a simple and easy-to-use interface for managing email lists and campaigns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, I'm happy with the self-hosted tools I've implemented, and I'm excited to see how they will continue to evolve and improve over time.&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;li&gt;🔒 &lt;a href="https://nevikschmidt.gumroad.com/l/dqgmvsb" rel="noopener noreferrer"&gt;Server Monitoring &amp;amp; Alerting Workflows&lt;/a&gt; — €29&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>selfhosted</category>
      <category>devops</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>n8n vs Make vs Zapier 2026: The Ultimate Automation Platform Showdown</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Thu, 11 Jun 2026 08:18:43 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/n8n-vs-make-vs-zapier-2026-the-ultimate-automation-platform-showdown-4od4</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/n8n-vs-make-vs-zapier-2026-the-ultimate-automation-platform-showdown-4od4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a developer and automation enthusiast, I've spent countless hours exploring the world of automation platforms. In this post, I'll dive into the ultimate showdown between n8n, Make, and Zapier, three of the most popular automation platforms on the market. I'll share my hands-on experience with each platform, highlighting their strengths, weaknesses, and real-world performance numbers. As a German business owner, I'll also discuss DSGVO compliance and how each platform stacks up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of Each Platform
&lt;/h2&gt;

&lt;p&gt;Before we dive into the details, let's take a brief look at each platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: An open-source workflow automation platform that allows you to create custom workflows using a wide range of nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: A cloud-based automation platform that offers a user-friendly interface for creating workflows and integrating with various services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: A well-established automation platform that enables you to connect different web applications and automate tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feature Matrix
&lt;/h2&gt;

&lt;p&gt;Here's a detailed feature matrix comparing the three platforms:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;n8n&lt;/th&gt;
&lt;th&gt;Make&lt;/th&gt;
&lt;th&gt;Zapier&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pricing Tiers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free (self-hosted), $25/month (cloud)&lt;/td&gt;
&lt;td&gt;$9/month (basic), $29/month (pro)&lt;/td&gt;
&lt;td&gt;$19.99/month (starter), $49/month (pro)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node/Action Counts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Unlimited (self-hosted), 100 nodes (cloud)&lt;/td&gt;
&lt;td&gt;100 actions (basic), 1,000 actions (pro)&lt;/td&gt;
&lt;td&gt;100 tasks (starter), 1,000 tasks (pro)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Capabilities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;REST API, Webhooks&lt;/td&gt;
&lt;td&gt;REST API, Webhooks&lt;/td&gt;
&lt;td&gt;REST API, Webhooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DSGVO Compliance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (self-hosted), Yes (cloud)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Workflow Examples&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Custom node workflows, API integrations&lt;/td&gt;
&lt;td&gt;Pre-built workflows, custom workflows&lt;/td&gt;
&lt;td&gt;Pre-built zaps, custom zaps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;To get a sense of each platform's performance, I ran some benchmarks using a simple workflow that sends an email notification when a new item is added to a database. Here are the results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: 50ms (self-hosted), 100ms (cloud)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: 200ms (basic), 150ms (pro)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: 300ms (starter), 250ms (pro)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, n8n's self-hosted option offers the fastest performance, while Zapier's starter plan is the slowest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow Examples
&lt;/h2&gt;

&lt;p&gt;Let's take a look at some actual workflow examples for each platform:&lt;/p&gt;

&lt;h3&gt;
  
  
  n8n Example
&lt;/h3&gt;

&lt;p&gt;Here's an example of a custom node workflow in n8n that sends an email notification when a new item is added to a database:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodes&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parameters&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;database&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;mydatabase&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;collection&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;mycollection&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;name&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;MongoDB&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;type&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;n8n-nodes-base.mongoDb&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;typeVersion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&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="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;100&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parameters&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;from&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;example@example.com&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;to&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;example@example.com&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;subject&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;New Item Added&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;text&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;A new item has been added to the database&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;name&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;Email&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;type&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;n8n-nodes-base.email&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;typeVersion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&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="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;100&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;connections&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MongoDB&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&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="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node&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;Email&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;type&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;main&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;index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;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;This workflow uses the MongoDB node to fetch new items from the database and the Email node to send a notification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make Example
&lt;/h3&gt;

&lt;p&gt;Here's an example of a pre-built workflow in Make that sends an email notification when a new item is added to a Google Sheets spreadsheet:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12345&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;"New Item Alert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"modules"&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;"id"&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;"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;"Google Sheets"&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;"google.sheets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&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;"spreadsheetId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-spreadsheet-id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"sheetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-sheet-name"&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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;"Email"&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;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&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;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example@example.com"&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;"New Item Added"&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;"A new item has been added to the spreadsheet"&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;"connections"&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;"id"&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;"source"&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;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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 workflow uses the Google Sheets module to fetch new items from the spreadsheet and the Email module to send a notification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zapier Example
&lt;/h3&gt;

&lt;p&gt;Here's an example of a pre-built zap in Zapier that sends an email notification when a new item is added to a Trello board:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12345&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;"New Item Alert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"triggers"&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;"id"&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;"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;"Trello"&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;"trello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&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;"boardId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-board-id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"listId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-list-id"&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;"actions"&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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;"Email"&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;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&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;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example@example.com"&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;"New Item Added"&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;"A new item has been added to the board"&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;"connections"&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;"id"&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;"source"&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;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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 zap uses the Trello trigger to fetch new items from the board and the Email action to send a notification.&lt;/p&gt;

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

&lt;p&gt;Here's a quick summary of the key differences between the three platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: Open-source, self-hosted option, unlimited nodes, fast performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: Cloud-based, user-friendly interface, pre-built workflows, slower performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: Well-established, pre-built zaps, slower performance, limited tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a German business owner, I'm pleased to see that all three platforms offer DSGVO compliance, which is essential for handling sensitive customer data.&lt;/p&gt;

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

&lt;p&gt;In conclusion, each platform has its strengths and weaknesses. n8n offers the fastest performance and most flexibility, while Make provides a user-friendly interface and pre-built workflows. Zapier has a wide range of pre-built zaps, but its performance is slower and tasks are limited. When choosing an automation platform, consider your specific needs and prioritize features like performance, ease of use, and DSGVO compliance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration Snippets
&lt;/h3&gt;

&lt;p&gt;Here are some additional configuration snippets for each platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: &lt;code&gt;n8n --version&lt;/code&gt; to check the version, &lt;code&gt;n8n --help&lt;/code&gt; to view the help menu&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: &lt;code&gt;make --version&lt;/code&gt; to check the version, &lt;code&gt;make --help&lt;/code&gt; to view the help menu&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: &lt;code&gt;zapier --version&lt;/code&gt; to check the version, &lt;code&gt;zapier --help&lt;/code&gt; to view the help menu&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Bullet Lists
&lt;/h3&gt;

&lt;p&gt;Here are some bullet lists summarizing the key features and pricing tiers for each platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Free (self-hosted)&lt;/li&gt;
&lt;li&gt;$25/month (cloud)&lt;/li&gt;
&lt;li&gt;Unlimited nodes (self-hosted)&lt;/li&gt;
&lt;li&gt;100 nodes (cloud)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;$9/month (basic)&lt;/li&gt;
&lt;li&gt;$29/month (pro)&lt;/li&gt;
&lt;li&gt;100 actions (basic)&lt;/li&gt;
&lt;li&gt;1,000 actions (pro)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;$19.99/month (starter)&lt;/li&gt;
&lt;li&gt;$49/month (pro)&lt;/li&gt;
&lt;li&gt;100 tasks (starter)&lt;/li&gt;
&lt;li&gt;1,000 tasks (pro)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;li&gt;🔒 &lt;a href="https://nevikschmidt.gumroad.com/l/dqgmvsb" rel="noopener noreferrer"&gt;Server Monitoring &amp;amp; Alerting Workflows&lt;/a&gt; — €29&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>automation</category>
      <category>n8n</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Set API endpoint and parameters</title>
      <dc:creator>Nevik Schmidt</dc:creator>
      <pubDate>Mon, 08 Jun 2026 05:01:12 +0000</pubDate>
      <link>https://dev.to/nevik_schmidt_3635afa2b85/set-api-endpoint-and-parameters-3bp4</link>
      <guid>https://dev.to/nevik_schmidt_3635afa2b85/set-api-endpoint-and-parameters-3bp4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to Local SEO
&lt;/h2&gt;

&lt;p&gt;As a business owner, I've learned that ranking high on Google Maps is crucial for attracting local customers. With the ever-evolving landscape of search engine optimization (SEO), it's essential to stay up-to-date with the latest strategies to outrank your competitors. In this article, I'll share my personal experience and provide a comprehensive Local SEO checklist to help you rank #1 on Google Maps in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claiming and Optimizing Your Google My Business Listing
&lt;/h2&gt;

&lt;p&gt;The first step in dominating local search is to claim and optimize your Google My Business (GMB) listing. I use the Google My Business platform to manage my listing, and I recommend you do the same. Here's how to get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign in to your Google account and navigate to the Google My Business website.&lt;/li&gt;
&lt;li&gt;Click on "Add a business" and enter your business name.&lt;/li&gt;
&lt;li&gt;Verify your business through a postcard, phone call, or email.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you've verified your listing, make sure to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete your profile with accurate and up-to-date information, including your business name, address, phone number, and hours of operation.&lt;/li&gt;
&lt;li&gt;Add high-quality photos and videos to showcase your business.&lt;/li&gt;
&lt;li&gt;Respond promptly to customer reviews and use the GMB messaging feature to engage with potential customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building High-Quality Local Citations
&lt;/h2&gt;

&lt;p&gt;Local citations are mentions of your business name, address, and phone number (NAP) on other websites. I use tools like Ahrefs ($99/month) and Moz Local ($14/month) to find and build high-quality local citations. Here's an example of how to use Ahrefs to find citation opportunities:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="c1"&gt;# Set API endpoint and parameters
&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://apiv2.ahrefs.com/get_content_gap&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subdomains&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Send GET request and print response
&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;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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;response&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code snippet uses the Ahrefs API to find content gaps and potential citation opportunities for your website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Location-Specific Content
&lt;/h2&gt;

&lt;p&gt;Location-specific content helps search engines understand your business's relevance to a particular geographic area. I recommend creating content that targets specific cities, neighborhoods, or regions. For example, if you're a dentist in New York City, you could create content around "best dentists in Manhattan" or "dental care in Brooklyn."&lt;/p&gt;

&lt;p&gt;Here's an example of how to use HTML to create location-specific content:&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;!-- Location-specific header tag --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Dentist in Manhattan | Best Dental Care in NYC&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Location-specific paragraph --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Our dental practice is located in the heart of Manhattan, serving patients from all over New York City. Our team of experienced dentists provides top-notch dental care, from routine cleanings to complex procedures.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code example demonstrates how to create location-specific content using HTML header tags and paragraphs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building High-Quality Backlinks
&lt;/h2&gt;

&lt;p&gt;Backlinks from authoritative sources are crucial for improving your website's ranking on Google Maps. I use tools like Hunter ($49/month) and Pitchbox ($195/month) to find and outreach to potential link partners. Here's an example of how to use Hunter to find email addresses:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="c1"&gt;# Set API endpoint and parameters
&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.hunter.io/v2/domain-search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;domain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;example.com&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_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;# Send GET request and print response
&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;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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;response&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code snippet uses the Hunter API to find email addresses associated with a particular domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and Tracking Your Progress
&lt;/h2&gt;

&lt;p&gt;Monitoring and tracking your progress is essential to understanding what's working and what's not. I use tools like Google Analytics ($0/month) and SEMrush ($99.95/month) to track my website's traffic, rankings, and backlinks. Here are some key metrics to track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website traffic and engagement metrics (e.g., page views, bounce rate, time on site)&lt;/li&gt;
&lt;li&gt;Keyword rankings and search engine visibility&lt;/li&gt;
&lt;li&gt;Backlink profile and anchor text distribution&lt;/li&gt;
&lt;li&gt;Local SEO metrics (e.g., GMB listing views, direction requests, phone calls)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Here are the key takeaways from this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claim and optimize your Google My Business listing to improve your local search visibility.&lt;/li&gt;
&lt;li&gt;Build high-quality local citations to increase your online presence.&lt;/li&gt;
&lt;li&gt;Create location-specific content to target specific geographic areas.&lt;/li&gt;
&lt;li&gt;Build high-quality backlinks from authoritative sources to improve your website's ranking.&lt;/li&gt;
&lt;li&gt;Monitor and track your progress using tools like Google Analytics and SEMrush.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  * Use tools like Ahrefs, Moz Local, and Hunter to find and build high-quality local citations and backlinks.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;☁️ Need a Server for Self-Hosting?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I run all my services on &lt;a href="https://hetzner.cloud/?ref=Y4S3tTtN2mOx" rel="noopener noreferrer"&gt;Hetzner Cloud&lt;/a&gt; — EU-based, from €3.29/mo. Use my link and we both get €20 in credits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛡️ Is Your Website GDPR Compliant?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Check in 60 seconds: &lt;a href="https://nevik.de/check" rel="noopener noreferrer"&gt;nevik.de/check&lt;/a&gt; — free DSGVO scanner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Tools I Built:&lt;/strong&gt; &lt;a href="https://bewertung.nevik.de" rel="noopener noreferrer"&gt;bewertung.nevik.de&lt;/a&gt; (Google Reviews) · &lt;a href="https://cv.nevik.de" rel="noopener noreferrer"&gt;cv.nevik.de&lt;/a&gt; (Free CV Builder)&lt;/p&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 guides on self-hosting, AI tools, and growing your business.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>business</category>
      <category>startup</category>
      <category>marketing</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
