Index: src/routes/posts.js
===================================================================
--- src/routes/posts.js	(revision 851239c078882db0b2674ad482985177b169bb8e)
+++ src/routes/posts.js	(revision 1907a18d87e0c381cc6c806cb4043835e2088adf)
@@ -398,4 +398,5 @@
   if (site.enable_audio_player !== 0) {
     html = AudioEmbedService.autoembed(html);
+    html = AudioEmbedService.embedMediaShortcodes(html);
     html = AudioEmbedService.embedExternalLinkShortcodes(html);
 
Index: src/services/AudioEmbedService.js
===================================================================
--- src/services/AudioEmbedService.js	(revision 851239c078882db0b2674ad482985177b169bb8e)
+++ src/services/AudioEmbedService.js	(revision 1907a18d87e0c381cc6c806cb4043835e2088adf)
@@ -187,4 +187,22 @@
       }
     );
+  }
+
+  /**
+   * Replace [[embed:<url>]] shortcodes met de platform-iframe (YouTube, Spotify,
+   * SoundCloud, Apple Music, Bandcamp, Vimeo). De editor-knop voegt deze
+   * shortcode in; losse URL-regels embedden ook automatisch via autoembed().
+   * Niet-ondersteunde/ongeldige URLs krijgen een nette inline-melding.
+   */
+  static embedMediaShortcodes(html) {
+    if (!html) return html;
+    return html.replace(/\[\[embed:([^\]]+)\]\]/gi, (match, rawUrl) => {
+      const url = rawUrl.trim().replace(/&amp;/g, '&');
+      const detected = this.detectProvider(url);
+      if (!detected) {
+        return `<div class="post-embed-missing"><em>Embed: niet-ondersteunde of ongeldige URL.</em></div>`;
+      }
+      return this.generateIframe(detected.provider, detected) || match;
+    });
   }
 
Index: src/views/pages/post-edit.ejs
===================================================================
--- src/views/pages/post-edit.ejs	(revision 851239c078882db0b2674ad482985177b169bb8e)
+++ src/views/pages/post-edit.ejs	(revision 1907a18d87e0c381cc6c806cb4043835e2088adf)
@@ -115,4 +115,7 @@
             <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="15" y2="18"/><polygon points="3 5 3 13 9 9"/></svg>
           </button>
+          <button type="button" id="insert-embed-btn" title="Embed (YouTube, Spotify, SoundCloud, Vimeo…)" aria-label="Media embedden">
+            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><polygon points="10 9 15.5 12 10 15"/></svg>
+          </button>
           <span class="pe-toolbar-spacer"></span>
           <button type="button" data-cmd="removeFormat" title="Wis opmaak" aria-label="Wis opmaak">
@@ -930,5 +933,5 @@
   // HTML attribute; since chipify only walks text nodes (never attribute
   // values) that's already safe.
-  const SC_RE = /\[\[(track|album|playlist):([^\]]+)\]\]/g;
+  const SC_RE = /\[\[(track|album|playlist|embed):([^\]]+)\]\]/g;
 
   const SC_ICONS = {
@@ -936,4 +939,5 @@
     album:    '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3"/></svg>',
     playlist: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="15" y2="18"/><polygon points="3 5 3 13 9 9"/></svg>',
+    embed:    '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><polygon points="10 9 15.5 12 10 15"/></svg>',
   };
 
@@ -946,4 +950,8 @@
     if (kind === 'album')    return 'Album: ' + value;
     if (kind === 'playlist') return 'Playlist: ' + value;
+    if (kind === 'embed') {
+      const clean = String(value || '').replace(/^https?:\/\/(www\.)?/, '');
+      return '▶ ' + (clean.length > 36 ? clean.slice(0, 34) + '…' : clean);
+    }
     return value;
   }
@@ -1157,4 +1165,17 @@
     }
     updateCharCount();
+  }
+
+  // ── Embed insert: plak een platform-URL -> [[embed:url]]-chip die server-side
+  //    een iframe wordt (YouTube/Spotify/SoundCloud/Vimeo/Apple Music/Bandcamp).
+  const embedBtn = document.getElementById('insert-embed-btn');
+  if (embedBtn) {
+    embedBtn.addEventListener('click', () => {
+      const raw = window.prompt('Plak een media-URL om in te sluiten\n(YouTube, Spotify, SoundCloud, Vimeo, Apple Music, Bandcamp):');
+      if (!raw) return;
+      const url = raw.trim();
+      if (!/^https?:\/\//i.test(url)) { alert('Geef een volledige URL (https://…).'); return; }
+      insertChip('embed', url);
+    });
   }
 
