Der Frame ist eine eigene Origin. Die eingebettete App kann weder DOM noch Cookies noch JavaScript des Partners lesen, und die Partnerseite nicht unsere. Das Host-Script hört auf einen festen Satz an Nachrichtentypen und ignoriert alles andere. Auf Marktplatz-Seite erlaubt die Content Security Policy das Framing nur von bekannten Partner-Domains.
Leistungen
Frontend-Architektur, Integrations-Engineering
Branche
B2B-Marktplatz
Jahr
2023-2024
Ein Marktplatz, der in den Websites seiner Partner läuft.
"Kann der ganze Marktplatz in unserer Seite leben?" Immobilienportale, Finanzberater und Branchenverzeichnisse stellten dieselbe Frage. Jeder wollte den kompletten Inserats-Flow auf der eigenen Domain, im eigenen Branding, und keiner wollte dafür ein Frontend bauen oder pflegen. Der Marktplatz selbst war ein Django-Monolith mit servergerenderten Templates.
DIE HERAUSFORDERUNG
Vier Arten, wie ein iframe kaputtgeht
Eine vollständige Anwendung in einem Frame auf einer fremden Seite bricht an vier Stellen. Der Frame hat eine feste Höhe, also läuft der Inhalt über oder zeigt eine zweite Scrollbar in der ersten. Ein Modal öffnet sich im Viewport des Frames, wird also abgeschnitten oder landet hinter dem Header des Partners. Safari und Firefox blockieren Drittanbieter-Cookies, die Django-Session kommt nie an, und die App weiß nicht, wer eingeloggt ist. Und die beiden Seiten teilen nichts: kein DOM, keinen JavaScript-Scope, keine Cookies. Die übliche Antwort ist eine API und ein Frontend, das der Partner baut. Für einen Marktplatz mit mehrstufigen Flows, serverseitiger Validierung, PDF-Erzeugung und dynamischer Preisbildung hätte das ein zweites Frontend bedeutet, das mit dem ersten synchron bleiben muss, auf jeder Partnerseite.
DIE LÖSUNG
Eine App, die weiß, dass sie in einem Frame steckt
Die Entscheidung: den Django-Monolithen behalten und ihm beibringen, seinen Container zu kennen. Eine Hilfsfunktion is_embedded_view() prüft auf einen embed-Parameter oder ein Session-Flag, und jedes Template erweitert dann _base_blank.html statt _base.html: dieselben Views und Formulare, ohne Navigation, Footer und Branding. Nur Views, die für Partner gedacht sind, tragen den Decorator xframe_options_exempt; überall sonst bleibt der Frame-Schutz an. Über die Origin-Grenze hinweg ist postMessage die einzige Brücke. Ein MutationObserver beobachtet das eingebettete Dokument auf Größenänderungen und schickt eine resize-Nachricht, gedrosselt auf eine pro 100 ms, und der Host setzt die Höhe mit einer CSS-Transition. Der Preis: Der Partner muss ein kurzes Script einbinden und einem festen Satz an Nachrichtentypen vertrauen. Die Alternative, ein eigenes einbettbares Frontend, hätte die zu pflegende Fläche verdoppelt.
Embed-Erkennung und Template-Umschaltung, einmal pro Request entschieden:
Python
def is_embedded_view(request):
"""Detect whether the current request is rendered inside an iframe."""
if request.GET.get('embed') == 'true':
request.session['is_embedded'] = True
return request.session.get('is_embedded', False)
def get_base_template(request):
"""Switch template inheritance based on embed mode."""
if is_embedded_view(request):
return '_base_blank.html' # stripped-down shell: content only
return '_base.html' # full chrome: nav, footer, branding
# In any view:
@xframe_options_exempt
def company_detail(request, slug):
base = get_base_template(request)
return render(request, 'company/detail.html', {
'base_template': base,
...
})Host und Embed im Gespräch
Die Seite links ist eine Partnerseite, der gestrichelte Kasten ist der iframe. Ändere Markenfarbe und Schriftgröße, einmal mit und einmal ohne Theme-Sync. Dann schalte die Höhenmeldung ab und navigiere im Embed: Die innere Scrollbar ist der Bug, den jeder Partner gemeldet hätte. Das Log zeigt jede Nachricht mit ihrer Payload.
Gewerbeimmobilien aus dem Marktplatz unseres Partners, gelistet auf unserer eigenen Domain.
postMessage-Log2
- Host → Embed+0.0s
theme:update{"brand":"#818cf8","fontSize":16} - Embed → Host+0.0s
ready{"path":"/listings"}
1 / 1Nachrichten, Embed → Host / Host → Embed
176 pxiframe-Höhe
176 pxEmbed-Inhalt
0 pxAbgeschnitten
Der Modal-Handshake, Embed-Seite und Host-Seite:
JavaScript
// Inside the embedded Django app
function openModal(modalEl) {
modalEl.classList.add('is-visible');
// Tell the parent page: "I need fullscreen"
const height = modalEl.offsetHeight;
window.parent.postMessage({
type: 'fullScreenOn',
modalHeight: height
}, '*');
}
function closeModal(modalEl) {
modalEl.classList.remove('is-visible');
// Tell the parent page: "Back to normal"
window.parent.postMessage({
type: 'fullScreenOff'
}, '*');
}
// --- On the partner site: ---
window.addEventListener('message', (event) => {
const iframe = document.getElementById('marketplace-embed');
if (event.data.type === 'fullScreenOn') {
iframe.style.height = event.data.modalHeight + 'px';
iframe.classList.add('fullscreen-overlay');
}
if (event.data.type === 'fullScreenOff') {
iframe.classList.remove('fullscreen-overlay');
iframe.style.height = ''; // back to auto-resize
}
});Sessions ohne Drittanbieter-Cookies
Das Django-Session-Cookie gehört zur Marktplatz-Domain, und ein Frame auf der Partner-Domain ist genau der Fall, in dem Safari und Firefox es nicht mitschicken. Der erste Embed-Request trägt den Session-Zustand deshalb als URL-Parameter, und im Frame wird der Session-Key als Fallback in localStorage gehalten. Logins überleben den Frame.
DAS ERGEBNIS
Aus einer Partner-Integration wurde Copy-Paste
Die Agentur eines Partners bettet den Marktplatz heute mit einem iframe-Tag und einem Script-Snippet ein; auf Partnerseite schreibt niemand gegen eine API oder baut ein Frontend. Das Marktplatz-Team pflegt einen Satz Templates und ein Deployment, und das Embed ist seit dem Launch so verfügbar wie die Plattform selbst.
WICHTIGE KENNZAHLEN
12+Partnerseiten live
99,9%Embed-Uptime
<2KBJS auf der Partnerseite
KUNDENSTIMME
"Ein neuer Partner schickt uns seine Markenfarben und bekommt einen iframe-Tag und ein Script-Snippet zurück. Seine Agentur hat den Marktplatz innerhalb einer Stunde auf der eigenen Domain laufen, und niemand auf seiner Seite muss gegen unsere API programmieren."
Product Owner
B2B-Marktplatz, Plattform-Integrationen
FÜR DEIN PROJEKT
- Wann es passt
Eine funktionierende Web-App, die Partner auf ihrer Domain wollen, in ihrem Branding, ohne ein Frontend zu bauen. Einbetten schlägt eine API, wenn die Flows mehrstufig und servergerendert sind: Der Partner bekommt jedes künftige Feature umsonst.
- Was du prüfen solltest
Welche Views überhaupt geframt werden dürfen, denn X-Frame-Options und CSP frame-ancestors sind pro View ein Opt-in, und ob dein Login ohne Drittanbieter-Cookies in Safari und Firefox überlebt. Teste das, bevor du einem Partner einen Termin versprichst.
- Was es braucht
Ein leeres Basis-Template, ein Host-Script von ein paar Dutzend Zeilen und ein Protokoll aus drei oder vier Nachrichtentypen. Plane die meiste Zeit für die Cookie-Übergabe und für Modals ein; der Höhenabgleich ist der einfache Teil.
FAQ
TECHNOLOGIE-STACK
Django
Python
JavaScript
Manuel Kasbarian - Geschäftsführer, SophistiXSeit mittlerweile 10 Jahren arbeiten wir immer wieder gerne mit Daniel zusammen. Wir schätzen dabei sehr seine schnellen Reaktionszeiten rund um die Uhr und sein Allroundwissen. Egal ob Serverkonfigurationen oder Programmierungen, er hat immer die passende Lösung.
Tritt in die Fußstapfen von Manuel und erwecke deine Vision zum Leben.
Frei für neue ProjekteSchreibe mir