NEWVectors or files. Pick a path.Start →
    Media
    Part of the Media & Entertainment solution →v1.2 · updated 2026-09-15

    Footage Intelligence at Archive Scale

    Millions of scenes you can move through instead of search. Footage, ads and editor assets land in three clean collections, and scenes are clustered one partition at a time so every run stays under the sample-size caps.

    scenes in the reference corpus
    1.27M
    sources into clean collections
    5 → 3
    documents per HDBSCAN run
    100k
    documents per k-means run
    1M
    click to first answer
    59.2 s
    How these were measured
    • 1.27M scenes in the reference corpus: The scale the partitioning recipe was written against, from the blessed clustering runbook.
    • 5 → 3 sources into clean collections: Three footage sources merge into one collection; ads and editor assets keep their own.
    • 100k documents per HDBSCAN run: The hard cap on the quadratic methods. The pairwise distance matrix costs sample_size squared times 8 bytes, about 80 GB at that ceiling.
    • 1M documents per k-means run: The hard cap on the linear methods. Above it, a partition is split again rather than the cap being raised.
    • 59.2 s click to first answer: from clicking apply to the first search that answers, timed on production on 6 November 2026 by the harness that runs nightly

    What’s inside

    Retrievers
    scene-search·feature_searchad-search·feature_searchlogo-on-screen-monitor·feature_search → llm_filter

    See it work

    • the take where the camera pushes in on the hands
      scene-search

      scene segments across an archive nobody has watched end to end

    • night exteriors with wet streets
      scene-search

      returns the moment, with production_id carried through

    • which cut did we use this shot in
      ad-search

      the same footage matched against the delivered ads

    Simulated walkthrough · illustrative frames, scripted decisions
    A camera operator silhouetted against a lit setcleared
    IngestStill: Pexels / Wolrider YURTSEVENframe 1 of 3
    Detections on this frame
    Decision path
    1. Ingest
    2. scene
    3. route: cleared
    Landed by a passthrough extractor with its source label intact.
    Running tally
    1
    cleared
    0
    review
    0
    excluded
    What a person's call does here
    Labels stored with each cluster in the cluster's own collection, where a person can review and rename them. This version does not write labels back onto the scenes; the FAQ says why.
    Try a search
    Pick a search to see which retriever answers it and whether it works on a one-click deploy.
    InFootageAdsEditor assetsOutClean collectionsPer-partition clustersA composite roll-upFiltered retrievers

    How it's wired

    Applies 5 buckets, 4 collections and 3 retrievers today

    SourceBucketCollectionRetrieverClusterAlertNot applied yet
    SOURCENeeds your inputactive-syncs3 · continuousSOURCENeeds your inputstatic-archives3 · one-timeSOURCENeeds your inputlegacy-loads3 · one-timeSOURCENeeds your inputad-librarys3 · continuousSOURCENeeds your inputeditor-outputmanual · on uploadBUCKETfootage-activecontent: video · dedupBUCKETfootage-archivecontent: video · dedupBUCKETfootage-legacycontent: video · dedupBUCKETadscontent: video · dedupBUCKETeditor-assetscontent: video · dedupCOLLECTIONDeploys readyraw-footagepassthrough_extractor@v1COLLECTIONDeploys readyfootage-scenesmultimodal_extractor@v1COLLECTIONDeploys readyad-creativesmultimodal_extractor@v1COLLECTIONDeploys readyeditor-assetspassthrough_extractor@v1RETRIEVERDeploys readyscene-searchrrf · top 50RETRIEVERDeploys readyad-searchrrf · top 50CLUSTERDeploys readyscene-themeskmeans · per production_idCLUSTERNeeds your inputcross-partition-themescomposite roll-upRETRIEVERDeploys readylogo-on-screen-monitortop 5ALERTlogo-on-screen

    Drag nodes to rearrange. Drag the background to pan, ctrl or cmd plus scroll to zoom. Click a node for its settings.

    What it costs

    Usage cost per month
    $7,692
    $0.77 per file · rate card when this page was built

    Processing is priced the way a batch is charged: each bucket's minutes, images, pages or tokens times its rate card lines. The batch dry run in Studio gives the binding quote.

    Models

    Collections and their documents

    raw-footagefrom bucket footage-active, by passthrough_extractor@v1
    FieldTypeRequired
    document_idstringset by Mixpeek
    collection_idstringset by Mixpeek
    source_labelstringno
    filenamestringno
    production_idstringno
    job_idstringno
    footage-scenesfrom bucket footage-active, by multimodal_extractor@v1

    Reads video from content

    FieldTypeRequired
    document_idstringset by Mixpeek
    collection_idstringset by Mixpeek
    production_idstringno
    job_idstringno
    source_labelstringno
    ad-creativesfrom bucket ads, by multimodal_extractor@v1
    FieldTypeRequired
    document_idstringset by Mixpeek
    collection_idstringset by Mixpeek
    ad_idstringyes
    brandstringyes
    source_labelstringno
    editor-assetsfrom bucket editor-assets, by passthrough_extractor@v1
    FieldTypeRequired
    document_idstringset by Mixpeek
    collection_idstringset by Mixpeek
    asset_typestringyes
    source_labelstringno

    Retrievers

    • scene-search
      feature_search over footage-scenes; input query
    • ad-search
      feature_search over ad-creatives; input query
    • logo-on-screen-monitor
      feature_search then llm_filter over footage-scenes; input query, document_id

    Spend limits

    Daily spend budget in the manifest
    1 USD a day; new batches pause once it is spent
    Acceptance run ceiling
    0.5 USD
    Model cost
    Unmeasured for 2 of 2 models

    Monthly cost at your volume is in the calculator. Served models start at zero replicas, so an idle namespace runs no model.

    Reward signals

    Clusters are re-cut as the corpus grows, one partition at a time.

    How reviewer decisions move the thresholds
    Explicit signals

    Labels stored with each cluster in the cluster's own collection, where a person can review and rename them. This version does not write labels back onto the scenes; the FAQ says why.

    Implicit signals

    Which clusters get opened and searched from, which is the signal for whether the grouping is useful.

    Where they land
    footage-scenes
    How the loop closes

    New footage joins its partition's clusters on the next run of that partition, which re-cuts them when the shape has drifted.

    A corpus you navigate by structure rather than by query, with every partition clustered under the limit that makes clustering possible at all.

    • Five sources land in three clean collections, so the people building search never touch ingestion.
    • Clustering runs one partition at a time, which is what keeps a multi-million-scene corpus inside the sample-size caps.
    • A composite run groups the centroids of the partition runs you name into a layer above them, in the same collection and without disturbing what the partition runs wrote.
    • Scene search works across the whole archive the entire time, and a filter keeps it inside one partition.

    For: Performance-video teams whose archive outgrew search. Once a corpus passes a million scenes, the question stops being 'find me this clip' and becomes 'show me what is in here', and a result list cannot answer that.

    What goes in
    Footage
    Three sources: an active sync, a large static archive, and a frozen legacy load. One shared schema so the merge is homogeneous.
    Ads
    Approved creatives, carrying their own ad and brand identifiers.
    Editor assets
    Graphics, text capsules and generated assets from the edit bay.
    What comes out
    Clean collections
    Raw footage, ads and editor assets, landed by a passthrough extractor so downstream teams build on stable inputs.
    Per-partition clusters
    One clustering execution per partition key, written to the cluster's own collection. Each run's cluster ids start again at cl_0, so a cluster id identifies a group within its run rather than across the corpus.
    A composite roll-up
    The centroids of the partition runs you name, grouped into a layer that sits above them in the same collection.
    Filtered retrievers
    Scene and ad search that can be narrowed to one partition.

    One file spins up the namespace. Generated from the workflow above. Also served at /templates/footage-intelligence.namespace.yaml.

    # footage-intelligence: one manifest spins up the namespace.
    # Platform manifest schema (GET /v1/discovery/schema). Validate with POST /v1/manifest/validate,
    # apply with POST /v1/manifest/apply or the Deploy button. Wiring comes from the flow diagram:
    # edges are bucket -> collection sources, collection -> retriever scope, retriever -> view.
    # Applying a SECOND time, over a namespace this template already created: use
    # POST /v1/manifest/apply?mode=create_missing, which creates what is missing and leaves
    # what exists alone. The default, create_only, fails the WHOLE apply and rolls it back if
    # any resource already exists, so an upgrade looks like a dead end without this. Use
    # mode=upsert to also patch resources that exist but have drifted from this file.
    version: '1.0'
    metadata:
      name: footage-intelligence
      description: "Namespace template footage-intelligence. Generated from the flow diagram on mixpeek.com/templates/footage-intelligence."
    namespaces:
      - name: footage-intelligence
        description: "Everything below lives in this namespace."
        feature_extractors:
          - name: passthrough_extractor
            version: v1
          - name: multimodal_extractor
            version: v1
        # Daily spend budget, in dollars of what you are charged (1,000 credits a dollar).
        # New batches pause once the namespace has spent this much today; queries are not capped.
        # Raise it later on the namespace: PATCH /v1/namespaces/<id> {"spend_budget": {"daily_usd": N}}.
        budget:
          daily_usd: 1
    
    # Data sources. A storage connection carries credentials, so it is created in Studio
    # (or POST /v1/organizations/storage-connections) and synced into the bucket named here.
    #   active-sync: s3, continuous -> bucket footage-active
    #   static-archive: s3, one-time -> bucket footage-archive
    #   legacy-load: s3, one-time -> bucket footage-legacy
    #   ad-library: s3, continuous -> bucket ads
    #   editor-output: manual, on upload -> bucket editor-assets
    buckets:
      - name: footage-active
        namespace: footage-intelligence
        description: "Meant to be fed by active-sync (s3, continuous). No source is connected yet: applying this manifest creates the bucket only. Connect the source to this bucket in Studio (Syncs) to start the feed."
        schema:
          properties:
            content:
              type: video
            source_label:
              type: string
            filename:
              type: string
            production_id:
              type: string
            job_id:
              type: string
      - name: footage-archive
        namespace: footage-intelligence
        description: "Meant to be fed by static-archive (s3, one-time). No source is connected yet: applying this manifest creates the bucket only. Connect the source to this bucket in Studio (Syncs) to start the feed."
        schema:
          properties:
            content:
              type: video
            source_label:
              type: string
            filename:
              type: string
            production_id:
              type: string
            job_id:
              type: string
      - name: footage-legacy
        namespace: footage-intelligence
        description: "Meant to be fed by legacy-load (s3, one-time). No source is connected yet: applying this manifest creates the bucket only. Connect the source to this bucket in Studio (Syncs) to start the feed."
        schema:
          properties:
            content:
              type: video
            source_label:
              type: string
            filename:
              type: string
            production_id:
              type: string
            job_id:
              type: string
      - name: ads
        namespace: footage-intelligence
        description: "Meant to be fed by ad-library (s3, continuous). No source is connected yet: applying this manifest creates the bucket only. Connect the source to this bucket in Studio (Syncs) to start the feed."
        schema:
          properties:
            content:
              type: video
            ad_id:
              type: string
            brand:
              type: string
            source_label:
              type: string
      - name: editor-assets
        namespace: footage-intelligence
        description: "Meant to be fed by editor-output (manual, on upload): upload files here or write them through the API. Nothing arrives until you do."
        schema:
          properties:
            content:
              type: video
            asset_type:
              type: string
            source_label:
              type: string
    collections:
      - name: raw-footage
        namespace: footage-intelligence
        description: "passthrough_extractor@v1 over bucket footage-active (the manifest wires one source bucket; footage-archive, footage-legacy are added after apply)."
        source:
          type: bucket
          bucket: footage-active
        feature_extractor:
          name: passthrough_extractor
          version: v1
          field_passthrough:
            - source_path: source_label
            - source_path: filename
            - source_path: production_id
            - source_path: job_id
        enabled: true
      - name: footage-scenes
        namespace: footage-intelligence
        description: "multimodal_extractor@v1 over bucket footage-active (the manifest wires one source bucket; footage-archive, footage-legacy are added after apply). Feeds logo-on-screen-monitor, logo-on-screen, scene-search, scene-themes."
        source:
          type: bucket
          bucket: footage-active
        feature_extractor:
          name: multimodal_extractor
          version: v1
          input_mappings:
            video: content
          field_passthrough:
            - source_path: production_id
            - source_path: job_id
            - source_path: source_label
        alert_applications:
          - alert: logo-on-screen
            input_mappings:
              - input_key: query
                source: {source_type: constant, value: "a brand logo on screen"}
              - input_key: document_id
                source: {source_type: document_field, path: _internal.document_id}
        enabled: true
      - name: ad-creatives
        namespace: footage-intelligence
        description: "multimodal_extractor@v1 over bucket ads. Feeds ad-search."
        source:
          type: bucket
          bucket: ads
        feature_extractor:
          name: multimodal_extractor
          version: v1
          field_passthrough:
            - source_path: ad_id
              required: true
            - source_path: brand
              required: true
            - source_path: source_label
        enabled: true
      - name: editor-assets
        namespace: footage-intelligence
        description: "passthrough_extractor@v1 over bucket editor-assets."
        source:
          type: bucket
          bucket: editor-assets
        feature_extractor:
          name: passthrough_extractor
          version: v1
          field_passthrough:
            - source_path: asset_type
              required: true
            - source_path: source_label
        enabled: true
    retrievers:
      - name: scene-search
        namespace: footage-intelligence
        description: "Searches footage-scenes across 1 feature index."
        collections:
          - footage-scenes
        input_schema:
          query:
            type: text
            required: true
            description: "What to look for; searched across every index below"
        stages:
          - stage_name: search
            stage_id: feature_search
            parameters:
              searches:
                - feature_uri: "mixpeek://multimodal_extractor@v1/vertex_multimodal_embedding"
                  query:
                    input_mode: text
                    value: "{{INPUT.query}}"
                  top_k: 50
              fusion: rrf
              final_top_k: 50
        tags:
          - template:footage-intelligence
      - name: ad-search
        namespace: footage-intelligence
        description: "Searches ad-creatives across 1 feature index."
        collections:
          - ad-creatives
        input_schema:
          query:
            type: text
            required: true
            description: "What to look for; searched across every index below"
        stages:
          - stage_name: search
            stage_id: feature_search
            parameters:
              searches:
                - feature_uri: "mixpeek://multimodal_extractor@v1/vertex_multimodal_embedding"
                  query:
                    input_mode: text
                    value: "{{INPUT.query}}"
                  top_k: 50
              fusion: rrf
              final_top_k: 50
        tags:
          - template:footage-intelligence
      - name: logo-on-screen-monitor
        namespace: footage-intelligence
        description: "The alert's check: does the scene just written show a brand logo on screen. The search is scoped to that one scene, and an llm_filter watches it and keeps it only when a logo is visible. Materialises into logo-on-screen."
        collections:
          - footage-scenes
        input_schema:
          query:
            type: text
            required: true
            description: "What to look for; searched across every index below"
          document_id:
            type: text
            required: true
            description: "The written document this run is scoped to, supplied by the alert attachment"
        stages:
          - stage_name: search
            stage_id: feature_search
            pre_filters:
              AND:
                - field: _internal.document_id
                  operator: eq
                  value: "{{INPUT.document_id}}"
            parameters:
              searches:
                - feature_uri: "mixpeek://multimodal_extractor@v1/vertex_multimodal_embedding"
                  query:
                    input_mode: text
                    value: "{{INPUT.query}}"
                  top_k: 5
              fusion: rrf
              final_top_k: 5
          - stage_name: judge
            stage_id: llm_filter
            parameters:
              criteria: "Keep this footage scene only if it shows {{INPUT.query}}: a company logo or brand name mark clearly visible in the frame. Discard it otherwise."
              include_media: true
        tags:
          - template:footage-intelligence
    # Composite cluster run(s) are not emitted below, because the manifest schema cannot express them:
    #   cross-partition-themes: rolls up the centroids of scene-themes
    # The manifest cluster spec requires source_collections to have at least one
    # item, and a composite run has no source COLLECTION: it reads the centroids of prior
    # EXECUTIONS. Naming it here fails validation for the entire manifest. Run it once the
    # partitioned runs have completed: POST /v1/clusters/{id}/execute on the partitioned cluster
    # with mode composite and source_execution_ids naming at least two of those runs.
    clusters:
      - name: scene-themes
        namespace: footage-intelligence
        description: "Groups footage-scenes by embedding similarity, one run per production_id."
        source_collections:
          - footage-scenes
        cluster_type: vector
        # Partitioned on production_id: execute once per value, passing
        #   filters: {AND: [{field: production_id, operator: eq, value: <one production_id>}]}
        # with each execution. The manifest cannot hold that value.
        # kmeans needs at least 24 documents in a production_id, since it has to
        # put each one in a group. Raise or lower n_clusters to the number of groups you
        # want to browse per production_id.
        vector_config:
          feature_uris:
            - mixpeek://multimodal_extractor@v1/vertex_multimodal_embedding
          clustering_method: kmeans
          algorithm_params:
            n_clusters: 24
        llm_labeling:
          enabled: true
          provider: google
          model_name: gemini-2.5-flash
    alerts:
      - name: logo-on-screen
        namespace: footage-intelligence
        description: "Emails the org notifications address (Settings -> Notifications; unset means opted out) when a newly indexed footage scene shows a brand logo on screen."
        source: retriever
        retriever: logo-on-screen-monitor
        trigger_on: results
        notification_config:
          channels:
            - channel_type: email
          include_matches: true
          include_scores: true
        enabled: false
    
    # Plan 11.14: two public-domain films from the starter sample set, ingested by
    # one bounded batch after apply, and the use case they must satisfy.
    seed:
      - bucket: footage-active
        max_objects: 2
        objects:
          - blobs: {content: samples/starter/videos/norelco-speed.mp4}
          - blobs: {content: samples/starter/videos/mexican-hat-dance.mp4}
    acceptance:
      max_cost_usd: 0.5
      steps:
        - name: footage-listed
          kind: documents
          collection: raw-footage
          expect: {min_documents: 2}
        - name: footage-scenes-indexed
          kind: documents
          collection: footage-scenes
          expect: {min_documents: 2}
        - name: scene-search-answers
          kind: query
          retriever: scene-search
          inputs: {query: people dancing}
          expect: {min_results: 1}

    Read from the manifest, so a part it ships commented out never shows as ready.

    raw-footageCollectionDeploys ready
    footage-scenesCollectionDeploys ready
    ad-creativesCollectionDeploys ready
    editor-assetsCollectionDeploys ready
    scene-searchRetrieverDeploys ready
    ad-searchRetrieverDeploys ready
    scene-themesClusterDeploys ready
    logo-on-screen-monitorRetrieverDeploys ready
    active-syncData sourceNeeds your input
    static-archiveData sourceNeeds your input
    legacy-loadData sourceNeeds your input
    ad-libraryData sourceNeeds your input
    editor-outputData sourceNeeds your input
    cross-partition-themesClusterNeeds your input
    What each part needs
    raw-footage
    Deploys and processes documents as they arrive.
    footage-scenes
    Deploys and processes documents as they arrive.
    ad-creatives
    Deploys and processes documents as they arrive.
    editor-assets
    Deploys and processes documents as they arrive.
    scene-search
    Deploys and answers queries once its collections hold documents.
    ad-search
    Deploys and answers queries once its collections hold documents.
    scene-themes
    Deploys. Run it once per production_id by passing that filter each time you execute it; the manifest cannot hold the value.
    logo-on-screen-monitor
    Deploys and answers queries once its collections hold documents.
    active-sync
    Connect this s3 source in Studio and sync it into its bucket. The manifest creates the bucket and leaves the connection to you.
    static-archive
    Connect this s3 source in Studio and sync it into its bucket. The manifest creates the bucket and leaves the connection to you.
    legacy-load
    Connect this s3 source in Studio and sync it into its bucket. The manifest creates the bucket and leaves the connection to you.
    ad-library
    Connect this s3 source in Studio and sync it into its bucket. The manifest creates the bucket and leaves the connection to you.
    editor-output
    You upload these files yourself. There is no connection to sync.
    cross-partition-themes
    The manifest cannot describe a cluster of clusters. Once the partitioned runs have completed, run it with POST /v1/clusters/{id}/execute in composite mode, naming at least two of those runs in source_execution_ids.
    ComponentRoleSourceToday
    passthrough_extractor v1Lands objects in a clean collection with their identifiers intact, so downstream teams build on stable inputs.Built inDeploys ready
    multimodal_extractor v1Embeds scenes and creatives so they can be searched and clustered by meaning.Built inDeploys ready
    Partitioned clusteringOne execution per partition key, with the algorithm chosen against the sample-size caps.Built in
    Composite clusteringClusters the centroids of prior executions, read from each execution's run record.Built in
    Your footageThree sources with one shared schema. The template creates the buckets; you supply the objects.You supply
    Mixpeek cloud

    The managed path. Nothing to run.

    Customer-hosted

    For archives that cannot leave your account. The footage stays in your object storage either way.

    Permissions
    Read on the source buckets. The template creates buckets, collections, retrievers and clusters inside one namespace and touches nothing outside it.
    Footprint
    Storage is dominated by the footage you already hold. The clustering cost scales with the partition, not the corpus, which is the point of partitioning.
    Reference fixtures

    A partition small enough to cluster in one run, so a change in grouping is visible without waiting on the full corpus.

    CategoryRule
    Partition sizeEvery partition stays under the cap for its algorithm: 100,000 for HDBSCAN, 1,000,000 for k-means. Over that, split the partition rather than raising the cap.
    Composite inputsA composite run names only executions that completed with centroids. One missing execution makes the roll-up a different shape without failing.
    Run completionEvery partition run completes with more than zero clusters. kmeans needs at least n_clusters documents in the partition, and it groups whatever it is given, so a partition that is too small fails rather than returning nothing. Density methods behave the other way: a test production of 68 scenes at HDBSCAN min_cluster_size 50 completed with every scene classified as noise.
    CountingRead the cluster documents themselves rather than the output collection's document_count, which trails one run behind on this path: 43 listed and 43 counted after the first run, 76 listed and 43 counted after the second.
    Throughput

    Clustering is a batch job per partition rather than a per-query cost, so search latency is unaffected by corpus size.

    Why partition at all, instead of clustering everything at once?+

    Because the methods have hard ceilings and they exist for memory reasons. HDBSCAN and the other quadratic methods cap at 100,000 documents, since the pairwise distance matrix costs sample_size squared times 8 bytes, about 80 GB at that ceiling. K-means caps at a million. A multi-million-scene corpus is clustered one partition at a time or not at all.

    What does a composite run actually do?+

    It clusters the centroids of the partition runs you name, which it reads from each run's record, and writes its groups into the same collection alongside them. Measured on prod: two partition runs left 76 documents, 8 of them centroids, and the composite over both took it to 88 with 12 centroids. Name only runs that completed with clusters, since a run that found none has no centroids to contribute.

    How does an agent use this?+

    Through the same retrievers a person uses. scene-search finds moments across the archive and takes a production_id filter to stay inside one partition, and each cluster run's results can be read back through the clusters API.

    Do I have to re-cluster to add new footage?+

    Yes, in this version. New scenes are searchable as soon as they are extracted, and they join a partition's clusters the next time that partition runs. Run it again when enough new footage has landed to change the grouping, which is a judgement rather than a schedule.

    Why doesn't this template write cluster labels back onto the scenes?+

    A cluster that enriches its source collection currently fails its first run on a collection that already holds documents, because a safety check reads the existing scene count as evidence of an earlier clustering run. Until that is fixed, scene-themes writes its clusters and labels to a collection of its own, and the scenes keep their production_id, job_id and search fields unchanged.

    Can I filter search results by a cluster id?+

    Within one run, yes. Cluster ids start again at cl_0 for every execution, so after two partition runs the same four ids hold documents from both productions. Filter on production_id to stay inside a partition, and treat a cluster id as a handle on a group within its run rather than a stable label across the corpus.

    What is the partition key here?+

    The template uses production_id because it is a natural grouping in the reference pipeline. The right key is whatever splits your corpus into pieces that fit under the cap and mean something to the people reading the clusters. Check the field is indexed on your documents before relying on it; a filter path that matches nothing returns an empty result rather than an error.