DEV Community

Cover image for Testing Your Metadata CSV Against Adobe, Vecteezy And Dreamstime Before Upload

Testing Your Metadata CSV Against Adobe, Vecteezy And Dreamstime Before Upload

I lost an entire Saturday to a CSV header.

Not to the art. Not to keywords. To one row of column names. I had 40 files ready for Adobe Stock, a metadata file I'd built by hand in a spreadsheet, and the uploader rejected it in about two seconds. The reason: Adobe's CSV wants exactly five columns, in a fixed order, and I had six. One extra column, "notes", that I thought would be harmless. It wasn't. The parser reads the header, sees a shape it doesn't expect, and stops before it ever looks at your actual files.

That was the moment I stopped hand-building metadata files and wrote a script to do it instead. Here's what I learned testing that script against all three platforms.

Each platform wants a different shape, and the shape is not documented well

Adobe is the strictest and the simplest. Five columns: filename, title, keywords, category, releases. Get the count wrong or the order wrong and the upload fails before review. There's no partial credit. My script, make_metadata.py, writes those five columns and nothing else. No extra columns "for my own reference". If I want notes, they live in a separate file, not in the CSV I feed the uploader.

Vecteezy takes four columns. Dreamstime takes fifteen. Fifteen. That one includes fields Adobe doesn't ask for at all, and if you've only ever built the Adobe file, the Dreamstime one will trip you up because you can't just reorder what you have. The script builds each one from the same folder of assets, so the source of truth is the files themselves plus a titles JSON, and the three CSVs are just projections of it.

The command looks like this, once per platform:

python make_metadata.py ./my-assets --platform adobe      --out metadata.csv   --ext .jpg
python make_metadata.py ./my-assets --platform vecteezy   --out vecteezy.csv   --ext .jpg
python make_metadata.py ./my-assets --platform dreamstime --out dreamstime.csv --ext .jpg
Enter fullscreen mode Exit fullscreen mode

Without a titles file it title-cases the filename as a placeholder. That's fine for a dry run, but I replace it before submitting. A filename is not a title, and reviewers can tell.

Test with one file, not forty

My second failure was batching. I generated metadata for 40 files, uploaded all of them, and found out afterward that half my titles were too long and several keyword lists had formatting problems. Now I always do this: build the CSV for a single test file, run it through the platform's uploader or validator, confirm it passes, then run the full batch. It costs ten minutes and has saved me from three bad batches so far.

The other thing I test for is the header itself. I keep the exact header row each platform expects in the script, so the output always starts with the right columns. If Adobe changes their format, I fix one line in one place instead of rebuilding a spreadsheet.

The double-post problem is worse than the rejection problem

A rejected CSV wastes an evening. A double-posted asset can flag your account. This happened to a friend of mine, not to me, which is why I built the guard before I needed it: upload_tracker.py is a plain ledger of what has been posted. Before any batch, I run:

python upload_tracker.py pending items.txt
Enter fullscreen mode Exit fullscreen mode

and it shows me what is genuinely new. After posting, I mark each item done. If a script re-runs by accident, or I forget which batch went out on Tuesday, the ledger remembers, not me. It uses only the Python standard library, so there's nothing to install and nothing to break.

Where the actual bottleneck sits

None of this is compute. My whole pipeline, the one that produced 39 finished products and 856 MB of output, ran on 1 vCPU and 2 GB RAM with no GPU. The hard parts are boring: the exact header each platform demands, the discipline of one test file before a batch, and a ledger so a re-run can't hurt you. The metadata script and the tracker together use zero third-party packages. The only installs in the whole kit are Pillow for cover rendering and reportlab for PDF output, and neither touches the metadata path.

One habit worth stealing: keep the raw research. I have 300+ pages of notes behind the rules these scripts enforce, and I once deleted a research folder to "clean up" and regretted it within a month. Notes are the raw material for the next product. Disk space is cheap. Rebuilding a scrape log is not.

What I actually built

After the third platform rejected a file for a reason I'd already fixed on another platform, I stopped patching spreadsheets and wrote the scripts properly. They're now the packaging layer of my pipeline: make_metadata.py for the Adobe 5-column, Vecteezy 4-column and Dreamstime 15-column CSVs, upload_tracker.py for the ledger, plus md2pdf.py and pack_product.py for turning documents and asset folders into sellable products with covers and thumbnails. I've collected them, with the folder layout and the small-server RAM notes, into the pipeline starter kit. It's the tool built from this work, nothing more. If you'd rather not lose a Saturday to a header row, it's there.

Get pipeline starter kit


Building digital products? Free guides & kits for digital product sellers.

Top comments (0)