Last March I ran a batch of 40 assets through my upload script at 2am, went to bed feeling smug, and woke up to find Adobe had rejected the entire CSV. One wrong column in the header. Not forty wrong rows, one wrong column count in row one. That was the moment I decided to stop hand-editing spreadsheets and write scripts that get the boring parts right, because the boring parts are what actually stop you from shipping.
I run everything on a server with 1 vCPU and 2 GB of RAM. No GPU, no cloud account. People assume you need more. You do not, if you respect what a single core can actually do. Here is what worked and why.
The CSV headers are contracts, and platforms check them first
Adobe Stock wants a 5-column CSV. Vecteezy wants 4 columns. Dreamstime wants 15. Every one of them rejects a file with the wrong header before a single image gets looked at. I know because I fed them wrong ones.
So make_metadata.py writes exactly the header each platform demands and nothing else. Adobe gets 5 columns, Vecteezy gets 4, Dreamstime gets 15. It reads a folder of files, title-cases the filename into a title, and fills the row. If you pass a titles.json with real titles and keywords, it uses those instead. Without it you get filename titles, which are fine for a first pass and bad for a final submission. Replace them before you upload. The review checks at these platforms are strict enough that lazy metadata is the cheapest thing to fix and the most common reason for rejection.
Double-posting is the fastest way to get flagged
This one cost me real anxiety. Run your batch script twice because you forgot you already ran it, and you have duplicate submissions. Stock platforms treat that as spam behavior and flag accounts for it.
The fix is embarrassingly simple. upload_tracker.py is a ledger, standard library only, no database. You mark an asset done, and any re-run shows you only what is pending. It took maybe 80 lines of Python and it removed an entire category of mistakes. If you are running automated batches, you need something like this before you need anything clever.
Pillow and reportlab cover 90 percent of what people think needs a framework
When I needed a product PDF from a Markdown file, I looked at the heavy options and closed the tab. md2pdf.py uses reportlab alone: headings, tables, lists, links, clean styling, one command:
python md2pdf.py content.md product.pdf "My Product Title"
Covers are the same story. A zip with a real 1280x720 cover and a 600x600 thumbnail sells. A bare file does not. pack_product.py renders both with Pillow, zips the files, and writes everything into a _system folder. Two third-party packages total across the whole kit. Everything else is the standard library.
The RAM habits that make 2 GB enough
The single core is not the constraint people think it is. Memory is. These habits are what keep the pipeline alive:
- One process at a time. Never fan out image jobs in parallel on a 1-core box. Parallelism buys you nothing when there is one core and costs you an OOM kill.
- Call
gc.collect()after each asset. Python does not always hand memory back on its own schedule, and on 2 GB you feel every lazy cleanup. - Measure peak RSS, not average.
resource.getrusage(RUSAGE_SELF).ru_maxrsstells you the real ceiling. Average memory tells you nothing about whether the next big file kills you. - Run heavy render steps one file per subprocess, so the OS reclaims the memory when the subprocess exits.
- Render at the resolution you need. Inspecting a preview at 60 dpi instead of 300 is the difference between a comfortable run and a swap-storm.
I validated the whole thing on that box: 39 finished products, 856 MB of output, running under a pipeline of roughly 19,000 lines with an agent orchestrator on top. The packaging layer, the part in this kit, is the small, boring, load-bearing piece.
Keep your research folder forever
One structural note, because it cost me real work. The layout that scales is simple: assets/ for raw output, output/ for ready-to-submit files, packs/ for finished zips and covers, scripts/ for the tools, and research/ for notes and scrape logs. I once deleted a research folder to clean up and later needed exactly those notes for a follow-up product. Keep it. Disk is cheap, redoing research is not.
None of this is exciting. That is the point. The art generation gets the attention, but the metadata headers, the upload ledger, the PDF renderer, and the cover packer are what turn a folder of files into 39 things you can actually sell. Those four scripts are the ones I run every week, and they are the reason a 2 GB box is still enough.
If you want the exact scripts instead of the ideas, I packaged them as the pipeline starter kit that grew out of this work. They sit alongside the vector prompt pack I sell, which is the content side of the same pipeline. The scripts are the tool I built because I got tired of rejected CSVs at 2am, and I would rather hand them over than describe them a fourth time.
Building digital products? Free guides & kits for digital product sellers.
Top comments (0)