How do I check video against my own compliance rules?
Turn each rule into something a machine can test: example images of what is not allowed, a list of banned phrases, a line that must appear on screen, or a yes-or-no question. Index every video into scenes, each with its speech transcript, on-screen text and start and end time. Then check each video's scenes against every rule and keep the scenes that break one. What comes back is a list of flagged moments per video: the rule, how close the match was, and where it happens. A person reviews those moments instead of watching every video end to end.
What kinds of rules can a machine check?
Most compliance rules fall into five shapes, and each shape uses a different signal:
| Rule shape | Example | Signal | How Mixpeek checks it |
|---|---|---|---|
| Something must not be shown | No alcohol near a minor, no competitor product on screen | The scene's picture | A taxonomy built from your example images |
| Something must not be said or written | "Guaranteed results", "risk-free", "cure" | Transcript and on-screen text | Phrase match on transcription and ocr_text |
| Something must be present | "Results not typical" on screen, a required disclaimer | On-screen text | A phrase query; no matching scene means it is missing |
| A judgment call | A claim that implies a health benefit | Transcript, on-screen text, sometimes the clip | A yes-or-no question per scene, answered by a model |
| A person, logo or slogan you have no rights to | A public figure, another brand's mark | Faces, logos, copy | Mixpeek's marketplace IP retrievers |
Write the rules down in these shapes before building anything. A rule like "nothing off-brand" has no shape yet, and no system can check it until someone says what it looks or sounds like.
Step 1: index each video into scenes
Upload each video to a bucket with an ID you can filter on, such as
asset_id, then create a
collection with the multimodal extractor.
Split by scene, and turn on transcription and on-screen text, because spoken and written claims are
where most ad rules apply:{
"collection_name": "ads",
"source": { "type": "bucket", "bucket_ids": ["bkt_ads"] },
"feature_extractor": {
"feature_extractor_name": "multimodal_extractor",
"version": "v1",
"input_mappings": { "video": "video_url" },
"field_passthrough": [
{ "source_path": "metadata.asset_id" },
{ "source_path": "metadata.market" }
],
"parameters": {
"split_method": "scene",
"run_multimodal_embedding": true,
"run_transcription": true,
"run_ocr": true,
"run_video_description": true,
"enable_thumbnails": true
}
}
}start_time, end_time, transcription, ocr_text,
description, a thumbnail and a 1,408-float embedding of the picture. Scenes longer than
max_segment_duration (30 seconds by default) are split further.Step 2: write the visual rules as a taxonomy
A taxonomy in Mixpeek labels documents by matching them against a reference collection. For compliance, the reference collection is your rule book: one document per example of a violation, each carrying the rule it belongs to.
Put a few example frames per rule in a second bucket, each with
rule_id, rule and
severity as metadata, and index them with the same extractor so their embeddings sit in the
same space as your scenes:{
"collection_name": "rule-examples",
"source": { "type": "bucket", "bucket_ids": ["bkt_rule_examples"] },
"feature_extractor": {
"feature_extractor_name": "multimodal_extractor",
"version": "v1",
"input_mappings": { "image": "example_image" },
"field_passthrough": [
{ "source_path": "metadata.rule_id" },
{ "source_path": "metadata.rule" },
{ "source_path": "metadata.severity" }
],
"parameters": { "run_multimodal_embedding": true }
}
}{
"retriever_name": "nearest-rule",
"collection_identifiers": ["rule-examples"],
"input_schema": { "vector": { "type": "array", "required": true } },
"stages": [
{ "stage_name": "nearest", "stage_type": "filter",
"config": { "stage_id": "feature_search", "parameters": {
"final_top_k": 3,
"searches": [ { "feature_uri": "mixpeek://multimodal_extractor@v1/vertex_multimodal_embedding",
"query": { "input_mode": "vector", "value": "{{INPUT.vector}}" }, "top_k": 3 } ] } } }
]
}POST /v1/taxonomies
{
"taxonomy_name": "ad_rules",
"config": {
"taxonomy_type": "flat",
"retriever_id": "<nearest-rule retriever ID>",
"input_mappings": [
{ "input_key": "vector", "source_type": "vector",
"path": "multimodal_extractor_v1_multimodal_embedding" }
],
"source_collection": {
"collection_id": "<rule-examples collection ID>",
"enrichment_fields": [
{ "field_path": "metadata.rule_id", "target_field": "rule_id", "merge_mode": "replace" },
{ "field_path": "metadata.severity", "target_field": "severity", "merge_mode": "replace" }
]
}
}
}Step 3: check one video against the visual rules
This retriever loads every scene of one video, labels each with its nearest rule, keeps the scenes that matched one closely enough, and sorts them by time. It uses Attribute Filter, which reads documents straight from the collection when it is the first stage, and Taxonomy Enrich:
{
"retriever_name": "check-visual-rules",
"collection_identifiers": ["ads"],
"input_schema": { "asset_id": { "type": "text", "required": true } },
"stages": [
{ "stage_name": "one_video", "stage_type": "filter",
"config": { "stage_id": "attribute_filter", "parameters": {
"field": "metadata.asset_id", "operator": "eq", "value": "{{INPUT.asset_id}}" } } },
{ "stage_name": "label", "stage_type": "enrich",
"config": { "stage_id": "taxonomy_enrich", "parameters": {
"taxonomy_id": "<ad_rules taxonomy ID>", "top_k": 1, "min_score": 0.75 } } },
{ "stage_name": "flagged_only", "stage_type": "filter",
"config": { "stage_id": "attribute_filter", "parameters": {
"field": "rule_id", "operator": "exists", "value": true } } },
{ "stage_name": "in_order", "stage_type": "sort",
"config": { "stage_id": "sort_attribute", "parameters": {
"field": "start_time", "direction": "asc" } } }
]
}start_time, end_time, rule_id, severity, the
thumbnail, and the match score in a _taxonomy_..._score field named after the taxonomy ID.min_score decides how many moments come back. Set it on your own videos: label a few dozen
scenes by hand, run the retriever at a few thresholds, and pick the one that misses nothing your
reviewers would have flagged. Scores depend on your examples, so a threshold from someone else's
rule book will not carry over.Step 4: banned phrases, required lines and judgment calls
Banned phrases. Match them in the transcript and on-screen text with the
phrase operator,
which matches the words in order at word boundaries:{ "stage_name": "banned_phrases", "stage_type": "filter",
"config": { "stage_id": "attribute_filter", "parameters": { "conditions": { "AND": [
{ "field": "metadata.asset_id", "operator": "eq", "value": "{{INPUT.asset_id}}" },
{ "OR": [
{ "field": "transcription", "operator": "phrase", "value": "guaranteed results" },
{ "field": "ocr_text", "operator": "phrase", "value": "guaranteed results" },
{ "field": "transcription", "operator": "phrase", "value": "risk free" },
{ "field": "ocr_text", "operator": "phrase", "value": "risk free" }
] }
] } } } }{"field": "ocr_text", "operator": "phrase", "value": "results not typical"}. An empty result
means the video never shows it, which is the flag.Judgment calls. Some rules need reading, such as "the ad implies the product treats a medical condition". Load the video's scenes with the first stage above, then add LLM Filter with the rule as its criteria:
{ "stage_name": "judgment", "stage_type": "filter",
"config": { "stage_id": "llm_filter", "parameters": {
"criteria": "Keep only scenes where the speech or on-screen text says or implies the product treats, cures or prevents a medical condition",
"include_reasoning": true } } }include_media to
true when the picture matters, and the scene goes to Gemini as video. LLM Filter makes one model
call per scene, and its docs advise narrowing first when more than 100 documents reach it. A
30-second ad has a handful of scenes, so per-video checks stay small.Step 5: faces, logos and slogans
Mixpeek's marketplace has public retrievers for the rights side of review:
Send each scene's thumbnail to IP Screen and each transcript or on-screen line to Trademark Slogan Match, through
POST /v1/marketplace/catalog/{public_name}/execute with
{"inputs": {"query": "<frame URL or text>"}}. Without an API key each listing allows 10 requests
a minute per IP address, which is enough to try it.Where does this run, and on whose storage?
Mixpeek reads the videos from your bucket (S3, GCS or another object store you connect) and keeps the scenes, transcripts and labels in your namespace. You call it through the API, so the flagged moments go wherever your review happens: a ticket, a spreadsheet, your own review screen. On the Enterprise plan the whole stack can also run in your own AWS, GCP or Azure account.
What does it cost?
At the rates in Mixpeek's public features API on 2026-11-10, video indexing with scenes, speech transcript and descriptions is $0.05 a minute, and on-screen text adds $0.10 a minute. Taxonomy enrichment is included.
| Library | Minutes | Indexing | On-screen text | Total |
|---|---|---|---|---|
| One 30-second ad | 0.5 | $0.025 | $0.05 | $0.075 |
| 1,000 thirty-second ads | 500 | $25 | $50 | $75 |
| 100 hours of long-form video | 6,000 | $300 | $600 | $900 |
You pay to index each video once. Rerunning the checks after a rule changes reads the stored scenes and does not re-index anything. LLM Filter calls are extra, one per scene that reaches the stage.
What you build on top
Mixpeek returns the flagged moments and the evidence for each one. It has no reviewer screen or approve-and-reject queue, no signed report format, and no ready-made rule packs for particular regulators or markets. Teams write their own rules from their policy documents and route the results into the tools their reviewers already use. Published accuracy figures for any compliance tool depend on the rules and footage they were measured on, so measure on yours.
Frequently Asked Questions
What is video compliance software?
Software that checks videos against a set of rules, such as ad standards, platform policies or brand guidelines, and points to the moments that break them. The useful output is a list of timestamps per rule, so a reviewer checks those moments instead of watching every video in full.
Can I use my own rules instead of a fixed list of categories?
Yes. In Mixpeek the visual rules are a taxonomy built from your own example images, phrase rules are lists you write, and judgment rules are plain sentences a model answers per scene. Changing a rule means changing those inputs, and the next check uses them without re-indexing the videos.
How do I check that a required disclaimer appears in a video?
Index the video with on-screen text turned on, then query its scenes for the disclaimer with a phrase match on
ocr_text. If no scene matches, the video never shows the line. Spoken
disclaimers work the same way against transcription.How do I find the exact timestamp where a rule is broken?
Index the video into scenes so every scene carries its own start and end time, then check scenes one at a time. Each flagged scene comes back with
start_time and end_time in seconds, which
a player can jump to directly.How is this different from a brand safety tool?
A brand safety tool scores content against a shared list of categories, such as violence or adult content, so advertisers can avoid placements near it. A compliance check uses your own rules on your own videos before they ship. The pipelines overlap, and our guide on brand safety vs brand suitability covers the category side.