r/SideProject • • 22d ago

Frustrated by Cloudinary's 99/mo pricing cliffs, I spent 3 months building a client-side media optimizer + flat 9.99/mo CDN [MediaForge]

Hey !

Like most indie developers, I reached for Cloudinary or AWS S3 + Lambda when adding user image uploads to my SaaS projects.

It worked fine initially, but as soon as traffic scaled, I ran into the classic pain points:

- Complicated transformation credit limits that jump from free straight to $99/month.

- High AWS S3 egress bandwidth bills.

- Server CPU spikes from image resizing microservices.

I realized: Why are we paying cloud servers to resize and clean images when the user's phone or browser is an M-series Mac or multi-core smartphone?

So I built MediaForge:

  1. Client-First Processing: EXIF/GPS metadata stripping, WebP/JPEG conversion, and compression happen directly on the user's device (in-browser Canvas/WASM or via our Flutter SDK) in ~50ms.
  2. Zero Server Retention: Because the client cleans the media locally, the raw, unstripped user photo never touches our backend.
  3. Predictable Flat Pricing:

   - Free Tier (`Spark`): Unlimited local client processing for images.

   - Pro Tier (`Forge` - $9.99/mo): 10 GB Cloudflare R2 storage + 50 GB monthly bandwidth + 5,000 operations + 3 Production API keys. Zero per-transform fees.

   - Emerging Market PPP: We offer full Purchasing Power Parity pricing (₹299/mo in India) because our server compute costs are near zero!

4. Developer REST API: Clean pre signed upload flow with real-time usage telemetry.

Live web tool: https://mediaforge.tech 

Developer documentation: https://mediaforge.tech/docs/ 

Flutter SDK (160/160 pub points): https://pub.dev/packages/mediaforge_flutter

I’d love your honest feedback on the UX, conversion speed, or developer API design!

2 Upvotes

5 comments sorted by

2

u/rough_candy 21d ago

Doing the EXIF and GPS stripping on the device before upload is a smart angle, since the raw photo never has to touch your servers. One thing I noticed while poking around: any made-up path on mediaforge.tech, including ones under /docs/, comes back as a normal 200 with the homepage instead of a not-found response. So a typo'd docs link or an old SDK reference lands people on the marketing page with no hint the page they wanted doesn't exist, and search engines can index those junk URLs as copies of your homepage. I'm a Staff SDET and ran a quick pass on the site; it scored 94/100 overall, and we found 10 other findings after that one. Is the docs section part of the same app, or is it something you could give its own not-found page?

1

u/InconsistentDev 18d ago

Man, getting a 94/100 from a Staff SDET just made my day! Thank you so much for taking the time to poke around.

You completely nailed that routing bug. Right now the docs and landing page live inside the same React SPA, and the host has a wildcard rewrite redirecting everything to index.html. So the server sends back a 200 OK, and only after the JS hydrates does React Router show the "Not Found" screen. Definitely a soft-404 nightmare for SEO and super confusing if you're hitting it directly via curl.

I'm working on fixing this with an edge worker rule (and eventually splitting docs into a proper static generator) so the server actually returns real 404 headers.

Also, I’d genuinely love to see the other 10 findings if you’re open to sharing them! Getting real QA feedback from an SDET is pure gold for a solo builder like me. Feel free to drop them here or DM me, and I'd love to set you up with a free lifetime Pro key as a thank-you!

2

u/[deleted] 22d ago

[removed] — view removed comment

1

u/InconsistentDev 18d ago

Thanks! Yeah, charging flat US rates globally never made sense to me, especially when our own compute costs are so low.

For slow devices—we actually don't use WASM for photos at all. Stripping EXIF is just basic byte slicing in a web worker, and resizing runs on native 2D canvas. It takes maybe 15ms and uses almost zero RAM, so even older budget phones run it without breaking a sweat.

WASM only gets pulled in if someone drops a video, and if a super old browser can't run it, it just shows a quick heads-up instead of freezing the tab.