Skip to content

Build1 publisher3 min readPublished

The 43MB Secret: WhatsApp Automation Fails At Deploy, Not At The Model

A one-German-word-a-day channel took a week, three hosting platforms and a git history rewrite. None of the hard failures were in the AI layer.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened

  • The author (dev.to, btkcodedev) set out to build a WhatsApp Channel that posts one German word every morning at A1 level, with an example sentence and a mnemonic.
  • The project took a week and required a git history rewrite.
  • Gemini can write the daily word, example sentence and mnemonic in a second; the hard part was never the AI and never the German.
  • The project became an argument with WhatsApp's session model, two hosting platforms, and the author's own repo git history.
  • whatsapp-web.js drives a real headless Chrome instance that logs into web.whatsapp.com like a browser would.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

A developer writing as btkcodedev published a postmortem of building something deliberately small: a WhatsApp Channel that posts one A1-level German word each morning with an example sentence and a mnemonic [1]. The content generation was a non-event, since Gemini produces that in a second [3]; the week went to WhatsApp's session model, two hosting platforms, and the repo's own history [2][4].

The pivot point is what `whatsapp-web.js` actually is. It drives a real headless Chrome instance that logs into web.whatsapp.com the way a browser does [5], and it works locally [6]. Its persisted auth state is therefore a full Chromium profile: cookies, IndexedDB, cache [7]. His measured 43MB [8]. GitHub Secrets cap out in the kilobytes [9]. That is three to four orders of magnitude of mismatch [4], and base64 makes it worse, not better, because encoding a 43MB tar produces roughly 57MB of text [1].

Which is why the standard tutorial answer exists: tar the profile, base64 it, paste it into a secret anyway, decode it back into place on every CI run [10]. He shipped that, complete with a `setup.ts` whose entire job was printing a giant blob for manual pasting into GitHub's secret editor [11]. It does not fix the failure it appears to fix, because the session expires on WhatsApp's schedule rather than yours, and a phone offline too long kills it [12], which puts you back at a QR code on a server with no screen [13]. According to the author, two things work: run the linking step once locally against the same database the deployed job reads [14], or watch the CI provider's live log stream, where the QR prints as ASCII art you can scan off a terminal [15].

The platform layer failed independently. He had it deployed on Railway, Render and GitHub at once, and none of them worked [16]. Railway's fair-use policy explicitly bans userbots, meaning anything logging into a personal account over an unofficial reverse-engineered protocol instead of a real bot API [17], which is a precise description of `whatsapp-web.js` [18] and not a defect he could patch [19]. On Render he hit `RemoteAuth` with a Mongo-backed store, which has open, unresolved GitHub issues where the session saves but does not reliably restore, silently demanding a fresh QR scan on restart [20].

What stuck was changing libraries. Baileys speaks WhatsApp's multi-device protocol directly over a WebSocket, with no Chromium and no Puppeteer [21], and its session is a handful of small JSON credential files measured in kilobytes [22]. That fits in a free MongoDB Atlas cluster rather than a secret [23], and with no browser to start, it runs on a constrained free tier instead of choking on headless-Chrome memory pressure [24]. The real requirement was about sixty seconds of compute once per 24 hours [25], a 0.07 percent duty cycle [2], so the answer was a GitHub Actions cron job [26]. Dockerfile, Render and Railway all deleted; the deployment surface became one YAML file [27].

The bill came due in git. He had committed a full `.wwebjs_auth` folder, 204 files, plus standalone tar and base64 dumps at 27MB and 41MB [28]. That folder is a live login session, readable by anyone who could read the repo [29], and deleting it from the working tree leaves it in every earlier commit [30]. `git filter-repo` plus a force-push took `.git` from 84MB to 284KB [31], a roughly 300-fold shrink [3].

Worth watching if you are building this: check your host's acceptable-use policy for userbot language before writing code [17], and treat any credential that will not fit in your secrets manager as evidence the architecture is wrong, not as an encoding problem [10].

Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories