Mastering Adobe Stock's Five-Column CSV Metadata: A Practical Guide to Passing Upload on the First Try

Developer shares header validation and duplicate-upload prevention tips for Adobe, Vecteezy, and Dreamstime metadata CSVs.
After a CSV was rejected for a header column name's case and column count, a developer built header validation into his scripts. He details the three stock platforms' different requirements—Adobe Stock's strict five fixed columns, Vecteezy's four columns with space-separated keywords and count limits, and Dreamstime's fifteen columns—plus using upload_tracker.py to prevent duplicate uploads and a pure-standard-library pipeline on low-spec hardware.
Title
Mastering Adobe Stock's Five-Column CSV Metadata: A Practical Guide to Passing Upload on the First Try
Meta Description
A developer shares hands-on experience getting Adobe Stock, Vecteezy, and Dreamstime metadata CSVs through upload on the first try: exact header specifications, keyword delimiter pitfalls, category number mapping, duplicate upload protection, and how to build a low-spec pipeline.
Article Content
When uploading stock assets, nothing is more frustrating than having a file rejected by the system before it even reaches human review. A developer shared his experience of wasting an entire afternoon: 40 JPEG images, a script-generated metadata CSV, and an instant rejection after upload. The problem was a single column name—he wrote Keywords, while Adobe requires lowercase keywords, and he had generated eight columns, while Adobe's parser only recognizes five.

That lesson drove him to build header validation directly into his script. Below is his summary of getting metadata CSVs through on the first try across Adobe, Vecteezy, and Dreamstime.
Adobe Stock: Strictly Five Columns, Fixed Order
Adobe Stock's CSV parser is extremely strict. The header row must be exactly five columns, in this order: Filename, Title, Keywords, Category, Releases. Any mistake in spelling, order, or column count causes the upload to fail before it enters review. The author's approach is to define the headers for all three platforms as constants in make_metadata.py, with the script writing the exact header based on the target platform—never adding extra convenience columns, notes columns, or trailing empty fields. Adobe's parser has zero tolerance for a sixth column—even if it's empty.
The Category column takes numbers rather than category names. Adobe maps categories to integers, and the script writes the numbers directly, with the mapping maintained in one central place. Manually entering category names leads at best to silent miscategorization and at worst to outright rejection.
Adobe Stock's CSV import mechanism is essentially a fixed-pattern parser: it reads data by column position rather than column name, so header spelling and order must match the official template exactly. This design stems from the historical architecture of its bulk upload system; early versions didn't even accept any extra blank columns. The integer mapping for the Category column corresponds to Adobe Stock's official category taxonomy (e.g., 1 for Animals, 2 for Buildings), which isn't fully listed in public documentation but can be obtained by downloading the official CSV template. Developers should always refer to the latest template, as Adobe occasionally adjusts category numbers.
Vecteezy: Four-Column Structure, Stricter Keyword Count Limit
Vecteezy's header is four columns: filename, title, keywords, category, all lowercase. The real trap isn't the header but the keywords field. Vecteezy imposes a cap on the number of keywords; if you paste over the 49 keywords used for Adobe as-is, they'll be flagged or truncated. The author maintains a keyword limit per platform in the script, trimming to the strictest standard rather than writing a CSV and hoping for the best.
Another easy pitfall: Vecteezy requires keywords within a cell to be separated by spaces, not commas. Adobe accepts comma separation. If you reuse the Adobe file directly for Vecteezy, each keyword becomes one long garbled string. This kind of error is exactly what happens when you pass the wrong --platform argument, so the script makes the platform a required parameter and outputs differently named files.
Vecteezy's keyword limit is typically around 30, though the exact cap may change with platform policy. Its requirement for space-separated keywords rather than commas comes from the fact that Vecteezy's backend treats the entire keyword field as a single string tokenized by spaces, so commas become part of the keyword. This difference makes reusing CSVs across platforms highly error-prone. Additionally, Vecteezy's category column accepts text category names rather than numbers, in contrast to Adobe, so the script must maintain separate category mapping logic for each platform.
Dreamstime: Fifteen-Column Structure, the Only One with Formal Release Fields
Dreamstime's CSV has fifteen columns, which sounds intimidating, but for vector and illustration work, most columns can be left blank. The key columns include filename, title, keywords, category, and release fields. If the submitted work contains identifiable people or property, the "No" or editorial flags in the release columns matter. For purely AI-generated abstract decorative work, most release columns are left blank, but the header must still list all fifteen columns, or the file will be returned.
The lesson shared across all three platforms: the header is a contract, not a suggestion. The author abandoned manual CSV editing entirely—the script reads files from a folder, converts filenames to title case as placeholders, then writes the exact header for the specified platform.
Among Dreamstime's fifteen-column CSV, the release fields (Releases) declare whether the work contains identifiable people, property, or trademarks. If the work contains such elements and the release information isn't filled in correctly, the upload may be rejected or require supplementary legal documents. For AI-generated abstract work, the relevant release columns are typically left blank or marked "No", but the header must retain all fifteen columns, because Dreamstime's parser validates the column count—missing any column causes the entire batch to be returned.
Filenames and Titles Are What Really Determine Approval and Visibility
Correct headers only get files parsed. Titles and keywords determine whether they pass review and can be found in search. The author's early titles were filename garbage, like asset_001_final.jpg converted to title case—completely useless. Now the script accepts a titles.json file providing real titles and keywords for each asset, with filename-derived titles used only as placeholders. Every asset gets a human-written title and 25 to 35 relevant keywords before upload. Assets that skip this step either get sent back by review or attract no attention at all.
Duplicate Uploads: The Invisible Killer Nobody Warns You About
Once the CSV passes, a new danger emerges: re-running batches. Uploading the same asset twice is one of the fastest ways to get your account banned on major stock platforms. After making that mistake once, the author built upload_tracker.py: a ledger recording completed jobs, where pending shows only assets not yet published and re-runs don't upload duplicates. Three commands, standard library only, no database. Run pending before each batch, done after each upload, and status when unsure.
Stock platforms typically detect duplicate uploads via file hashes or metadata fingerprints. The same file may still be recognized as a duplicate even if renamed or retitled, as long as the content hash is identical. Duplicate uploads at best cause files to be ignored and at worst trigger account review or even a ban. Therefore, an upload tracker should record not just filenames but also content hashes (such as SHA-256), so it can accurately determine whether a file has already been uploaded even after it's renamed or moved.
The Whole Pipeline Runs on Extremely Low Specs
All of this runs on a server with 1 vCPU, 2 GB of RAM, and no GPU. Metadata generation is lightweight computation, achievable with pure Python standard library, no installation required. The heavier steps in the pipeline follow two rules: only one process at a time on a single core, and gc.collect() after processing each asset. Peak memory is measured with resource.getrusage(RUSAGE_SELF).ru_maxrss, yielding a real memory ceiling rather than a guess. If generating AI images, the per-image cost is small, but across a whole directory it adds up, so the author batches and reviews before rendering final versions.
The Actual Workflow Today
The folder structure is fixed: assets/ holds raw output, output/ holds submission-ready files and CSVs, packs/ holds finished products, research/ holds notes, and scripts/ holds tools. The metadata step is one command per platform. The tracker maintains the ledger. Nothing is edited manually, because manual editing is exactly what caused the eight-column mistake in the first place.
The author packaged this workflow into a Pipeline Starter Kit containing four scripts (make_metadata.py with exact Adobe, Vecteezy, and Dreamstime headers, upload_tracker.py, md2pdf.py, pack_product.py), which on the same 2 GB machine turned a prompt engine into 39 finished products, about 856 MB of output. Two dependencies in total, and the two metadata scripts need none.
One-line Summary
A developer shares header validation and duplicate-upload prevention lessons for getting Adobe, Vecteezy, and Dreamstime metadata CSVs through on the first try.
Paragraph Summary
After wasting an afternoon on a CSV rejected for a header column name's case and column count, a developer built header validation into his scripts. The article details the three stock platforms' differing requirements: Adobe Stock's strict five fixed-order columns, Vecteezy's four columns with space-separated, count-limited keywords, and Dreamstime's fifteen columns where most can be left blank. The author stresses that the header is a contract and manual editing is the root of errors, and describes using upload_tracker.py to prevent duplicate uploads and running the whole pipeline with pure Python standard library on a low-spec server, ultimately packaged as a Pipeline Starter Kit.
Related articles

Chain of Thought Isn't Just for AI: How Humans Can Use CoT to Improve Thinking Quality
Chain of Thought isn't just a prompt trick for large models. Starting from a Hacker News discussion, this article analyzes why CoT works for human thinking too, breaks down actionable ways to transfer it, and highlights the key differences between human CoT and machine CoT.
Cloudflare Teams Up with OpenAI: Closi…
Cloudflare Teams Up with OpenAI: Closing the Loop from Vulnerability Discovery to Defense with AI
Cloudflare uses OpenAI Daybreak to investigate security vulnerabilities and generate reviewable remediation plans, while developers use Codex to boost coding efficiency and quality.

Orca Multi-Agent Orchestration in Practice: A Guide to Parallel Collaboration with Claude and Codex
Orca is Stable AI's free open-source agent workbench supporting 34 agents like Claude Code and Codex in parallel. Learn its Git worktree isolation, multi-model orchestration, and mobile management.