DEV Community

孫昊
孫昊

Posted on

I Shipped 5 Gumroad SKUs in 24 Hours via Browser Automation. Here is What Worked.

TL;DR: Day 60 of an indie iOS dev experiment. Yesterday: 3 Gumroad SKUs LIVE. Today: 2 more (ASC API Toolkit $499, AutoApp Dashboard $39). Total catalog: $572. The bottleneck wasn't writing the products — it was the Gumroad bureaucracy. Browser automation cut that to 90 seconds per SKU.


The pile-up

When you've been writing a product for 6 weeks and finally have the PDF + cover + description ready, the LAST thing you want is a 20-step Gumroad checkout-to-publish flow. But that's exactly what Gumroad asks:

  1. Click "New product"
  2. Pick "Digital product" radio
  3. Set currency to USD
  4. Fill name + price
  5. Click "Next: Customize"
  6. Wait for product edit page to load
  7. Upload PDF (drag-drop or file picker)
  8. Wait for upload
  9. Fill description (contenteditable, no plain textarea)
  10. Click "Save and continue"
  11. Add cover image
  12. Set tags
  13. Configure pricing tiers
  14. Set up upsells
  15. Save again
  16. Open Share tab
  17. Generate permalink
  18. Set up URL slug
  19. Click "Publish"
  20. Verify the public URL

For one SKU, fine. For 5 in a launch wave, that's 100 clicks, 50 wait moments, 10+ context switches. I'd rather automate.

What I built

I have a gumroad_uploader.py script (~700 lines, MIT) that drives Gumroad via Chrome DevTools Protocol + Playwright. The script encodes the 20-step flow as a typed ProductSpec dataclass and walks through it.

@dataclass(frozen=True)
class ProductSpec:
    slug: str
    permalink: str
    name: str
    description: "str"
    price_usd: float
    cover_path: Path
    file_path: Path
    is_bundle: bool = False
    tags: tuple[str, ...] = ()
Enter fullscreen mode Exit fullscreen mode

For each spec, the script:

  1. Navigates to /products/new (uses persistent Chrome session = logged in once)
  2. Clicks "Digital product" radio
  3. Fills name + price
  4. Clicks "Next" — waits for /products//edit URL
  5. Uploads PDF via file input
  6. Fills description (Gumroad uses [aria-label="Description"] contenteditable)
  7. Clicks "Save and continue"
  8. (Manual: cover image — Gumroad rejects programmatic file uploads to the cover slot)
  9. Verifies public URL HTTP 200

For the 2 SKUs I shipped today (ASC API Toolkit + AutoApp Dashboard), this took ~90 seconds each. Total wall-clock for both: 3 minutes.

What works

1. Persistent Chrome session

Use --user-data-dir=/path/to/persistent when launching Chrome with --remote-debugging-port=9222. Login once, the session persists across restarts. This is critical because Gumroad's anti-bot increasingly sees fresh sessions as suspicious.

chrome.exe \
    --remote-debugging-port=9222 \
    --remote-allow-origins=* \
    --user-data-dir="$HOME/.gumroad-cdp-profile" \
    --no-first-run --no-default-browser-check
Enter fullscreen mode Exit fullscreen mode

2. Multi-selector resilience

Gumroad's React UI changes selectors across releases. My script tries multiple selectors per field:

SELECTORS = {
    "name_input": [
        "LABEL:Name",                       # Playwright's get_by_label
        'input[name="name"]',
        'input[aria-label="Name"]',
        'input[placeholder*="Name"]',
        'input[id*="name"]',
    ],
    ...
}
Enter fullscreen mode Exit fullscreen mode

The custom LABEL: prefix uses page.get_by_label() which is the most stable across Gumroad's redesigns.

3. The "Next" button needs a real submit

The "Next: Customize" button looks like a button but actually triggers a React form submit. If you click it programmatically without focus on the price field, the form doesn't submit. Fix:

price_input.click()
price_input.press("End")
next_btn = page.locator('button[type="submit"]:has-text("Next")').first
next_btn.click()
Enter fullscreen mode Exit fullscreen mode

4. Description editor is contenteditable, not textarea

Gumroad's description field looks like a textarea but is actually [aria-label="Description"] contenteditable. Use Playwright's .fill() (not direct value set):

desc = page.locator('[aria-label="Description"]').first
desc.click()
time.sleep(0.5)  # let cursor settle
desc.fill(description)
Enter fullscreen mode Exit fullscreen mode

What doesn't work (yet)

1. Cover image upload

Gumroad's cover image slot has additional drag-drop validation that rejects Playwright's set_input_files(). I haven't found a reliable way around this. Cover image is the only step still manual.

2. Bundle product picker

When creating a Bundle SKU, the "Add products to bundle" picker only shows products that have been published 24+ hours ago. New SKUs from the same launch session don't appear in the picker due to indexing delay.

I created a Bundle SKU draft today ("Indie Hacker 2026 Toolkit") — it's parked, will add yesterday's 3 SKUs to it tomorrow once they index.

3. Affiliate enable for new SKUs

Same indexing delay. New SKUs don't show in the affiliate program product picker for 24h. Setup affiliates with existing SKUs first, add new ones the next day.

Why this matters at indie scale

The unit economics:

  • Manual upload time per SKU: 15-25 minutes (with reading + filling + verifying)
  • Automated time per SKU: 90 seconds + cover image (~1 min manual)
  • Time saved per SKU: ~15 minutes
  • Time saved on a 5-SKU launch wave: 75+ minutes

That's not "more SKUs faster." That's "more SKUs feasible." When manual cost is 15 min, you ship 1-2 SKUs per session. When automated cost is 1.5 min, you ship 5+ in the same focus block. The catalog grows faster.

The 5 SKUs LIVE today (Day 60)

For context, here's what's in my Gumroad catalog after this wave:

  1. iOS Indie Launch Playbook ($19) — 50pp PDF
  2. 30-Day B2B Cold Email Templates ($15) — 25 templates × 5 ICPs
  3. 14 iOS Rejection Reasons (FREE) — lead magnet
  4. NEW ASC API Toolkit ($499) — 60+ Python scripts
  5. NEW AutoApp Dashboard ($39) — manifest-driven indie tool stack

Plus an affiliate program at 30% commission (writeup).

Source

The actual gumroad_uploader.py: github.com/jiejuefuyou (MIT). 700 LOC, no dependencies beyond playwright. Tested against Gumroad's UI as of 2026-05-07.


If you're shipping multiple Gumroad SKUs in 2026 and want the proven automation playbook + the 50pp PDF on iOS launches: iOS Indie Launch Playbook covers the full 60-day toolkit.

Top comments (0)