Ihre Extension erzeugt einen Text, schreibt ihn nach tt_content, und damit endet die Spur. Monate später soll jemand sagen, welche Absätze aus einem Modell stammen und welche von einem Menschen, und die ehrliche Antwort lautet: das weiß niemand mehr. Dieses Problem hat jede KI-Funktion in TYPO3, und ein weiteres Häkchen in einem weiteren Backend-Formular löst es nicht.
AI Label in AI Foundation löst es einmal, für alle Erweiterungen einer Installation. AI Foundation ist quelloffen unter GPL-2.0-or-later, Ihre Extension kann die Schnittstelle also heute nutzen. So funktioniert KI-Kennzeichnung in TYPO3-Extensions von Anfang bis Ende: ein Event-Listener, ein Aufruf beim Speichern, ein ViewHelper im Template. Das Beispiel arbeitet mit EXT:news, weil die bei den meisten von uns produktiv läuft.
Die Pflicht dahinter ist Artikel 50 der EU KI-Verordnung, gültig seit dem 2. August 2026. Den Rahmen behandeln wir im Beitrag zur EU KI-Verordnung für TYPO3, den Redaktionsalltag im Beitrag zur KI-Kennzeichnungspflicht in TYPO3. Dieser Beitrag richtet sich an die Person, die die Extension schreibt.
Was Ihre Extension von AI Label bekommt
Drei Dinge, und keines davon bauen Sie selbst. Ihre Extension bekommt einen Herkunftsnachweis am gerade gespeicherten Datensatz, einen Prüf- und Bestätigungsschritt für die Redaktion im AI-Label-Modul, und einen Besucherhinweis im Frontend, der aus dem bestätigten Zustand entsteht und die offiziellen Symbole der Europäischen Kommission verwendet. In einem Projekt mit Fluid Styled Content erscheint dieser Hinweis ganz ohne Template-Anpassung.
Sie schreiben das Mittelstück: die Zeile, die sagt "dieser Datensatz, jene Generierung". Alles links und rechts davon ist bereits da.
| Aufgabe | Wer sie trägt | Ihr Aufwand |
| Die Generierung speichern | AI Foundation, automatisch | Keiner, das passiert in der Service-Schicht |
| Generierung und Datensatz verknüpfen | Ihre Extension | Ein Aufruf dort, wo die UID feststeht |
| Datenbankspalten auf der eigenen Tabelle | AI Foundation | Ein Event-Listener und eine Datenbankanalyse |
| Redaktionelle Prüfung, Bestätigung, Regeln | AI Foundation | Keiner |
| Besucherhinweis samt Symbolen | AI Foundation | Eine Site-Set-Abhängigkeit oder ein ViewHelper |
| Nachweisexport für eine Prüfung | AI Foundation | Keiner |
Was Sie vorher brauchen
- AI Foundation installiert.
composer require nitsan/ns-t3af, danach aktivieren. Läuft auf TYPO3 v12 bis v14 mit PHP 8.2 oder neuer. Kostenlos und quelloffen, ohne Lizenzschlüssel, ohne Registrierung und ohne Domain-Limit, ausführlich im Beitrag zur kostenlosen KI-Erweiterung für TYPO3. - Eine Stelle, an der Ihre Extension KI-Ausgaben speichert.
pages,tt_contentundsys_file_metadatasind ab Werk vorgesehen. Für eine eigene Tabelle kommt ein Schritt dazu, siehe Schritt 1. - KI-Aufrufe über AI Foundation. Ruft Ihre Extension
AiServiceInterfaceauf, wird die Generierung für Sie erfasst und trägt eine Korrelations-ID. Ruft sie einen Anbieter direkt auf, funktioniert trotzdem alles, Sie nehmen dann Schritt 3 statt Schritt 2.
Hinweis: Für AI Label brauchen Sie keinen konfigurierten KI-Anbieter. Die Kennzeichnung läuft ohne, eine Installation kann also damit anfangen, bevor sie mit allem anderen anfängt.
Erfassen, verknüpfen, ausgeben: die drei Integrationspunkte
Erfassen passiert automatisch. Jede Generierung, die durch AI Foundation läuft, liegt in tx_nst3af_ailabel_generation, bevor Ihr Code das Ergebnis überhaupt sieht. Das ist Absicht und es ist die Entscheidung, die den Rest günstig macht: Die Erfassung sitzt in der Service-Schicht, in der die Generierung tatsächlich stattfindet, Datensatz und Generierung teilen sich eine Transaktion, und keine Extension muss daran denken, etwas zu melden.
Verknüpfen ist Ihre Aufgabe. Eine erfasste Generierung hängt noch an nichts, was ein Besucher sehen könnte. Nur Ihre Extension weiß, in welcher Datenbankzeile die Ausgabe gelandet ist, also kann auch nur sie diese Verbindung herstellen. Ein Aufruf, beim Speichern.
Die Ausgabe liest den bestätigten Zustand. Das Frontend fragt Ihre Extension nichts. Es liest die Spalten am Datensatz und die Einstellungen im Modul und entscheidet selbst, ob ein Hinweis fällig ist.
Warum das vor dem Code steht: Wenn Sie anfangen, an einem Dutzend Stellen Herkunft zu melden, sind Sie falsch abgebogen. Es gibt eine Stelle, und das ist die, an der Sie speichern.
Schritt 1: die eigene Tabelle registrieren
pages, tt_content und sys_file_metadata tragen die AI-Label-Spalten bereits. Ihre eigene Tabelle melden Sie über CollectApplicableTablesEvent an.
use NITSAN\NsT3AF\AiLabel\Event\CollectApplicableTablesEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;
#[AsEventListener]
final class RegisterNewsTableForAiLabel
{
public function __invoke(CollectApplicableTablesEvent $event): void
{
$event->addTable('tx_news_domain_model_news');
}
} Dasselbe geht ohne Code in AI Label, Einstellungen, anwendbare Tabellen oder über $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['ns_t3af']['ailabelApplicableTables']. Das Event nehmen Sie, wenn die Tabelle zu Ihrer Extension gehört und überall dort registriert sein soll, wo die Extension installiert ist.
AI Foundation steuert daraufhin die Spaltendefinitionen für diese Tabelle bei. Ihr Datensatz bekommt eigene Herkunftsfelder, darunter tx_nst3af_ailabel_involvement, tx_nst3af_ailabel_recording_source, tx_nst3af_ailabel_confirmed_by und tx_nst3af_ailabel_confirmed_at. Sie sind der Nachweis, und sie liegen am Datensatz statt in einer Nebentabelle. Genau deshalb bleiben sie beim Inhalt, auch durch eine Kopie, einen Workspace oder einen Export hindurch.
Hinweis: Nach dem Hinzufügen einer Tabelle führen Sie Wartung, Datenbankstruktur analysieren aus. Die Spalten kommen als Schema-Fragmente dazu, vorher existieren sie nicht, und jeder Aufruf aus Schritt 2 sieht aus, als hätte er stillschweigend nichts getan.
Schritt 2: die Generierung beim Speichern verknüpfen
Rufen Sie AiLabelBindHelper an der Stelle auf, an der die endgültige UID feststeht, also nachdem der DataHandler oder Ihr Repository gespeichert hat.
use NITSAN\NsT3AF\AiLabel\Service\AiLabelBindHelper;
// nach DataHandler oder Repository
AiLabelBindHelper::bindContentRecord($uid, 'my_extension');
AiLabelBindHelper::bindPageRecord($uid, 'my_extension');
AiLabelBindHelper::bindFileMetadata($metaUid, 'my_extension');
AiLabelBindHelper::bindRecord('tx_news_domain_model_news', $uid, 'my_extension'); Übergeben Sie Ihren eigenen Extension-Key als Quelle. Er wird als Erfassungsquelle gespeichert, er steht im Nachweisexport, den eine Prüfung zu sehen bekommt, und die Regeln zur automatischen Bestätigung im Modul greifen darauf zu. Ein beliebiger Wert kostet Sie heute nichts und den Betreiber später eine Erklärung.
Beide Fälle erledigt der Helper selbst. Liegt im aktuellen Request eine Korrelations-ID vor, verknüpft er die gespeicherte Generierung mit Ihrer Zeile. Liegt keine vor, etwa weil das Speichern in einem Folge-Request nach asynchroner Dateiverarbeitung passiert, schreibt er die Herkunft direkt. Sie brauchen dafür keine Fallunterscheidung.
Soll die Anbindung optional bleiben, sichern Sie sie ab. Eine Klassenprüfung genügt, damit Ihre Extension auch ohne AI Foundation weiterläuft.
if ($uid <= 0 || !class_exists(AiLabelBindHelper::class)) {
return;
}
AiLabelBindHelper::bindContentRecord($uid, 'my_extension'); Genau diese Prüfung verwendet unsere eigene Referenz-Extension. EXT:ns_t3af_extended auf GitHub ist ein öffentliches Repository, das jeden Integrationspunkt vorführt, und sein T3afExtendedAiLabelBinder ist diese Anleitung in zwanzig Zeilen, mit ns_t3af_extended als Erfassungsquelle. Sein MCP-Tool t3af_extended_summarize_content schreibt eine Zusammenfassung nach tt_content und verknüpft sie im selben Request. Schneller können Sie eine Verknüpfung im Modul nicht ankommen sehen, ohne selbst etwas zu schreiben.
Eine Falle, die einen Namen verdient. bindFileMetadata() kennt den Schalter altTextOnly. Setzen Sie ihn, wenn sich nur Metadatentexte geändert haben, also Alternativtext, Titel oder Beschreibung, und lassen Sie ihn weg, wenn die Datei selbst generiert wurde.
// Der Alternativtext wurde generiert. Das Foto nicht.
AiLabelBindHelper::bindFileMetadata($metaUid, 'my_extension', altTextOnly: true); Ein Foto, dessen Alternativtext ein Modell geschrieben hat, ist kein KI-generiertes Bild. Wer es trotzdem so stempelt, trifft eine Aussage über die eigene Redaktion, die nicht stimmt. Zu viel zu kennzeichnen ist ebenso eine Aussage wie zu wenig.
Schritt 3: Herkunft melden, wenn nichts erfasst wurde
Spricht Ihre Extension direkt mit einem Anbieter, gibt es keine Erfassung zum Verknüpfen. Dann melden Sie die Herkunft selbst über die öffentliche Schnittstelle.
use NITSAN\NsT3AF\AiLabel\Domain\Involvement;
use NITSAN\NsT3AF\Api\AiLabelRecorderInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
$recorder = GeneralUtility::makeInstance(AiLabelRecorderInterface::class);
$recorder->recordOrigin(
'tt_content',
$uid,
Involvement::AiGenerated,
'my_extension',
aiSystem: 'gpt-4',
aiVendor: 'openai',
); AiLabelRecorderInterface bringt außerdem drei Kurzwege mit, markGenerated(), markModified() und clearInvolvement(). Jeder von ihnen setzt die Bestätigung zurück, weil sich der Inhalt geändert hat. Alle drei werfen \InvalidArgumentException, wenn die Tabelle nicht registriert ist, und das ist der Fehler, den Sie sich wünschen: Eine nicht registrierte Tabelle ist ein Konfigurationsfehler und nichts, was man verschlucken sollte.
| Wert | Wann er gilt |
not_reviewed | Standard. Noch hat niemand aus der Redaktion entschieden |
no_ai | Die Redaktion stellt fest, dass keine KI beteiligt war |
ai_generated | Der Inhalt ist im Wesentlichen von einer KI erstellt |
ai_modified | Eine KI hat vorhandenen Inhalt verändert |
origin_unknown | Die Rolle der KI lässt sich nicht mehr feststellen |
suggestion | Das System hat erkannt oder vorgeschlagen, ein Mensch hat noch nicht geprüft |
Eine Verknüpfung aus einer Kind-Extension speichert immer ai_generated. Die Redaktion kann das später im Modul ändern, und das ist die richtige Richtung: Ihr Code meldet, was passiert ist, ein Mensch entscheidet, was es bedeutet.
Schritt 4: den Hinweis im eigenen Template ausgeben
In einem Projekt mit Fluid Styled Content sind der Hinweis am Inhaltselement und die Bild-Überlagerung bereits vorhanden, sobald das TypoScript geladen ist. Zu den ViewHelpern greifen Sie erst, wenn Sie Datensätze selbst ausgeben.
Das Site Set, ab TYPO3 v13.4
Nehmen Sie das Site Set in Ihr Sitepackage auf und importieren Sie sein Setup.
dependencies:
- nitsan/ns-t3af-label @import 'EXT:ns_t3af/Configuration/TypoScript/setup.typoscript' Der zweite Block ist nicht optional, und er ist der, der übersehen wird. Ein Site Set als Abhängigkeit zu führen lädt sein TypoScript nicht mit. Bei klassischen Templates binden Sie stattdessen das statische Template "AI Foundation labels" ein oder importieren dieselbe Datei.
Den Hinweis in Fluid ausgeben
Den Namensraum ail registriert AI Foundation, Ihr Template kann ihn also direkt verwenden.
<html xmlns:ail="http://typo3.org/ns/NITSAN/NsT3AF/AiLabel/ViewHelpers"
data-namespace-typo3-fluid="true">
<ail:label record="{data}" table="tt_content" />
<ail:label file="{file}" />
</html> Den Zustand lesen, statt ihn auszugeben
Wenn Sie den Zustand ohne fertiges Markup brauchen, weil Ihr Design den Hinweis an einer eigenen Stelle platziert, weisen Sie ihn zu und lesen ihn aus.
<ail:recordState record="{data}" table="tt_content" as="labelState" />
<f:if condition="{labelState.showLabel}">
<p class="ai-notice">{labelState.involvementKey}</p>
</f:if>
<ail:fileState file="{image}" as="labelState" /> Das Objekt trägt die Art der KI-Beteiligung, ob ein Mensch bestätigt hat, ob überhaupt ein Hinweis fällig ist, und den Grund für diese Entscheidung.
Derselbe Zustand aus TypoScript
Wer aus TypoScript statt aus einem Template heraus ausgibt, bekommt denselben Zustand über den DataProcessor-Alias nst3af-label.
tt_content {
dataProcessing {
1550 = nst3af-label
1550 {
as = labelState
}
}
} Was Ihr Code festhält, und was nur ein Mensch entscheiden kann
Achten Sie darauf, was in keinem der vier Schritte passiert ist: Keiner hat einem Besucher einen Hinweis angezeigt. Eine Verknüpfung hält Herkunft fest. Der Hinweis erscheint erst, wenn ein Mensch bestätigt, oder wenn eine Regel bestätigt, die der Betreiber dafür eingerichtet hat.
Diese Grenze ist keine Hürde, um die herum man entwickelt. Ein Hinweis auf einer veröffentlichten Seite ist eine Aussage über die Redaktion, die dahintersteht, und eine Extension ist nicht in der Lage, sie zu treffen. Wer die Website betreibt, ist im Sinne der Verordnung der Betreiber, und im Bestätigungsschritt sitzt genau diese Verantwortung. Ihre Aufgabe ist es, dafür zu sorgen, dass die bestätigende Person etwas Wahres vor sich hat.
AI Foundation stellt die technischen Voraussetzungen für Compliance bereit, ersetzt jedoch keine rechtliche Prüfung. Ob ein bestimmter Inhalt auf einer bestimmten Website eine Pflicht auslöst, gehen wir gern gemeinsam mit Ihnen durch, und es ist keine Frage, die ein ViewHelper beantwortet.
Was Open Source für Extension-Entwickler ändert
AI Foundation steht unter GPL-2.0-or-later, im TYPO3 Extension Repository und auf GitHub, gepflegt vom NITSAN-Team hinter T3Planet. Für die Anbindung oben heißt das ganz praktisch: Sie können die Klasse lesen, die Sie aufrufen, bevor Sie sie aufrufen. AiLabelBindHelper hat achtzig Zeilen. AiLabelRecorderInterface ist die gesamte öffentliche Oberfläche, in einer Datei. Die Unit-Tests zu AI Label liegen in Tests/Unit/AiLabel/, und sie sind der schnellste Weg herauszufinden, was eine Regel wirklich tut.
Es heißt außerdem, dass diese Schnittstelle keine private Abmachung zwischen unseren eigenen Erweiterungen ist. Jede TYPO3-Extension, die Inhalte erzeugt, kann Herkunft darüber melden, und eine Website mit drei solchen Erweiterungen bekommt eine Prüfansicht statt drei. Genau das würden wir am liebsten entstehen sehen. Es ist auch der Grund, warum die Schnittstelle ein veröffentlichter Vertrag ist und kein interner Service.
Wenn bei Ihrer Anbindung etwas fehlt, ist der Issue-Tracker von AI Foundation auf GitHub die richtige Adresse, und Pull Requests sind willkommen. Wer lieber vorher spricht: Die Erweiterung hat einen eigenen Kanal im TYPO3 Slack.
Häufige Fragen zur KI-Kennzeichnung in TYPO3-Extensions
Zum Verknüpfen ja, Ihr Code ruft deren Klassen auf. Schritt 2 zeigt die eine Zeile, die sie optional macht.
Es funktioniert trotzdem. Ihnen fehlt die automatische Erfassung, also nehmen Sie recordOrigin() aus Schritt 3 und übergeben System und Anbieter selbst.
pages, tt_content und sys_file_metadata ab Werk, dazu jede Tabelle, die Sie über CollectApplicableTablesEvent, den Einstellungen-Tab oder das EXTCONF-Array registrieren. Danach die Datenbankstruktur analysieren.
Nein. Die Verknüpfung hält die Herkunft fest. Für den Hinweis braucht es eine Bestätigung, aus der Redaktion oder aus einer Regel, die der Betreiber aktiviert hat.
Nein. Die Kennzeichnung läuft ohne.
TYPO3 v12 bis v14 mit PHP 8.2 oder neuer. Das Site Set aus Schritt 4 setzt v13.4 voraus, auf älteren Installationen binden Sie stattdessen das statische Template ein.
Jürgen Pietschmann
TYPO3 AI ConsultantJürgen Pietschmann ist T3Planet Product Consultant beim T3Planet Shop. Er ist auf die Integration von KI in redaktionelle Workflows spezialisiert – von intelligenter Content-Erstellung und automatisierter SEO bis hin zu KI-gestützter Suche und Chatbot-Lösungen für TYPO3-Websites. Als technischer Berater für das T3Planet AI Universe arbeitet er eng mit Agenturen und Redaktionsteams an praxisnahen TYPO3-Implementierungen. Jürgen schreibt seit Dezember 2025 die Reihe This Month in TYPO3 und war als Speaker bei der T3CON25 sowie den TYPO3 Developer Days 2026 (T3DD26) vertreten, wo er Content Editing Unlocked mitpräsentierte.
More From Author