Doku

Einblick SDK In-Page-Editing

Externe Sites registrieren, Framework-Support verstehen und Einblick In-Page-Editing integrieren, ohne SSR oder Host-Caching zu brechen.

sdkapicmseditingexternal-sites

Einblick In-Page-Editing

Öffne Systemeinstellungen → API, um External Sites zu registrieren, erlaubte Origins zu verwalten und den publishable site key für die In-Page-Editing-Runtime zu kopieren.

Framework-Support

  • @einblick/sdk ist framework-agnostisch. Nutze es für typisierte Reads, Schema-Generierung, Public-Command-Aufrufe und serverseitiges CMS-Fetching in jedem JavaScript- oder TypeScript-Stack.
  • @einblick/editor enthält framework-neutrale Bindings, inerte DOM-Attribute und die lazy geladene Browser-Runtime. Das Paket braucht das Data SDK nicht.
  • @einblick/editor/react liefert Provider und bearbeitbare Marker für Next.js, Remix, plain React und Astro-React-Islands. @einblick/editor/next liefert den App-Router-Boot.
  • @einblick/sdk/react bleibt der Ort für die datenbezogene EinblickImage-Komponente. SDK 0.x behält die bisherigen Editor-Symbole nur als veraltete Kompatibilitätskopien.
  • Die gehosteten Editing-Routen nutzen Protokoll 2 und behalten Protokoll 1 für ein Rolling-Deployment-Kompatibilitätsfenster. Neue Integrationen verwenden immer den proof-gebundenen Protokoll-2-Flow; Versionen außerhalb des aktuellen/vorherigen Fensters werden abgelehnt.

Typisierte Reads und Response-Formate

  • Collection-Reads unterstützen limit, cursor, sort, include, fields und locale. Für sort nutzt du komma-separierte Feldnamen und stellst bei absteigender Sortierung ein - vor das Feld. Ohne explizites sort folgen CMS-Collections der in Einblick gepflegten manuellen Reihenfolge, und jeder Record liefert diesen Wert als sort in den Record-Metadaten mit.
  • Nutze fields: ['title', 'thumbnail'] bei Collection-, Singleton- oder Record-Reads, um nur die lesbaren Attribute zu laden, die eine Seite braucht. Generierte Clients typisieren das Array auf die lesbaren Feldschlüssel der Ressource; komma-separierte Strings funktionieren ebenfalls. Unbekannte oder nicht lesbare Felder liefern 400.
  • Für lokalisierte native Ressourcen akzeptiert locale einen Sprach-Tag oder eine geordnete Zeichenfolge im Stil von Accept-Language. Lokalisierte eingebaute und benutzerdefinierte Textfelder fallen über Workspace- und Quellsprache zurück; ohne locale bleiben die gespeicherten Quellwerte erhalten.
  • Relation-Includes funktionieren nur für lesbare Relationsfelder und nur dann, wenn derselbe API-Schlüssel auch Zugriff auf die verknüpfte Collection hat. Eingeschlossene Records kommen in included zurück.
  • CMS-richtext-Werte werden als strukturierte Dokument-JSON zurückgegeben, nicht als bereits abgeflachte HTML-Ausgabe.
  • Asset-Payloads liefern stabile URLs sowie optionale width, height, title, copyright, description, tags und sort. Wenn zu einem CMS-Video eine Web-Playback-Variante erzeugt wurde, zeigt die öffentliche Asset-URL auf diese browser-kompatible MP4- oder WebM-Datei. Browser-Anfragen mit Origin-Header werden für nicht transformierte Dateien mit CORS-Headern und Range-Support geproxyt; serverseitige Anfragen ohne Origin-Header können kurzlebigen Storage-Redirects folgen.
  • Gemeinsame Fetch-Einstellungen wie cache und next.revalidate legst du im requestInit des Clients ab. Einstellungen in fetch.next pro Request werden mit diesen Standards zusammengeführt; ressourcenspezifische next.tags verwerfen daher nicht das gemeinsame Revalidierungsintervall.

Bild-Asset-Transformationen

Mit getEinblickAssetUrl(asset, transform) leitest du aus der stabilen Asset-URL eine Bildvariante ab. Alternativ übergibst du den Namen eines Transform-Presets aus dem Asset-Payload.

import { getEinblickAssetUrl } from '@einblick/sdk'
 
