DEV Community

Cover image for I Automated 500 Assets Before I Made a Single Sale. Here Is What I Learned

I Automated 500 Assets Before I Made a Single Sale. Here Is What I Learned

I remember the exact moment. It was late, my upload queue showed 500 assets ready to go, and I pasted my metadata CSV into Adobe Stock's uploader. Rejected in seconds. Wrong header. Five columns, and I had given it six. Five hundred assets, zero uploads, zero sales, and I had spent weeks generating the art itself.

That was the night I stopped treating the pipeline as "make images, then figure out the rest" and started treating the boring parts as the actual product. Here is what I learned getting from that failure to 39 finished products.

The metadata header is a contract, not a suggestion

Every stock platform validates the CSV header before it looks at a single file. Adobe wants exactly 5 columns. Vecteezy wants 4. Dreamstime wants 15. Get one column wrong and the whole batch bounces, no matter how good the art is.

So I wrote make_metadata.py to emit the exact header each platform demands and nothing else. It walks a folder of files, title-cases the filename as a fallback title, and writes the CSV. If you pass a titles.json, you get real titles and keywords instead. The fallback is fine for a first pass, but replace it before you submit, filenames like asset-001.jpg are not going to rank anywhere.

The lesson: the art is maybe a third of the work. The metadata is the gate, and it is the cheapest thing to automate.

Double-posting will get you flagged faster than bad art

This one cost me a scare. I re-ran a batch script overnight, forgot it had partially completed, and nearly posted duplicates. Duplicate submissions are one of the fastest ways to get a contributor account flagged, and once you are flagged, every future upload gets slower reviews or rejections.

The fix is dumb and essential: a ledger. upload_tracker.py is a small standard-library script that records what you have marked done. You run pending before every batch, you mark items done as they upload, and a re-run simply skips anything already in the ledger. No database, no cloud, just a file that makes the mistake impossible.

If you automate anything in your pipeline, automate this. It is the difference between a re-run being boring and a re-run being an account risk.

Your server is smaller than you think, and that is fine

The whole pipeline ran on 1 vCPU, 2 GB RAM, no GPU. That constraint taught me habits I would not have learned on a beefy machine:

  • One image job at a time. Never fan out renders in parallel on a single core, you just thrash.
  • Call gc.collect() after every asset. Python holds references longer than you expect.
  • Measure peak RSS with resource.getrusage(RUSAGE_SELF).ru_maxrss, not your gut feeling. Average memory tells you nothing about the spike that kills the process.
  • Run heavy render steps one file per subprocess so memory actually returns to the OS.
  • Inspect previews at 60 dpi instead of rendering at 300. You only need the full resolution for the final output.

AI image generation costs money per image, so wasted renders are wasted cash. A pipeline that dies at asset 340 of 500 because of a memory spike is burning both.

A folder of files is not a product

I had 856 MB of finished output and nothing sellable, because a folder of loose files does not look like anything. What made the difference was a fixed layout and one packaging command.

The layout that stuck:

project/
  assets/     raw output
  output/     ready-to-submit files + metadata
  packs/      finished zips + covers
  research/   notes and sources
  scripts/    the tools
Enter fullscreen mode Exit fullscreen mode

And pack_product.py does the last mile: zips the files and renders a 1280x720 cover plus a 600x600 thumbnail. That is it. A zip with a real cover sells, a bare file does not. The cover dimensions are not arbitrary, they fit the preview slots on the marketplaces where I list.

One mistake from this project I will not repeat: I deleted my research/ folder once to "clean up". Those notes and scrape logs were the raw material for the next three products. Keep it forever.

The 80/20 was not where I expected

Rough numbers from the project: about 19,000 lines of pipeline code, 300+ pages of research behind the rules, 39 products packaged, and the first sale came after all of that, not before. The art generation was the fun part and the smallest part. The parts that actually stalled me were metadata headers, duplicate protection, document-to-PDF conversion (one command via md2pdf.py, using reportlab, headings and tables and links intact), and packaging.

Of the four tools that handle those, two need nothing but the Python standard library, and the other two need exactly two packages: Pillow for covers and reportlab for PDFs. No framework, no cloud account, no monthly bill. Everything validated on the 1 vCPU, 2 GB box.

I am not going to pretend the kit makes sales automatic. It does not. Sales still depend on what you make and whether anyone wants it. What it does is remove the four failure points that kept me at zero for weeks: wrong headers, double posts, ugly documents, and unpackaged files.

I packaged the exact scripts from this work into the Pipeline Starter Kit, with the folder layout, the RAM notes, and the platform rules baked in. It is the tool I wish I had on the night Adobe bounced my first 500 rows.

Get compliance metadata kit


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

Top comments (0)