← All guides AI Release
RU Subscribe to @ai_release1

AI content labeling in Russia from March 2027: a practical checklist

Updated: 30.10.2026 · AI Release · @ai_release1
AI content labeling in Russia from March 2027: a practical checklist

TL;DR

Requirements and setup

Illustration: Requirements and setup
Illustration: Requirements and setup

Create the working layout. Every artifact gets one manifest file and one asset file with the same ID — that naming rule is what makes the rest of the guide scriptable.

mkdir -p ai-labeling/{schema,manifests,assets,scripts}
cd ai-labeling
git init
ai-labeling/
├── schema/label.schema.json
├── manifests/img-2027-0001.json
├── assets/img-2027-0001.jpg
└── scripts/verify_labels.sh

Example: after cloning your empty repo, ls prints assets manifests schema scripts — you are ready for Step 1.

Step 1. Define the label record and validate it

What to do: create one JSON manifest per asset that was generated or edited by AI, describe its fields in a JSON Schema, and validate every manifest against that schema before it reaches production. A manifest is a plain-text record of provenance — what made the asset, when, and whether a human reviewed it.

Why: the manifest is the single source of truth. The file metadata, the page label, and the API header are all generated from it, so they cannot drift apart. Writing the record first also forces you to capture the model identifier at generation time, before it is lost.

Example: manifests/img-2027-0001.json:

{
  "asset_id": "img-2027-0001",
  "asset_sha256": "<output-of-sha256sum>",
  "created_at": "2027-02-14T10:22:00Z",
  "origin": "ai-generated",
  "model_provider": "<provider-name-from-your-contract>",
  "model_id": "<exact-model-id-returned-by-the-api>",
  "ai_generated_share": 1.0,
  "human_reviewed": true,
  "reviewer": "editor@example.com",
  "reviewed_at": "2027-02-14T11:05:00Z",
  "disclosure": { "visible_label": "AI-generated image", "machine_readable": true }
}

Replace <exact-model-id-returned-by-the-api> with the string your provider returns in the response body — do not type a model name from memory. For AI-written text assets use the same schema and set origin to ai-assisted where an editor rewrote the draft; see AI for text work: translation, summarization, rewriting for the workflows that produce those drafts.

Add schema/label.schema.json with "required": ["asset_id", "asset_sha256", "created_at", "origin", "model_id", "ai_generated_share", "human_reviewed", "disclosure"], then hash the asset and validate:

sha256sum assets/img-2027-0001.jpg > checksums.txt
python3 -c "import json,jsonschema;jsonschema.validate(json.load(open('manifests/img-2027-0001.json')),json.load(open('schema/label.schema.json')));print('manifest valid')"

How to check: the terminal prints exactly manifest valid. Then delete "model_id" from a copy of the manifest, validate again, and confirm you get a ValidationError naming that field — the schema is actually enforcing something.

Step 2. Write the label into the asset, the page, and the API response

Illustration: Step 2. Write the label into the asset, the page, and the API response
Illustration: Step 2. Write the label into the asset, the page, and the API response

What to do: propagate the manifest to three surfaces: (1) machine-readable metadata inside the file, (2) a visible label plus a machine-readable tag on the web page, (3) a header on any API that returns AI-generated content. Each surface is read by a different audience — file metadata survives download and re-upload, the page label is what a human sees, and the header is what an automated client sees.

Why: a single surface fails the "transparent to both humans and machines" test. A visible caption disappears when the image is embedded elsewhere; file metadata is invisible to a reader. You need both.

Example — image metadata. The -overwrite_original flag stops ExifTool from leaving .jpg_original backup files in your build output:

exiftool -overwrite_original \
  -XMP-dc:Description="AI-generated image. Model: <model-id>. Provenance: /provenance/img-2027-0001.json" \
  -XMP-xmpMM:DocumentID="img-2027-0001" \
  assets/img-2027-0001.jpg

Example — video metadata. -codec copy remuxes without re-encoding, so quality is untouched and the job takes seconds:

