I still have the rejection email open in a tab. Adobe bounced 14 of my vectors in one batch because my CSV header had six columns instead of five. Vecteezy wanted four. I had written one spreadsheet and assumed it worked everywhere. It did not. That afternoon cost me two weeks of queue time, and queue time is the only thing a solo seller cannot buy back.

That failure is why the pipeline I run now starts with metadata and tracking, not with prompts. Here is what actually works, with the numbers from my own register.

One prompt engine, many products, but the bottleneck is not the art

The prompt engine I built produced a steady stream of vector assets. Making the art was the easy part. What stalled me, over and over, were four unglamorous things: writing upload CSVs in each platform's exact format, remembering what I had already submitted, turning documents into sellable PDFs, and packaging a zip with a cover that does not look like an afterthought.

Once I scripted those four steps, one engine turned into 39 finished products, 856 MB of output, running on a server with 1 vCPU, 2 GB RAM, and no GPU. No cloud account, no framework. Four standalone Python scripts and two third-party packages total: Pillow for covers, reportlab for PDFs. The metadata and tracking scripts use the standard library alone.

The CSV headers are not negotiable

Adobe's bulk upload template has 5 columns. Vecteezy has 4. Dreamstime has 15. All three reject a wrong header instantly, before anyone looks at your art. There is no partial credit and no warning, just a failed batch and a support ticket if you cannot figure out which column you got wrong.

So the metadata script writes the header each platform demands and nothing else. It walks a folder of files, title-cases the filename into a title, and emits the CSV. If I pass a titles.json with real titles and keywords, it uses those instead. The filename fallback is fine for a first pass, but I always replace it before submitting, because a title like "asset_0041_final" reads as spam to a reviewer and to a buyer.

Double-posting is the fastest way to get flagged

This one bit me early. I re-ran a batch script, forgot it had already submitted half the queue, and posted duplicates. Platforms treat that as a quality problem, and repeated duplicates can get an account flagged. The fix was dumb and effective: a ledger.

The tracker is a flat file with three commands. pending items.txt shows what is not done yet, done "asset-001.jpg" marks something finished, status gives the overview. Any batch step checks the ledger before it acts, so a re-run can never double-post. It is the least interesting code in the project and the code I would least want to lose.

Packaging is where a file becomes a product

A bare PDF does not sell. A zip with a real cover does. The packaging step does three things in one command: zips the files, renders a cover at 1280x720, and a thumbnail at 600x600. Those two sizes cover the listing images every marketplace I sell on asks for, so I never resize by hand.

For turning written content into products, a second script converts Markdown to a styled PDF, headings, tables, lists, links, in one command. My sticker sheets and template guides all go through it.

The folder layout that scales

A catalogue turns into a junk drawer without fixed structure. Mine is five folders: assets for raw output, output for ready-to-submit files plus their CSVs, packs for finished zips and covers, research for notes and sources, scripts for the tools.

The one I would defend hardest is research. I once deleted my scrape logs and notes to "clean up". Those notes were the raw material for the next three products. Keep them forever.

Notes for running on a tiny box

If you are doing this on a cheap VPS like I am, 1 vCPU and 2 GB RAM is enough, but only with discipline:

  • One process at a time. Never fan out image jobs in parallel on a single core.
  • Call gc.collect() after each asset to free memory between items.
  • Measure peak RSS, not average. resource.getrusage(RUSAGE_SELF).ru_maxrss tells you the real ceiling, and the real ceiling is what gets you OOM-killed.
  • Run heavy render steps as one file per subprocess so memory returns to the OS.
  • Render at the resolution you need. Inspecting a preview at 60 dpi instead of 300 saved me more memory than any other single change.

The full pipeline behind these scripts is about 19,000 lines, with 300+ pages of research behind the rules the scripts enforce. The four tools here are just the packaging layer, but they are the layer that took me from a folder of files to 39 products I could actually list.

I bundled those exact scripts, the ones that produced the 39 products, into the vector prompt pack. It is not a tutorial that ends at "here's how you'd do it". It is the working tools, validated on the same 1 vCPU, 2 GB RAM box, plus the research behind them. If any of this matched the walls you have been hitting, it will save you the two weeks I lost.

Get vector prompt pack

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