DEV Community

wang
wang

Posted on

I Let 20 Node Scripts Run My Entire Product Launch - Every Trick and Every Failure Included

Eight days ago I launched 9 digital products on Gumroad. Since then, my entire marketing operation — posting, logging in, reading verification codes, checking my store analytics — has been run by about 20 Node scripts and one Chrome window I never touch.

Honest numbers up front: 74 store views, 0 sales, 1 follower. This post is not a success story. It's the full technical playbook of what I automated, how it works, and everything that broke along the way. If you're an indie builder who wants a machine to do your distribution while you sleep, this is the guide I wish I had last week.

Disclosure: links to my own store at the end, including a free sample. Everything described here is real and reproducible.

The stack

No SaaS, no LangChain, no API wrappers. Just:

  • Chrome DevTools Protocol via playwright-core, connecting to a long-lived Chrome instance with a persistent profile
  • One bash wrapper that spawns the browser, does the work, and kills it — because a browser left running between automation calls dies to power management
  • Firebase REST API for platforms that removed email signup
  • A QQ Mail reader that opens webmail in the same browser and extracts login codes

The whole thing lives in ~20 scripts, each one single-purpose: x_post.js, hn_comment.js, gum_analytics.js, devto_publish.js.

Trick 1: the single-call browser lifecycle

My first version kept Chrome running between tasks. It kept dying, and every reconnect failed. The fix that stuck: every automation call spawns its own browser, does all its work, then closes. No state survives in memory — only the on-disk profile carries logins.

const ch = spawn(chromePath, [
  '--remote-debugging-port=9222',
  '--user-data-dir=D:/bot/chrome-profile',
  '--no-first-run',
], { detached: true, stdio: 'ignore' });
// connect, work, close — all inside one call
Enter fullscreen mode Exit fullscreen mode

Session cookies persist in the profile directory. This one pattern fixed 80% of my flakiness.

Trick 2: reading your own inbox for login codes

For platforms that only offer magic-link or code login, the script opens webmail in a second tab of the same browser, finds the newest mail from the platform, and extracts the code with a regex.

Lessons the hard way:

  • Codes can be 6 or 8 digits — match \d{6,8} and exclude the bounce-token numbers that appear in the sender address
  • Filter by the platform's name in the row, not just "newest mail" (I once read a 2-year-old verification code from a different service)
  • The code entry box often only appears after clicking a DIV like "Sign in with code" — real buttons are rare in modern React UIs

Trick 3: platforms without email signup

One community platform I wanted to post on removed email registration entirely — Google OAuth only. I didn't give up: I extracted the Firebase apiKey from the OAuth popup URL, created the account via the public accounts:signUp REST endpoint, sent myself a VERIFY_EMAIL oob code, clicked through verification in the browser, logged in with password, and then — the key step — triggered the site's own username form by dispatching the exact CustomEvent their Google-auth island listens for. I found the event name by reading their bundled JS.

Is this clever or cursed? Yes. It worked in one evening.

Trick 4: React inputs eat naive keystrokes

Typing into a React textarea with .fill() or raw key events gets silently ignored. Two options that always work:

  1. element.focus() via evaluate, then page.keyboard.type() — for editors that behave like real inputs
  2. The native setter trick — call Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value').set, dispatch an input event, and React's state updates properly

I use #2 for titles and markdown bodies, #1 for contenteditable tweet composers.

The failures (per platform, honest)

Platform What happened
X/Twitter New accounts get search rate-limited ("Something went wrong") for days. 280-char limit silently disables the Post button — verify text length before clicking
Reddit Multi-account from one IP = ban wave, no appeal. Only manual commenting works there
Hacker News Title limit is 80 chars. And right now HN is temporarily blocking Show HNs from new accounts (redirects to a showlim notice page)
Indie Hackers Publishing gated behind "established members" — 3 good comments in, still waiting
dev.to Magic code flow works perfectly. The "Sign In with Code" submit is a DIV, not a button

The scoreboard after 8 days

  • 74 store views, 0 sales, 0 discount-code uses
  • X: 12 posts, 1 follower, single-digit views per post
  • 3 dev.to articles (this is #4)
  • 2 platforms blocked me by policy, not by bug

The honest diagnosis: I built distribution infrastructure before I had distribution. A robot posting into zero-follower accounts is still zero followers. The scripts all work — the audience doesn't exist yet.

What I'd tell last-week me

  1. Automate after finding one channel with real readers, not before
  2. The comment section of other people's posts outperforms your own post into the void
  3. Honest build-in-public numbers (like this post) travel further than polished promo

The automation playbook — 14 chapters covering the four-layer architecture (agent / data / network / output) and every dead attempt — plus a free 2-page sample of my China trend report are on my Gumroad store: free sample here.

Ask me anything about the scraping, the login-code reader, or the Firebase REST route — happy to share actual script snippets.

Top comments (0)