DEV Community

Cover image for Pricing Digital Asset Kits For Global Buyers: What 39 Products Taught Me About Tiered CSV Channels

Pricing Digital Asset Kits For Global Buyers: What 39 Products Taught Me About Tiered CSV Channels

Last March I priced a sticker pack at $12 flat and watched a buyer from the Philippines abandon checkout twice in one evening. Same pack, same files, same cover. The price was fine for someone in Berlin and completely wrong for someone in Manila, and I had built 38 other products with the same one-size price. That night I opened a spreadsheet and started rebuilding the whole pricing layer around tiers and channel-specific CSVs. Here is what 39 products taught me.

One price is a tax on your cheapest markets

When you sell digital assets, your costs are basically zero per copy. That means the only thing a flat price does is decide who gets excluded. A $12 vector pack is a casual purchase in the US, a considered purchase in Brazil, and a non-purchase in a lot of other places. Purchasing power differences are real and large, and platforms know this. Gumroad lets you set up tiered pricing and even has a purchasing power parity option that discounts automatically for buyers in lower-income countries. I ignored that for months because setting it up felt like a chore. It is not a chore. It took about twenty minutes per product, and on the next pack I sold roughly the same number of units at full price while picking up a stream of discounted international sales that simply did not exist before.

The lesson is not "charge everyone less". It is: define three tiers, full price, a mid tier, and a parity-adjusted floor, and let the channel apply the right one.

Every channel wants a different CSV, and they reject wrong headers instantly

If you also feed stock channels instead of only selling direct, pricing and metadata live in the same file, and each platform is picky in its own way. My pipeline writes three formats from one folder of assets:

  • Adobe Stock wants a 5-column CSV header. Get one column wrong and the whole upload fails before review even starts.
  • Vecteezy wants a 4-column header. Different column set, same folder of files.
  • Dreamstime wants 15 columns. Fifteen. Same assets, three times the metadata work if you do it by hand.

I wrote make_metadata.py so it emits the exact header each channel demands and nothing else, because I got tired of the instant rejection emails. The pricing insight here: your per-asset metadata is the same across channels, but your revenue per download is completely different. Stock sites pay cents per download. Direct sales pay dollars. So the tiered price you set on Gumroad has nothing to do with the royalty structure on Vecteezy, and you should stop pretending one pricing sheet covers both. I keep them separate: a pricing tier file for direct sales, and channel CSVs that carry only what each platform's spec requires.

Tier the product, not just the price

A discount with nothing behind it feels cheap. A tier with real scope differences feels like a choice. Across my 39 products I settled on a pattern that works:

  • Base tier: the asset files plus the metadata CSVs, ready to upload.
  • Mid tier: adds the PDF documentation, generated from Markdown with a script so it costs me nothing per copy.
  • Top tier: adds the source files and the cover plus thumbnail renders at 1280 by 720 and 600 by 600.

Because my packaging script pack_product.py already produces the zip, the cover, and the thumbnail in one command, making a second and third tier of the same product costs me minutes, not hours. That is the whole trick. Tiers only work if the marginal cost of an extra tier is near zero. If tiering your product means hand-building a second bundle, you will not keep it up past product number five, let alone 39.

Never double-post, especially when testing prices

Here is a failure that cost me real anxiety. When I started experimenting with tiered listings, I re-ran a batch upload to "refresh" a listing. The tracker I had at the time was a text file I forgot to update. The same asset went up twice on one channel. That is the fastest way I know to get an account flagged, because from the reviewer's side it looks like duplicate spam, not an accident.

upload_tracker.py exists because of that mistake. It is a ledger with three commands, pending, done, and status, and a re-run can never post the same asset twice. When you are iterating on pricing and metadata across three channels, you will re-run things. Make the tooling make that safe, because willpower does not survive a long upload day.

Run the whole thing on hardware you already have

None of this needs a cloud bill. The entire pipeline, metadata generation, tracking, PDF rendering, packaging, 39 products, 856 MB of output, ran on a single vCPU with 2 GB of RAM and no GPU. The habits that made it work: one process at a time, gc.collect() between assets, measuring peak RSS with resource.getrusage instead of guessing, one file per subprocess for heavy renders, and inspecting previews at 60 dpi instead of 300. If your pricing experiments keep failing because the pipeline is fragile or expensive to run, fix the pipeline first. Cheap infrastructure is what makes tiered experiments cheap to run.

What I would tell myself a year ago

Flat pricing was the single easiest fix in my whole catalogue, and I put it off longer than any technical problem. The order that actually worked: fix the CSV headers per channel first, because rejections waste more time than anything else. Then add the upload tracker so iteration is safe. Then introduce three tiers per product and a parity discount for direct sales. Total setup cost across the catalogue was a few evenings. The international sales that showed up afterward were not dramatic, but they were steady, and they cost nothing to serve.

Everything above is the packaging and pricing layer of a larger pipeline, roughly 19,000 lines built on top of 300-plus pages of research, and I have pulled the four scripts that do this specific job into the pipeline starter kit: make_metadata.py for the Adobe, Vecteezy, and Dreamstime CSVs, upload_tracker.py for safe re-runs, md2pdf.py for tier documentation, and pack_product.py for bundles and covers. Two dependencies, Pillow and reportlab, and the metadata and tracking scripts need nothing but Python. It is the tool I built out of the 39-product mess described above, nothing more.

Get pipeline starter kit


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

Top comments (0)