const socialImage = getEinblickAssetUrl(asset, {
  width: 1200,
  height: 630,
  fit: 'cover',
  quality: 82,
  format: 'webp',
})
  • Eine Transformation nutzt width, height, fit, quality und format; daraus werden die URL-Parameter w, h, fit, q und fmt. Explizite Größen und Qualität werden nicht auf eine feste Leiter gerundet. Die Auslieferung begrenzt jede Kante auf 12.000 Pixel und die Qualität auf 1–100; ein Breite-Höhe-Paar über 100 Megapixel wird proportional verkleinert.
  • Unterstützte Fit-Modi sind scale-down, contain, cover, crop, pad, squeeze und scale-up. Das SDK akzeptiert außerdem fill als squeeze sowie inside oder outside als contain.
  • Unterstützte Formate sind auto, webp, avif, jpeg, baseline-jpeg, png und png-force; das SDK akzeptiert jpg als jpeg. png ist eine Präferenz und kann eine JPEG-Quelle als JPEG belassen, während png-force eine PNG-Ausgabe garantiert.
  • Jede unterschiedliche Kombination aus Quelle und Parametern kann eine weitere ausgelieferte Variante erzeugen. Wenn Größen aus beliebigen Layout-Messungen stammen, rufst du snapEinblickAssetTransform(...) ausdrücklich auf, um die Variantenmenge zu begrenzen. Bei next/image erfüllt eine kurze deviceSizes-Liste meist denselben Zweck.

Resource-Writes

  • Nutze client.createResource(...), client.updateResource(...) und client.deleteResource(...) für die Standard-Resource-API. CMS-Ressourcen liegen unter /api/v1/cms/{slug}; native Ressourcen liegen unter /api/v1/{slug}.
  • Resource-Writes brauchen eine passende Resource-Write-Freigabe am API-Schlüssel sowie schreibbare Felder für Create- und Update-Payloads. CMS-Ressourcen unterstützen Create, Update und Delete. Native Resource-Writes unterstützen aktuell Gebäude, Events und Festivals; native Deletes archivieren den Datensatz.
  • Übergib für wiederholbare Resource-Writes einen idempotencyKey. Wird derselbe Key für dieselbe Route und denselben Payload erneut genutzt, kommt das gespeicherte Ergebnis zurück; bei anderem Payload gibt es einen Konflikt.

Public Commands

  • Public Commands sind von Resource-Reads getrennt und brauchen explizite Write-Action-Freigaben auf dem API-Schlüssel.
  • Mit client.getCommandSchema() prüfst du, welche Commands für den aktuellen Token verfügbar sind.
  • Nutze client.command(name, input) oder typisierte Helfer wie client.jobs.submitApplication(...) für freigegebene Actions. Für wiederholbare Submit-Aufrufe kannst du einen idempotencyKey mitgeben.
  • Newsletter-Anmeldungen sind über client.newsletter.signup(...) verfügbar, wenn der Schlüssel newsletters.signup freigibt. Der Aufruf erstellt oder aktualisiert einen Kontakt, kann veröffentlichte Kontaktgruppen-Slugs anwenden und liefert je nach Workspace-Einstellung subscribed oder pending_confirmation.

