<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: wang</title>
    <description>The latest articles on DEV Community by wang (@chinaweop).</description>
    <link>https://dev.to/chinaweop</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4222278%2F6be5f575-59ad-491e-b787-dda9053818e6.jpg</url>
      <title>DEV Community: wang</title>
      <link>https://dev.to/chinaweop</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chinaweop"/>
    <language>en</language>
    <item>
      <title>I Let 20 Node Scripts Run My Entire Product Launch - Every Trick and Every Failure Included</title>
      <dc:creator>wang</dc:creator>
      <pubDate>Sun, 08 Nov 2026 12:53:26 +0000</pubDate>
      <link>https://dev.to/chinaweop/i-let-20-node-scripts-run-my-entire-product-launch-every-trick-and-every-failure-included-1f76</link>
      <guid>https://dev.to/chinaweop/i-let-20-node-scripts-run-my-entire-product-launch-every-trick-and-every-failure-included-1f76</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Honest numbers up front: &lt;strong&gt;74 store views, 0 sales, 1 follower&lt;/strong&gt;. 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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclosure: links to my own store at the end, including a free sample. Everything described here is real and reproducible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;No SaaS, no LangChain, no API wrappers. Just:&lt;/p&gt;

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

&lt;p&gt;The whole thing lives in ~20 scripts, each one single-purpose: &lt;code&gt;x_post.js&lt;/code&gt;, &lt;code&gt;hn_comment.js&lt;/code&gt;, &lt;code&gt;gum_analytics.js&lt;/code&gt;, &lt;code&gt;devto_publish.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trick 1: the single-call browser lifecycle
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chromePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--remote-debugging-port=9222&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--user-data-dir=D:/bot/chrome-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--no-first-run&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;detached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stdio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ignore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// connect, work, close — all inside one call&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Session cookies persist in the profile directory. This one pattern fixed 80% of my flakiness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trick 2: reading your own inbox for login codes
&lt;/h2&gt;

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

&lt;p&gt;Lessons the hard way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Codes can be &lt;strong&gt;6 or 8 digits&lt;/strong&gt; — match &lt;code&gt;\d{6,8}&lt;/code&gt; and exclude the bounce-token numbers that appear in the sender address&lt;/li&gt;
&lt;li&gt;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)&lt;/li&gt;
&lt;li&gt;The code entry box often only appears after clicking a DIV like "Sign in with code" — real buttons are rare in modern React UIs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Trick 3: platforms without email signup
&lt;/h2&gt;

&lt;p&gt;One community platform I wanted to post on removed email registration entirely — Google OAuth only. I didn't give up: I extracted the Firebase &lt;code&gt;apiKey&lt;/code&gt; from the OAuth popup URL, created the account via the public &lt;code&gt;accounts:signUp&lt;/code&gt; REST endpoint, sent myself a &lt;code&gt;VERIFY_EMAIL&lt;/code&gt; 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 &lt;code&gt;CustomEvent&lt;/code&gt; their Google-auth island listens for. I found the event name by reading their bundled JS.&lt;/p&gt;

&lt;p&gt;Is this clever or cursed? Yes. It worked in one evening.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trick 4: React inputs eat naive keystrokes
&lt;/h2&gt;

&lt;p&gt;Typing into a React textarea with &lt;code&gt;.fill()&lt;/code&gt; or raw key events gets silently ignored. Two options that always work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;element.focus()&lt;/code&gt; via &lt;code&gt;evaluate&lt;/code&gt;, then &lt;code&gt;page.keyboard.type()&lt;/code&gt; — for editors that behave like real inputs&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;native setter&lt;/strong&gt; trick — call &lt;code&gt;Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value').set&lt;/code&gt;, dispatch an &lt;code&gt;input&lt;/code&gt; event, and React's state updates properly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I use #2 for titles and markdown bodies, #1 for contenteditable tweet composers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failures (per platform, honest)
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  The scoreboard after 8 days
&lt;/h2&gt;

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

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

&lt;h2&gt;
  
  
  What I'd tell last-week me
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Automate &lt;em&gt;after&lt;/em&gt; finding one channel with real readers, not before&lt;/li&gt;
&lt;li&gt;The comment section of other people's posts outperforms your own post into the void&lt;/li&gt;
&lt;li&gt;Honest build-in-public numbers (like this post) travel further than polished promo&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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: &lt;a href="https://9045830696405.gumroad.com/l/qwpmqd" rel="noopener noreferrer"&gt;free sample here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ask me anything about the scraping, the login-code reader, or the Firebase REST route — happy to share actual script snippets.&lt;/p&gt;

