Eine Sektion ist ein horizontaler Streifen einer Seite — der Hero, die Preistabelle, die FAQ — samt all ihren Blöcken. Normalerweise bekommst du Sektionen gratis mit, innerhalb von /v1/pages/:marker. Dieser Endpoint ist für die Momente, in denen du nur ein Stück willst und nicht die ganze Torte.
Wann eine Sektion die ganze Seite schlägt
Die ganze Seite zu holen bleibt der Standard, und für die meisten Seiten ist das richtig: ein Request, alles drin. Eine einzelne Sektion gewinnt in ein paar konkreten Situationen:
- Lazy Loading unterhalb des Folds. Die Seite ist lang, das Review-Karussell wohnt irgendwo beim vierten Scrollen, und die meisten Besucher kommen nie dort an. Hol die Seite mit
?emptyfür Titel und Meta-Tags, lade die Sektionen des ersten Screens per Marker und die schweren erst, wenn der Besucher in ihre Nähe scrollt. - Geteilte Sektionen. Der Footer, ein Newsletter-Streifen, ein Kontaktblock „Noch Fragen?“, der auf jeder Seite auftaucht. Pfleg ihn einmal im CRM und hol ihn per Marker, wo immer du ihn brauchst.
- Einen Teil aktualisieren. Ein clientseitiges Widget, das sich nur für eine Sektion interessiert — etwa ein Promo-Bereich, den du per Timer neu prüfst —, muss nicht jedes Mal die ganze Seite herunterladen.
Eine Sektion abrufen
/v1/sections/:markerhttps://back.sitecog.com/content/v1/sections/:marker
content. Die Form ist exakt dieselbe wie bei einer Sektion in der Seiten-Response, derselbe Rendering-Code funktioniert also für beide.Parameter
markerpathstringPflichthero oder reviews. Gleiche Regeln wie bei Seiten-Markern: lateinische Buchstaben, Ziffern und Unterstriche, 2–40 Zeichen, Groß-/Kleinschreibung zählt. Die Sektion wird allein über ihren Marker gefunden — einen Seiten-Parameter gibt es nicht —, also gib Sektionen, die du so abrufst, Marker, die sich auf anderen Seiten nicht wiederholen.langquerystringoptionalStandard: alle aktiven Sprachen?lang=en, ?lang=en,de oder ?lang=en&lang=de. Jeder Code muss eine aktive Sprache der Site sein, sonst bekommst du 400 unknown_lang. Siehe Sprachen & Fallbacks.emptyqueryflagoptionalStandard: auscontent — nur id, marker, name, index und show. Vorhanden = an: ?empty, ?empty=1, ?empty=true; aus mit 0 oder false. Praktisch für einen günstigen Check „ist diese Sektion überhaupt eingeschaltet?“, bevor du etwas Schweres lädst.x-crm-keyheaderstringPflicht?key= übergeben, wenn Header keine Option sind. Siehe Site-Keys.Beispiel-Request
curl "https://back.sitecog.com/content/v1/sections/reviews?lang=en" \
-H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"const res = await fetch('https://back.sitecog.com/content/v1/sections/reviews?lang=en', {
headers: { 'x-crm-key': 'pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40' },
});
if (!res.ok) throw new Error(`Content API: ${res.status}`);
const section = await res.json();
if (section.show) {
console.log(section.content.reviews_title.content.en); // "What people say"
}'use client';
import { useEffect, useRef, useState, type ReactNode } from 'react';
// Der Site-Key ist absichtlich öffentlich, im Browser ist er also okay
const KEY = process.env.NEXT_PUBLIC_CRM_KEY!;
export function LazySection({ marker, lang, render }: {
marker: string;
lang: string;
render: (section: any) => ReactNode;
}) {
const ref = useRef<HTMLDivElement>(null);
const [section, setSection] = useState<any>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const io = new IntersectionObserver(async ([entry]) => {
if (!entry.isIntersecting) return;
io.disconnect(); // nur einmal laden
const res = await fetch(`https://back.sitecog.com/content/v1/sections/${marker}?lang=${lang}`, {
headers: { 'x-crm-key': KEY },
});
if (res.ok) setSection(await res.json());
}, { rootMargin: '400px' }); // etwas früher starten, bevor sie sichtbar wird
io.observe(el);
return () => io.disconnect();
}, [marker, lang]);
return <div ref={ref}>{section?.show ? render(section) : null}</div>;
}Beispiel-Response
{
"id": 47,
"marker": "reviews",
"name": "Customer reviews",
"index": 4,
"show": true,
"content": {
"reviews_title": {
"id": 120,
"marker": "reviews_title",
"name": "Title",
"type": "text",
"multilang": true,
"updatedAt": "2026-09-21T11:02:15.000Z",
"content": { "en": "What people say" }
},
"reviews_list": {
"id": 121,
"marker": "reviews_list",
"name": "Reviews",
"type": "array",
"multilang": false,
"updatedAt": "2026-09-25T08:40:03.000Z",
"content": [
{
"author": { "en": "Maria, Berlin" },
"text": { "en": "Finally I can hear my podcast on the U-Bahn." },
"rating": 5
}
]
}
}
}Mit ?empty liefert derselbe Request nur den oberen Teil — praktisch, wenn du nur wissen willst, ob die Sektion eingeschaltet ist:
{
"id": 47,
"marker": "reviews",
"name": "Customer reviews",
"index": 4,
"show": true
}Felder der Response
idnumbermarkerstringnamestringindexnumbershowbooleancontent{ [blockMarker]: Block }?empty übergibst.content →
idnumbermarkerstringreviews_title.namestringtypestringtext, html, image, video, link, number, color, date, date_range, boolean, object, array. Bestimmt die Form von content.multilangbooleanupdatedAtstring (ISO 8601)contentdepends on type{ file } bei einem einzelnen Bild, ein Array von Einträgen bei array und so weiter. Alle Formen stehen auf der Seite Blocktypen.Das show-Flag: ausgeblendet ist nicht gelöscht
Die Redaktion kann eine Sektion im CRM ausschalten, ohne sie zu löschen — für eine saisonale Aktion, eine halb fertige FAQ oder einen Block, der noch auf die Rechtsabteilung wartet. Die API liefert so eine Sektion trotzdem, mit "show": false und ihrem kompletten Inhalt. Sie nicht zu rendern, ist der Job deines Templates:
const reviews = await getSection('reviews');
return (
<>
<Hero />
{reviews.show && <Reviews section={reviews} />}
</>
);Fehler
| Status | Body | Was passiert ist |
|---|---|---|
| 400 | {"message":"invalid_marker"} | Der Marker enthält Zeichen außerhalb von A–Z a–z 0–9 _ oder hat die falsche Länge. |
| 400 | {"message":"invalid_lang", …} | Ein Code in lang ist fehlerhaft (etwa english statt en). |
| 400 | {"message":"unknown_lang", …} | Eine Sprache in lang ist auf der Site nicht aktiv. Der Body listet die verfügbaren auf. |
| 401 | {"message":"invalid_key"} | Key fehlt, ist fehlerhaft oder wurde widerrufen. |
| 404 | {"message":"section_not_found"} | Keine Sektion mit diesem Marker auf dieser Site. Tippfehler? Anderer Site-Key? |
| 429 | {"message":"rate_limit_exceeded"} | Zu viele Requests in dieser Minute. Siehe Rate-Limits. |
Die vollständige Liste mit Lösungen findest du auf der Seite Fehler.