Was die Runtime macht

  • Anonyme Besucher behalten das normale SSR-, Caching- und Performance-Verhalten der externen Site.
  • Angemeldete Editor*innen erhalten Hover-Indikatoren, Inline-Bearbeitung für einfache Felder und einen gehosteten Drawer für komplexere Felder.
  • Der publishable site key identifiziert nur die registrierte Site und Origin. Nach dem Sign-in nutzen Navigator und Saves die normalen Einblick-Rollenrechte der angemeldeten Person im Workspace; Browser-Editing nutzt keinen geheimen API-Schlüssel und keine API-Key-Resource-Freigaben.
  • Standardmäßig zeigt der authentifizierte Edit-Modus unten eine fixe Einblick-Kontrollleiste mit verbundener Site, einem allgemeinen Sammlungen-Button und einem Mehr-Menü für Einblick-Öffnen oder Logout. Mit chrome="badge" nutzt du den bisherigen Launcher; mit chrome="none" stellt die Host-Site eine eigene Oberfläche bereit.
  • Nutze accentColor am EinblickEditProvider, wenn das Standard-Orange auf einer Host-Site nicht genug Kontrast hat. Die Farbe ersetzt SDK-eigenes Orange in Hover-Outlines, Quick-Edit-Buttons, Badge-Chrome und der unteren Kontrollleiste. EinblickNextEditBoot reicht denselben Prop weiter und kann NEXT_PUBLIC_EINBLICK_ACCENT_COLOR lesen.
  • Das Collections-Panel erlaubt Suche über alle Ressourcen, die der External-Site-Session zur Verfügung stehen. CMS-Collections sind unter einem aufklappbaren CMS-Eintrag gruppiert; unterstützte native Ressourcen stehen auf derselben Ebene wie diese Gruppe. Editor*innen können verschachtelte CMS-Collections auf- und zuklappen, die passende Ressource in Einblick öffnen, bestehende Records im gehosteten Drawer bearbeiten oder löschen und Records direkt von der Host-Site erstellen. Native Drawer-Bearbeitung nutzt aktuell die normalen Einblick-Formulare für Gebäude, Events und Festivals. Die Suche klappt passende Zweige auf, damit Treffer in Unter-Collections erreichbar bleiben. Record-Labels nutzen das konfigurierte Display-Feld, wenn es vorhanden ist, und fallen sonst auf title, name, headline, ein anderes anzeigbares Feld, den Slug oder ein generisches Record-Label zurück. Singleton-Ressourcen zeigen die Erstellen-Aktion nur, solange noch kein Record existiert.
  • Editor*innen können CMS-Records im Collections-Panel über den Drag-Handle umsortieren, solange Sortierung für die Collection nicht deaktiviert ist.
  • Umschließe gerenderte Listenflächen mit EditableCollection und einem createEditableCollectionBinding({ resourceSlug })-Binding, wenn eine Fläche mehrere Records rendert. Setze showCreateButton am EditableCollection, wenn diese Fläche im Edit-Modus einen Eintrag hinzufügen-Button am Listenende rendern soll, der den gehosteten Drawer direkt im Erstellmodus öffnet. Lege item-bezogene EditableRegion-Bindings innerhalb dieses Wrappers an, damit jeder Record seinen eigenen Hover-Bearbeitungszustand behält.
  • Im gehosteten Drawer können Editor*innen mehrwertige files- und tags-Felder umsortieren. Gespeicherte files-Arrays behalten diese Reihenfolge in SDK- und Public-API-Antworten.
  • Relationsfelder und mehrwertige Relationsfelder im gehosteten Drawer laden auswählbare Records über die aktuelle Edit-Session und bleiben auf die im Feld konfigurierte Ziel-Collection begrenzt. Der Picker nutzt das Display-Feld der Ziel-Collection für Labels, liefert aktuell bis zu 100 Datensätze aus demselben Workspace, und Editor*innen können verknüpfte Records direkt daraus erstellen oder bearbeiten, ohne separat ins CMS zu wechseln. Wenn beim Erstellen in der Ziel-Collection ein Relationsfeld zurück zur aktuellen Collection existiert, füllt Einblick diese Rückreferenz vor.
  • Feldbezogene Saves patchen aktuell sichtbare textartige Bindings sofort.
  • Einwertige Bild- und Datei-Bindings können Medien direkt aus dem externen Editor hochladen und ersetzen. Mehrwertige images- und files-Felder öffnen stattdessen den gehosteten Drawer, damit Editor*innen die ganze Liste sehen, Dateien hinzufügen oder entfernen und sie, wo unterstützt, umsortieren können. CMS-Bildfelder akzeptieren Bilder; CMS-file- und files-Felder können erlaubte MIME-Typen und maximale Dateigröße begrenzen. Generische CMS-Dateifelder starten mit 500 MB; die Obergrenze ist die normale 5-GB-Grenze pro Upload angemeldeter Benutzer*innen.
  • Der Refresh-/Refetch-Pfad der Host-Site über onSave bleibt nötig, wenn die gerenderte Seite von aufgelösten Asset-URLs, SSR-Ausgabe oder gecachten Daten abhängt.