</description>
      <category>automationashowdevsideprojecti</category>
    </item>
    <item>
      <title>I stopped guessing what sells on Gumroad — and built two tools from my own data</title>
      <dc:creator>wang</dc:creator>
      <pubDate>Mon, 02 Nov 2026 13:06:51 +0000</pubDate>
      <link>https://dev.to/chinaweop/i-stopped-guessing-what-sells-on-gumroad-and-built-two-tools-from-my-own-data-1io2</link>
      <guid>https://dev.to/chinaweop/i-stopped-guessing-what-sells-on-gumroad-and-built-two-tools-from-my-own-data-1io2</guid>
      <description>&lt;p&gt;When I listed my first digital product, Gumroad showed me a price field and nothing else. No market, no benchmark, no idea whether my niche was viable or dead on arrival. So I did what you do when a dashboard is empty: I went and got the data myself.&lt;/p&gt;

&lt;p&gt;Two problems turned up, and two tools came out of fixing them. Here's the short version — in case you're about to make the same blind guesses I did.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 1: you pick a niche and a price blind
&lt;/h3&gt;

&lt;p&gt;44% of Gumroad products earn exactly $0. Most of them never stood a chance, because the seller skipped the research step entirely. After I pulled live bestseller rankings for 14 keywords and analyzed a platform dataset of &lt;strong&gt;146,271 products and $206M in tracked revenue&lt;/strong&gt;, a few numbers changed how I build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;$30–49 price band converts ~28% better&lt;/strong&gt; than under-$10 pricing. Cheap is not a strategy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Downloads outsell courses 2.5x&lt;/strong&gt; by volume. A PDF people own beats a course people start.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;77.3% of revenue goes to the top 1%&lt;/strong&gt; of products. This is a winner-take-most market — which means picking the right category matters more than your marketing.&lt;/li&gt;
&lt;li&gt;Category economics vary wildly: Software Development averages ~$60k per product, Writing &amp;amp; Publishing ~$15k with only 226 competitors. Your category choice is worth more than your copy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trap is obvious in hindsight: most people open the editor before they open the spreadsheet. I built the &lt;strong&gt;&lt;a href="https://9045830696405.gumroad.com/l/yjzgqg" rel="noopener noreferrer"&gt;Gumroad Seller Toolkit&lt;/a&gt;&lt;/strong&gt; to make that research step take 15 minutes instead of a weekend — live bestseller data, the 146k-product analysis, a pricing calculator, and a 5-gate niche selector that kills bad ideas in ten minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 2: your product looks like a printout
&lt;/h3&gt;

&lt;p&gt;So you did the research, you wrote the guide, and then you export it with print-to-PDF. It looks like a document, not a product. Buyers judge by the cover — literally. Marketplace data shows well-presented products earn multiples of identical content that looks like a bare printout.&lt;/p&gt;

&lt;p&gt;I got tired of fighting a design tool's export dialog for three hours, so I wrote a one-command tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python forge.py content.md &lt;span class="nt"&gt;--theme&lt;/span&gt; indigo &lt;span class="nt"&gt;--kicker&lt;/span&gt; &lt;span class="s2"&gt;"YOUR BRAND"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; product.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In comes your markdown; out comes a product-grade PDF — a dark branded cover with a title and promise line, then styled body pages with colored headings, callout boxes, clean lists, and proper code blocks. Four themes tuned to niches (tech, creator/AI, business, marketing), CJK font support, and the only dependency is &lt;code&gt;reportlab&lt;/code&gt; — no paid API, no telemetry, runs fully offline. That's the &lt;strong&gt;&lt;a href="https://9045830696405.gumroad.com/l/qpvsep" rel="noopener noreferrer"&gt;PDF Product Forge&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The order that actually works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Research first&lt;/strong&gt; (is the category viable? what's the price anchor?).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the product&lt;/strong&gt;, not a printout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish&lt;/strong&gt; and let the data tell you what to iterate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I turned the full research — the 146k-product analysis, the live bestseller pull, the pricing model, and the rendering workflow — into those two tools so I'd stop re-doing the work every time I ship something. If you're at step 1 right now, start with the dataset; if you're at step 2, start with the PDF tool.&lt;/p&gt;

&lt;p&gt;Happy to answer setup or pricing questions in the comments — especially if your first product is sitting at $0 and you don't know whether it's the price or the product.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