ffmpeg -i assets/clip-2027-0002.mp4 -codec copy \
  -metadata comment="AI-generated video; provenance clip-2027-0002" \
  assets/clip-2027-0002.labeled.mp4

Example — page markup. One meta tag for machines, one paragraph for readers:

<meta name="ai-generated" content="true">
<p class="ai-disclosure">AI-generated image. <a href="/provenance/img-2027-0001.json">Provenance record</a></p>

Example — API response. Add these to the response builder for any endpoint that returns generated text, image, or audio:

X-AI-Generated: true
X-AI-Provenance: /provenance/img-2027-0001.json

For providers that support embedded provenance manifests, sign the file with c2patool instead of plain XMP — flag names and the signing-key setup change between releases, so check the current syntax in the tool's documentation and record the version you pinned.

How to check: run exiftool -s3 -XMP-dc:Description assets/img-2027-0001.jpg and confirm the description line appears. Run curl -sI https://<your-domain>/api/render | grep -i x-ai-generated and confirm x-ai-generated: true; replace <your-domain> with the hostname of your staging or production environment.

Step 3. Verify end-to-end and enforce in CI

Illustration: Step 3. Verify end-to-end and enforce in CI
Illustration: Step 3. Verify end-to-end and enforce in CI

What to do: turn the manual checks into one script and run it on every commit, so an asset that lost its label during a re-export fails the build instead of shipping.

Why: labels disappear silently. Design tools, image optimizers, and CDN pipelines routinely strip XMP blocks, and nobody notices until a complaint arrives. A failing build is the only reminder that survives a team change.

Example — scripts/verify_labels.sh:

#!/usr/bin/env bash
set -euo pipefail
npx ajv-cli validate -s schema/label.schema.json -d "manifests/*.json" --errors=text
sha256sum -c checksums.txt
for f in assets/*.jpg; do
  exiftool -s3 -XMP-dc:Description "$f" | grep -q "AI-generated" \
    || { echo "MISSING LABEL: $f"; exit 1; }
done
echo "all labels verified"

Wire it into CI as a single step running bash scripts/verify_labels.sh, and make that step required for merges. The same pattern — a script plus a scheduled run — extends to bulk re-labeling of large archives; see AI agents for task automation: a guide for how to wrap it as a repeatable job, and AI for programmers: coding assistants in 2026 if you want help generating the CI config.

How to check: run the script and confirm three lines appear in order — manifests/img-2027-0001.json valid, assets/img-2027-0001.jpg: OK, all labels verified. Then copy an asset, strip its metadata with exiftool -all= assets/test-unlabeled.jpg, re-run, and confirm you get MISSING LABEL: assets/test-unlabeled.jpg followed by echo $? printing 1.

Final checklist before you consider the rollout done:

Troubleshooting

Problem. The validator rejects manifests that were fine yesterday.

Problem. The schema validates with Python but the CI step fails.

Problem. Re-wrapping the video produces an empty output file.

Summary and next steps

Build the manifest first, propagate it to file metadata, page markup, and API headers, then lock all three behind a CI check that fails on unlabeled assets. Next, extend the same schema to your existing asset archive, starting with the highest-traffic pages.

FAQ

Does a metadata field inside the file satisfy the disclosure requirement?

Machine-readable metadata alone is normally not enough — it is invisible to a reader, so pair it with a visible label. The exact required wording and any exemptions must be confirmed against the current regulation text.

What happens to the label when a user downloads and re-uploads the file?

XMP metadata often survives a download but is stripped by editors and social platforms. Treat the manifest plus your published provenance URL as the durable record, and re-apply labels whenever an asset re-enters your pipeline.

Do we have to label content that is only partly AI-generated?

Record the proportion in ai_generated_share in the manifest and label according to the scope rules that apply to you. The threshold values and category rules are check with the documentation — confirm them with legal counsel rather than guessing.

Can we retro-fit labels to content published before March 2027?

Yes. Generate manifests from your existing asset records, run the same ExifTool and page-tagging steps in bulk, and add the verification script to the cron job. Start with assets that are still live and high-traffic.

🤖 AI summary