Login und Edit-Sessions

  • EinblickLoginButton und die Provider-Aktion login() öffnen die Anmeldung aus dem Klick der Benutzer*in. Die URL-Trigger ?einblick-login und ?login zeigen zuerst einen Hinweis auf der Host-Site; erst dessen Anmelden-Button öffnet das Popup. Damit bleibt das Öffnen an eine ausdrückliche Browser-Aktion gebunden.
  • Wird das Popup blockiert oder geschlossen oder endet der sichere Handshake nicht innerhalb von zwei Minuten, bleibt der Edit-Modus aus und die Host-Site erhält einen wiederholbaren Anmeldefehler. Ein blockiertes Popup löst keinen automatischen Full-Page-Redirect mehr aus.
  • Protokoll 2 verwendet einen kurzlebigen, proof-gebundenen Broker zwischen Host-Site, Einblick-Popup und eingebetteter Bridge. Der Edit-Session-Bearer wird innerhalb der Bridge übernommen und nie über URL oder Hash der Host-Site zurückgegeben.
  • Nach erfolgreicher Anmeldung schließt sich das Popup und der Editor aktiviert sich auf der aktuellen Seite.
  • Der Provider speichert die Edit-Session pro Site-Key auf dem aktuellen Gerät, damit Editor*innen auf derselben registrierten Origin weiterarbeiten können, bis die Session abläuft oder der Edit-Modus beendet wird.
  • Edit-Sessions sind an die Origin gebunden. Nutzt eine Site mehrere erlaubte Origins, ist auf jeder Origin ein eigener Sign-in nötig.

Was die Host-Site weiterhin verantwortet

  • Die Host-Site bleibt für serverseitige Reads, das Rendering der Seite und langlebige Cache-Layer verantwortlich. Geheime API-Schlüssel bleiben serverseitig für Reads und Code-Generierung; die Browser-Editing-Runtime nutzt nur den publishable site key und die Edit-Session.
  • Das SDK kann Teile des aktuell sichtbaren DOM sofort patchen, aber nicht automatisch framework-spezifische SSR-Caches, CDN-Caches oder Static-Generation-Outputs auf jedem Host invalidieren.
  • Für die beste Erfahrung verdrahte den onSave-Callback des Providers mit der Cache-Invalidierung plus dem kleinstmöglichen Refresh-/Refetch-Mechanismus, der frische Daten neu rendert. Der Callback läuft auch nach Creates und Deletes im gehosteten Drawer; gelöschte Records kommen mit value: null.
  • Die Standard-Kontrollleiste reserviert unten Body-Platz und setzt --einblick-editor-bottom-offset sowie data-einblick-editor-bar-active auf <html>. Verschiebe fixe Bottom-UI der Host-Site mit dieser Variable oder setze reserveBottomSpace={false}, wenn die Host-Site den Abstand selbst steuert.

Best Practices für Cache-Invalidierung

  • Wenn deine Site kein persistentes SSR- oder CDN-Caching nutzt, können textartige Feldänderungen und Inline-Medienersetzungen bereits sofort korrekt aussehen. Refreshe oder refetche nach dem Save trotzdem, wenn die Seite aufgelöste Asset-URLs oder gecachte Daten rendert.
  • Nutzt deine Site tag-basierte Daten-Caches, invalide den kleinsten Tag-Bereich, der die bearbeitete Ressource abdeckt.
  • Rendert deine Site Routen statisch, invalide zusätzlich den betroffenen Route-Output. Tags erneuern den Data-Cache; Pfade erneuern den prerendered Page- oder Layout-Cache.
  • Nutzt deine Site ein CDN oder Reverse-Proxy-Caching, purge den relevanten Cache-Key oder Pfad nach einem erfolgreichen Save.

Next.js

  • Halte CMS-Fetching auf dem Server.
  • Versehe Resource-Fetches mit next.tags, am besten über createEinblickCmsTags() aus @einblick/sdk/next/cache.
  • Stelle POST /api/einblick/revalidate mit createEinblickRevalidateHandler({ tags, secret }) bereit. Das Secret ist erforderlich, bleibt ausschließlich serverseitig und muss mit dem Token in den Einblick-External-Site-Einstellungen übereinstimmen. Für Route-Handler und Einblick-Webhooks nutze sofortige Expiration (revalidateTag(tag, { expire: 0 })); profile: "max" kann einmal stale Content ausliefern, bevor neu geladen wird.
  • Für statisch gerenderte App-Router-Seiten muss dieselbe Route auch betroffene Pfade invalidieren. Der SDK-Helper nutzt standardmäßig revalidatePath('/', 'layout'), ein robuster Default für kleine Sites. Größere Apps können eine engere paths-Map übergeben.
  • Montiere EinblickNextEditBoot im Root-Layout. Der Boot ruft nach Saves router.refresh() auf; die authentifizierte Einblick-Webhook-Anfrage übernimmt die serverseitige Cache-Invalidierung.
  • Lass in den External-Site-Einstellungen den Revalidierungs-Endpunkt auf /api/einblick/revalidate, damit direkte Änderungen in Einblick dieselben Tags invalidieren. Einblick sendet nach CMS-Create, -Update, -Delete, Umsortierung und Dateiänderungen aus dem externen Editor { resourceSlug } zusammen mit dem konfigurierten Secret.
