AI Label integration
Integrate your TYPO3 extension with AI Foundation AI Label so AI-generated content is recorded, reviewable in the backend module, and labelled on the frontend when rules require it.
Prerequisites
- AI Foundation (
ns_) installedt3af - Your extension persists content on applicable tables (
pages,tt_,content sys_, or tables registered in AI Label settings)file_ metadata - AI requests go through AI Foundation (
Ai) so capture correlation ids are availableService Interface
Overview
Three integration points:
- Capture (automatic) — AI Foundation stores each generation in
tx_.nst3af_ ailabel_ generation - Bind (your code) — when you save a record, link the generation to that row.
- Optional direct origin — report involvement without a prior capture.
Applicable tables
Built-in:
pagestt_content sys_file_ metadata
Additional tables: add via AI Label → Settings → Applicable tables,
$GLOBALS,
or listen to Collect:
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');
}
}
Schema columns for extra tables are added by Applicable
as CREATE TABLE fragments. After changing extra tables, run
Maintenance → Analyze Database Structure so the columns exist.
Bind after save (recommended)
Use Ai at the point where your extension knows the final
record uid (after DataHandler or repository save):
use NITSAN\NsT3AF\AiLabel\Service\AiLabelBindHelper;
// After DataHandler / repository save — pass your extension key as $source
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');
Every child bind stores involvement ai_. Editors may change that
later in the AI Label module. Visitor badges still require confirmation.
Parameters:
$uid— live record uid (file metadata uid forbind)File Metadata $source— short extension identifier stored as recording source (use your extension key, for examplemy_)extension $alt(Text Only bindonly) — skip bind when only file metadata text changed (alt / title / description). Do not use this flag when the binary media itself was AI-generated (images, TTS audio). ns_t3aa metadata writes always passFile Metadata altso photos are not stamped as AI media when only accessibility text was generated.Text Only: true
If no capture correlation id is in the current request (for example a follow-up
HTTP request after async file processing), the helper writes origin with
record instead of bind.
Direct origin reporting
When capture correlation is unavailable:
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',
);
Public API interface: Classes/.
Convenience methods (also reset confirmation):
$recorder->markGenerated('tt_content', $uid, 'my_extension');
$recorder->markModified('tt_content', $uid, 'my_extension');
$recorder->clearInvolvement('tt_content', $uid, 'my_extension');
These throw \Invalid when $table is not an applicable
table.
Involvement values
| Value | Use when |
|---|---|
not_ | Default; no editor decision |
no_ | Editor asserts no AI involvement |
ai_ | Content substantially created by AI |
ai_ | AI changed existing content |
origin_ | Role of AI unclear |
suggestion | System detected/suggested; awaiting person |
Frontend rendering
Include the TypoScript that hooks into fluid_ (visitor badges
on content elements). Listing a Site Set as a dependency does not load its
TypoScript automatically — import the file as well.
Site Set (TYPO3 v13.4+): add nitsan/ to your sitepackage
set's dependencies, and import the setup:
dependencies:
- nitsan/ns-t3af-label
@import 'EXT:ns_t3af/Configuration/TypoScript/setup.typoscript'
Classic TypoScript templates: include static template
“AI Foundation labels”, or @import the same file.
Fluid badge (namespace ail is registered by AI Foundation):
<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>
Fluid Styled Content ships an image partial override that already calls
<ail: on each rendered file.
Assign state without rendering the badge:
<ail:recordState record="{data}" table="tt_content" as="labelState" />
<f:if condition="{labelState.showLabel}">…</f:if>
<ail:fileState file="{image}" as="labelState" />
DataProcessor alias nst3af- (variable label by default):
tt_content {
dataProcessing {
1550 = nst3af-label
1550 {
as = labelState
}
}
}
Or inject Frontend / Frontend in PHP.
Auto-confirm
Settings tab drives auto-confirm via Auto:
- Confirm when OUR extension recorded it —
ns_,t3ai ns_,t3aa ns_for media, text, or both.t3af - Confirm when DETECTED on upload — recording source
detected_(IPTC Digital Source Type already signals AI).upload - Hold — public-interest text stays manual (also EXTCONF
ailabel).Hold List
EXTCONF ailabel remains an extra allow-list (used even
when the Settings own-toggle is off). Auto-confirm never fills the responsible
person field.
Check Auto and Ai before
relying on auto-confirm in production.
Module settings consumed on the frontend
Ai drives visitor badge appearance:
label,Size label— passed toWording Frontend(Label Renderer show_= text only;site_ language icon_= icon only)only mark— enables image partial wrapper and overlay badgeImage File === overlay mark— stamps processed image copies (ImageMagick)Image File === written_ in label— overlay CSS class and processed-file stamp cornerPosition machine—Readable iptc/iptc_/jsonld offlabel— visitor badge for confirmed unknown-origin mediaUnknown Origin second— expandableInfo Layer <details>on the badge with human-readable involvement wording only (machine reason codes stay in evidence export / backend lists)- When
mark, media CTypes (Image File === overlay image,textmedia,textpic) skip the content-element After/All drop-in badge so the image overlay is the single visitor mark
Deep links
File list module: Process adds AI Label link to
the media tab with folder pre-selected.
Maintainer references
- Agent summary:
context/features/ ai- label. md - Deep spec:
context/specs/ FEATURE_ Ai Label. md - Unit tests:
Tests/Unit/ Ai Label/
Run tests:
cd packages/ns_t3af
composer test -- --filter AiLabel