Two video ads for the same wallet brand are running in Meta's public Ad Library as we write this. One is a creator pitching to camera in his front yard with a tray of colorways, the other is a beach skit where the product doesn't even appear in the opening frame. Run them through a typical DTC creative taxonomy and they come out literally identical: 7 of 7 fields, same copy word for word. Whatever makes one of them win is invisible to the exact system that exists to explain wins.
This is worth dwelling on because creative analysis is the current promise of every ad platform and every AI tool: tag your assets, cut performance by attribute, learn what works, brief better creative. The whole chain runs on the taxonomy, and in our experience inside brands' own libraries the taxonomy is where it quietly dies. Not because teams don't tag, but because the fields themselves can't hold the distinctions that matter.
| Field | Ad A | Ad B |
|---|---|---|
| Product | Wallet | Wallet |
| Copy | โSlim. Secure. Built to last.โ | โSlim. Secure. Built to last.โ |
| Feature tag | RFIDBlocking | RFIDBlocking |
| CTA | ShopNow | ShopNow |
| Destination | ridge.com | ridge.com |
| Offer | None | None |
| Media type | Video | Video |
The instinctive fix, and the one we watched a brand try, is to add a field that captures "what the ad looks like". Theirs was called VisualTheme: one required pick from ~25 values. It sounds reasonable until you lay the values out and notice they aren't 25 answers to one question, they're answers to 6 different questions that all got poured into the same field.
A close-up editorial-style testimonial has 3 correct VisualTheme values and the field allows one, so every tagger's pick is defensible and every pick is wrong. That's what "not MECE" means in practice: not a philosophical flaw, but 2 people tagging the same asset differently while both follow the instructions. Fields like this end the same way every time.. applied to a small share of assets, inconsistently, and then abandoned.
The rebuild
The rebuilt system runs on 3 rules rather than more effort:
One question per field. Shot scale, visual style, setting and layout each get their own field with their own value list. A field is healthy when 2 people tagging the same asset agree without discussing it.
Single vs multi-select is declared, not assumed. A modern ad rarely argues exactly one thing, so value props are explicitly multi-select, while benefit type stays a single forced call (performance-led vs brand-led) because that tension is the point of the field.
Every field passes "would it change a brief". If knowing that an attribute wins wouldn't change what you ask creators to make next, the field is diligence theater and gets cut, however easy it is to tag.
Applied to a real library, that lands at roughly 29 fields across 7 groups, which sounds heavy until you run the same 2 ads from the top of this post through it:
| Field | Ad A | Ad B | |
|---|---|---|---|
| Message | Benefit type | PerformanceLed | PerformanceLed |
| Value props + | Slim|Secure|RFID | Slim|Secure|RFID | |
| Hook | DirectPitch | Skit | |
| Proof type | Demonstration | LifestyleScene | |
| Visual | Setting | HomeExterior | Beach |
| Shot scale | MidShot | WideShot | |
| Product focus | OpeningFrame | LateReveal | |
| Text treatment | Captions | StoryCaptions | |
| Product | Department | Wallets | Wallets |
| Hero product | ClassicWallet | ClassicWallet | |
| Colorways shown | 6 | 1 | |
| People | Human model | Male | Female |
| Model behavior | TalkToCamera | ActedScene | |
| Production | Production type | CreatorUGC | CreatorUGC |
| Producer | Partner | Partner | |
| Motion style | LockedCamera | Handheld | |
| Audio | Voice | OnCameraSpeech | OnCameraSpeech |
| Music | None | None | |
| Format | Media type | Video | Video |
| Video length | 30-60s | 30-60s |
B bt:PERF ยท vp:SLM|SEC|RFID ยท hk:SKIT ยท st:BEACH ยท sc:WIDE ยท hm:F ยท mb:SCENE ยท pt:UGC ยท vl:37
The taxonomy that saw 2 identical ads now sees 9 differences, and they're the right ones: hook, setting, shot scale, who's on camera, how it's shot. The similarities it keeps are real too.. same value props, same production type.. which matters just as much, because a cut by "creator UGC" should include both of these ads while a cut by "beach skit" includes one.
The operating layer is what makes 29 fields cheaper than 7 bad ones. Each field gets a 2-4 character code, and a small generator assembles the codes into the ad name itself (the 2 name lines under the table above), so the taxonomy travels inside every platform's reporting with no integration work and tagging a new asset takes ~2 minutes. The historical library gets backfilled by AI against the written field definitions, with human spot-checks on a sample.. and this is the part worth being precise about: AI is very good at applying an ontology and unreliable at inventing one. Generic auto-tagging gives you generic fields, which is the VisualTheme problem again with better marketing.
Why key:value codes, not underscores
Most naming conventions are positional underscore strings: EVG_PROS_UGC_BEACH_30_V2. The meaning lives in the position, and position is fragile. The day a field gets added, the day one ad skips a segment, or the day two teams disagree on whether slot 4 is audience or placement, every report parsing those names silently misreads.. and nobody notices, because the string still looks like a name. Key:value codes (st:BEACH, hk:SKIT) put the meaning in the token instead: order doesn't matter, a missing field is a missing key rather than a shifted column, and any tool.. a spreadsheet, a warehouse model, an AI.. can parse names it has never seen.
The quieter benefit is change. A taxonomy is never finished: next quarter you'll want a field for a new format, or to split one that turned out to be holding 2 questions (the VisualTheme lesson). With key:value names you add the key and move on.. every historical name stays valid and every report keyed on existing fields keeps working. With positional names, a change means re-parsing history or running 2 conventions side by side forever, so in practice nobody changes anything and the taxonomy stays wrong.
One thing the name should never be, though, is the join key. Campaigns and ads get renamed, and every rename silently orphans the web data that was joined on the old string. Pass the platform's ad ID through your UTMs (e.g. utm_content={{ad.id}} on Meta, so it populates automatically), join platform data to web data on that, and let the name carry the taxonomy. Renames then cost you nothing: the ID holds the join, and the current name re-parses into the current tags.
What to do with it
Run the twin test on your current system: pull your best and worst recent ad and compare their tags. If they nearly match, your creative reads are noise, whatever the dashboard says.
Split every field where 2 taggers could both be right. One question per field, and declare single vs multi-select explicitly for each.
Gate each field with "would it change a brief". Cut the ones that fail, even the easy ones.
Encode the fields into ad names via a generator, as key:value codes rather than positional underscores, and join platform data to web data on the ad ID passed through UTMs.. never on the name, which renames will break.
Let AI backfill history against your written definitions and spot-check a sample before trusting any cut of it.
Happy to walk through how we'd approach it for your creative library.
Common questions
Can't AI just tag our creative automatically?
It can apply a taxonomy far faster and more consistently than people, and that's exactly how the backfill above works. What it can't do reliably is decide what the fields should be, because it doesn't know which distinctions would change your briefs. Off-the-shelf auto-tagging tools ship generic fields ("lifestyle", "product-focused", "UGC") that fail the same MECE test the catch-all field failed, just with less visible seams. The working division of labor: humans define the ontology against the would-it-change-a-brief test, write real definitions for each value, and AI executes tagging at scale with humans spot-checking a sample. Teams that skip the definition step usually discover it 6 months later, when the cuts contradict each other and nobody trusts the creative reporting.
Isn't ~29 fields too many to maintain?
It's fewer decisions than it looks like, because most fields are a single obvious pick (shot scale, setting, format) and only a handful require judgment. With codes assembled by a generator, tagging a new asset runs ~2 minutes, which is less time than teams currently spend arguing about one ambiguous catch-all value. The count also isn't the goal; it's the output of the 3 rules. A smaller library with fewer formats might land at 15 fields. What matters is that each field answers one question and earns its place, because a wrong 7-field system produces confident wrong answers, and a right 29-field system produces cuts you can act on.
How do we get value from this before hundreds of new ads are tagged?
The backfill is the shortcut. Because the fields have written definitions, AI can tag your existing library retroactively, so the first real analysis cut is available in weeks rather than quarters. Start with the dimensions most likely to move a brief (content type, benefit type, value props) and validate against a hand-tagged sample of ~50 assets before reading anything directionally. Early reads will be directional at best until sample sizes build within each cut, so treat the first pass as hypothesis generation for creative testing rather than settled truth. The compounding value shows up after that: every new ad ships pre-tagged through the name generator, so the dataset never decays the way manually tagged libraries do.
This kind of structure-first measurement is core to our Acquisition & Creative work.
See how it works โ