// lib/einblick-cache.ts
import { createEinblickCmsTags } from '@einblick/sdk/next/cache'
 
export const einblickTags = createEinblickCmsTags({
  fanOut: { 'gedanken-sections': ['gedanken'] },
})
// app/api/einblick/revalidate/route.ts
import { createEinblickRevalidateHandler } from '@einblick/sdk/next/cache'
import { einblickTags } from '@/lib/einblick-cache'
 
export const POST = createEinblickRevalidateHandler({
  tags: einblickTags,
  secret: process.env.EINBLICK_REVALIDATE_SECRET,
  // Default: paths: [{ path: '/', type: 'layout' }]
})
// app/layout.tsx
import { EinblickNextEditBoot } from '@einblick/editor/next'
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html>
      <body>
        <EinblickNextEditBoot>{children}</EinblickNextEditBoot>
      </body>
    </html>
  )
}

Remix und Custom SSR

  • Halte CMS-Fetching auf dem Server oder in Loaders.
  • Invalidiere nach dem Save Loader-Daten, Route-Caches oder CDN-Caches im kleinstmöglichen Scope und triggere danach den kleinsten Refresh-/Refetch-Pfad, der frische Server-Daten neu rendert.
  • Wenn du clientseitige Query-Caches nutzt, triggere nach dem Save bei Bedarf zusätzlich ein Refetch.

Empfohlene Integrationsform

  1. Hole CMS- oder native Resource-Daten serverseitig mit @einblick/sdk.
  2. Mappe rohe Records in View-Models und halte Bindings aus @einblick/editor daneben vor.
  3. Umschließe CMS-basiertes Output mit EditableText, EditableImage oder EditableRegion. Für wiederholte Listen umschließt du die ganze Liste mit EditableCollection und legst item-bezogene Regions darin ab. Für native Records setzt du am Binding sourceType: 'native' und übergibst den nativen Resource-Slug plus Record-ID.
  4. Montiere EinblickEditProvider mit dem publishable site key und wähle die Standard-Kontrollleiste, chrome="badge" oder eine eigene Host-Oberfläche. Setze accentColor nur, wenn das Standard-Orange auf der Host-Site schwer zu sehen ist.
  5. Nutze EinblickLoginButton oder ?einblick-login / ?login als Einstieg in den Editor.
  6. Nutze onSave, um Caches zu revalidieren und den Refresh-/Refetch-Pfad der Host-Site anzustoßen, wenn die Seite Resource-Daten per SSR oder andere Caches liest.

Tipps zur Content-Modellierung

  • Nutze für Inhalte, die Editor*innen bearbeiten sollen, bevorzugt konkrete Feldtypen: string für Labels, text oder markdown für längere Texte, Medienfelder für Bilder/Dateien und verknüpfte Collections für wiederholbare Einträge. Vermeide json für Copy, CTA-Labels oder Textsegmente; das ist für nicht-technische Editor*innen schwer zu bearbeiten und Inline-Editing kann keine einzelnen JSON-Eigenschaften gezielt ansprechen.
  • Rendere ein vollständiges Quellfeld in genau einem Feld-Marker. Hänge dasselbe Binding nicht an Werte aus split, map, slice, [0], Auszüge oder Fallbacks. Rendere mehrzeiligen rohen text einmal mit erhaltenen Zeilenumbrüchen; vollständiges Markdown, Rich Text, semantische Absätze, Listen und Links gehören gemeinsam unter eine EditableRegion.
  • Wenn eine Host-Site nur einen Teil von Markdown rendert, bilde diese Regel im Host-Mapper ab. Eine Site kann zum Beispiel **fett** als hervorgehobenen Text ausgeben und alle anderen Markdown-Zeichen zu normalem Text glätten.
  • Lege beim Seeden oder Importieren von CMS-Medien jede Datei im Ordner des CMS Records ab, dessen Bild-/Dateifeld sie verwendet, oder in einem Collection-Ordner, der durch die Existing-File-Selection des Felds erlaubt ist. Die Public-API-Asset-Auflösung ist auf Ressource, Feld und erlaubte Ordnerwurzeln begrenzt; eine Datei-ID aus einem anderen Record kann deshalb für dieses Medienfeld als null zurückkommen.

Verwandte Doku