Development Choices

Enrich Asset Metadata Automatically at Upload

Author
Joseph TrasattiMember of technical staff
Published
Section
No-Code
Length
7 min read3 sources cited

Enrich metadata in the upload path, not afterwards: upload-time enrichment costs one operation per asset, while backfilling re-reads and re-writes the whole library. Gate automatic tags with a confidence threshold and an allowlist, mark machine-written values as machine-written, keep the step re-runnable per subset, and judge it by whether a previously empty search now returns the right assets.

Before you start

You need three things in place, and the order matters.

A product environment with the fields already defined. Structured metadata in Cloudinary is schema-first: a field has an external ID, a type, and for enum and set types a fixed list of allowed values, and an upload can only write to a field that exists. The structured metadata reference covers the field types and how they are created. Define the fields before the first enriched upload lands, because a value written to a field that does not exist is not stored, and the upload still succeeds — the failure is silent.

An automatic-tagging add-on enabled, if you want machine tags. Tagging at upload is a paid add-on and is billed as a separate line from base-plan credits; on the Free plan you reach only the add-on’s free tier. Check what your plan includes before wiring it in, and do not assume the free tier covers a bulk import.

A decision about what enrichment is for. Not a philosophy — a list of two or three searches that currently return nothing useful. “Every hero image shot outdoors.” “Product photos on a white background from the spring shoot.” Write them down. They are the acceptance test in step 6, and if you cannot name one, the enrichment has no job to do and you should stop here.

If the assets are arriving from a spreadsheet rather than an application, the flow in bulk asset ingestion driven from a spreadsheet is where the upload parameters below get set; the enrichment logic is the same.

Steps

  1. Put the enrichment in the upload path, not in a later pass.

    Metadata written at upload costs one operation: the asset is being created anyway, and the tags and structured values ride along in the same request. The same metadata applied later is a different job entirely — a script or flow that lists the library, reads every asset, decides what to write, and writes it back, one asset at a time. On a library of a few hundred assets that is an afternoon. On a library of a few hundred thousand it is a project with its own rate limits and its own bill, and it competes with the Admin API budget everything else in the environment relies on.

    Practically, this means the upload preset (or the upload call, if you control it) carries the enrichment settings, and the flow that handles the upload runs before anyone can search for the asset. If you are choosing between a MediaFlows PowerFlow on the upload event and a webhook handler you write yourself, a hosted visual automation against a hand-written webhook handler sets out the trade; either way, it should fire on upload, not on a schedule.

  2. Turn on automatic tagging, then gate what it returns.

    Cloudinary’s automatic tagging does not return a set of tags. It returns candidates, each with a confidence score, and the upload option that turns candidates into tags takes a threshold: only candidates at or above it are written. That threshold is the whole control surface, and the default is not your setting.

    Set it deliberately, then add a second gate the vendor does not supply: an allowlist. Automatic tagging on a photograph will happily emit person, people, human, adult, man and smile for one subject, all above a middling threshold. Ten thousand assets later the tag space has several thousand distinct values, most used once, and a search on tags returns either nothing or everything. An allowlist — a fixed vocabulary of the thirty or fifty tags your searches actually use, applied to the candidates in the flow before they are written — is what keeps the space searchable. Candidates outside the list are dropped, or mapped to a list entry, never written raw.

    The threshold and the allowlist pull in opposite directions: a high threshold with no allowlist under-tags, a low threshold with a tight allowlist tags accurately but misses candidates the list did not anticipate. Start with the allowlist tight and the threshold moderate, and widen the list from the rejected candidates you see in the logs, not from imagination.

  3. Write machine values so they read as machine values.

    Every value the flow writes without a human deciding it should be distinguishable from one a human set. Two ways that work: a dedicated structured metadata field — an enum such as source: auto | human | imported — set alongside the enriched values, or a naming convention on the tags themselves (auto:outdoor rather than outdoor) so provenance is visible in the value.

    This is not tidiness. Some later automation will branch on these values — expiring assets, routing them for review, deciding whether alt-text generation inside a media automation flow should run or skip — and it needs to know how far to trust what it reads. A tag a curator applied is a fact; a tag a model applied at 0.71 confidence is a guess. If the two are indistinguishable, the downstream flow either trusts everything and acts on guesses or trusts nothing and ignores the curator. Store the confidence too if you can afford the field: a later step that wants only high-confidence values can filter on it instead of re-running the model.

  4. Make the step re-runnable on a subset before you make it right.

    Enrichment that cannot be re-run is a liability. The model behind automatic tagging changes; your allowlist changes; you discover a month in that the threshold was too low for illustrations and fine for photographs. When that happens you need to reprocess the illustrations from June — not the whole library, and not nothing.

    That means the enrichment must be callable on an existing asset, not only on an upload event, and it must be idempotent: running it twice on the same asset leaves the same result, which in practice means it overwrites the machine-owned values and leaves the human-owned ones alone — which is why step 3 comes first. It also means the flow needs a way to select the subset, which is a search expression on the fields you already write: source is auto, uploaded in a date range, tagged from the old vocabulary. Build the reprocess path on the first day, when the library is small and running it against everything is cheap, because the day you need it the library will not be small.

    Do not spend the first week tuning the threshold. Spend it making sure the second run is one command.

  5. Choose the query before the field.

    Every value you write should be reachable through the search method, which lets you filter on tags, structured metadata fields and upload attributes in one expression. Before adding a field, write the search that will use it. If the search does not need the value to be a typed field — if a tag will do — use a tag; if the search will filter on a range, a date, or one of a fixed set of values, use a structured field of the matching type so the search engine can treat it as data rather than text. A field nobody has written a query for is a field nobody will query.

  6. Run the acceptance test: an empty search that now returns the right thing.

    Take the searches from the prerequisites. Run each against the library before enrichment and record the result — usually zero, or a handful of assets somebody tagged by hand. Upload a representative batch through the enriched path, run the searches again, and check the results by eye.

    The test of an enrichment is not that the values look plausible in the media library UI. It is that a search that returned nothing now returns the right assets, and only those. If a query returns more than before but the extras are wrong, the threshold or the allowlist is off — go back to step 2. If no query improves at all, the field was decoration: it cost an operation on every upload and bought nothing, and the right move is to remove it, not to keep it because it was already built.

Done looks like

Enrichment runs inside the upload path and costs one operation per asset. Tags come from an allowlist, written only above a threshold you chose and can name. Every machine-written value is marked as machine-written, with its confidence where it matters, so a later flow — expiry, review, duplicate detection — can decide how much to trust it. The same enrichment can be re-run on any subset you can express as a search, in one command, without touching human-set values. And at least one search that returned nothing before now returns the right assets, which is the only evidence that any of it was worth doing.

Sources

  1. structured metadata referencecloudinary.com
  2. automatic taggingcloudinary.com
  3. search methodcloudinary.com

See also