Building LinkedIn-ify: A Satirical AI Post Generator
#web development#learning#developers#nextjs#web resources

Building LinkedIn-ify: A Satirical AI Post Generator

Author
Kurt Chan
Coffee Driven Developer
20 hours ago

5 mins read


The Idea

It started as a joke. A running bit with developer friends about how LinkedIn posts follow the same formula regardless of what actually happened: open
with a dramatic hook, inflate the mundane event into a career-defining moment, thank five unrelated people, close with a vague philosophical question.

So I decided to automate it.

LinkedIn-ify is a small Next.js app that takes any ordinary input — "I ate lunch alone," "My code finally worked after 3 hours," "I got my driving
license" — and uses Google Gemini to rewrite it as a perfectly plausible LinkedIn post. The kind a real person might actually post. Unironically.

The Goal

Keep it small, ship it fast. The constraints I set for myself:

  • One page, no auth, no database
  • The AI does the heavy lifting — prompt engineering over model fine-tuning
  • Output should feel like a real screenshot, not a mockup
  • Must be shareable (copy text, download as PNG, or native share on mobile)

The stretch goal was to make it so convincing that someone might actually use it unironically. I think I got close.

The Stack

  • Next.js App Router — specifically for Server Actions, which made the AI call feel like calling a local function from the client without spinning up an
    explicit API route
  • Google Gemini (gemini-2.5-flash) — I started on a preview model (gemini-3.1-flash-lite-preview) but switched after a notice that it will now be removed for preview
  • React Hook Form + Zod — form validation and type safety from a single schema definition
  • Tailwind CSS + shadcn/ui — unstyled primitives, all the polish is custom
  • Upstash — Redis-backed rate limiting by IP so one person can't drain the Gemini quota in one session
  • html-to-image — renders the output card to a PNG for download and sharing
  • Sonner — toast notifications for errors and success states

The Prompt Engineering Was the Real Work

The core challenge wasn't the UI. It was the prompt.

The app needed to produce output that read like a real LinkedIn post — not parody, not obvious satire. The inflation had to be subtle enough that a reader
might actually believe a real person wrote it.

I landed on a system prompt with three moving parts:

Archetypes. Four personas the AI randomly draws from: the Hustle Guru, the Vulnerable Overcomer, the Humble Bragger, and the Vague Philosopher. Each has
its own voice, structural patterns, and emotional register. I expose these as user-selectable options in the UI so you can target a specific flavor, or
leave it random.

Language Inflation Rules. The core mechanic. A set of examples showing how to dress up mundane events in professional language without crossing into
obvious absurdity. "I worked at McDonald's" becomes "associate at a multinational firm in the service industry with revenue exceeding $20 billion." The original event is still traceable — just buried.

Realism Rules. The guardrails. If the output reads like obvious parody, it fails. Adding one invented specific detail (a time, a number, a place) makes it
feel lived-in. The lesson should feel discovered, not manufactured.

The output format uses a ---TAGS--- delimiter to separate post body from hashtags. Simple and reliable — no JSON parsing, no structured output mode, just a string split.

Problems Encountered

Model Versioning


The first model I used (gemini-3.1-flash-lite-preview) started producing inconsistent output mid-development — sometimes ignoring the archetype, sometimes returning JSON when it should have returned plain text. Switching to gemini-2.5-flash fixed it. Lesson: preview models move fast; pin to a stable version or build tolerance for format drift.

The Share Button Was Messier Than Expected


Capturing the card as an image sounds simple. It wasn't.

html-to-image needs an explicit backgroundColor or the PNG exports transparent. The Web Share API is inconsistent across browsers — you need to check navigator.canShare({ files: [...] }) before passing a file, then fall back to text-only share, then fall back to clipboard copy. And AbortError gets
thrown when the user dismisses the native share sheet, which shouldn't trigger an error toast but does if you're not filtering it.

All three code paths (download PNG, copy image to clipboard, native share) needed separate try/catch blocks with their own failure modes.

Fake Engagement Numbers That Don't Flicker


The output card shows fake like/comment/repost counts to complete the illusion. The obvious implementation — Math.random() — meant the numbers changed on every re-render, which looked broken.

The fix: seed the random from body.length with a simple modulo. Same body, same numbers. It's not cryptographically stable, but it's stable enough for a
UI.

text
function fakeCount(seed: number, min: number, max: number) { return min + (seed % (max - min)) } const likes = fakeCount(seed * 7, 312, 2800)

What Made It Fun

The prompts. Watching "I made my bed this morning" come out as a 90-word meditation on discipline and self-leadership is genuinely funny every time.

The archetype system also added replayability. The same input routed through "Vulnerable Overcomer" versus "Hustle Guru" produces completely different
posts. Getting that distinction consistently from a single LLM without fine-tuning — just prompt design — was the most satisfying part.

The loading copy reads "Inflating your achievements…" and I'm not changing that.

What I'd Do Differently

Structured output from the start. Using a ---TAGS--- delimiter is fragile — if the model includes it mid-body for some reason, the split breaks. Gemini's
structured output mode would have been cleaner and worth the extra setup.

A better model fallback. Right now, if the model is at capacity, the user gets an error. A queue with a retry would be a nicer UX, even if just a simple
client-side retry with exponential backoff.

Try It

The app is live. Drop in something mundane and see how professional it sounds on the other end.

Built with Next.js, Gemini, Tailwind, and too much time reading LinkedIn posts ironically.


Written by

Author
Kurt Chan
Coffee Driven Developer
20 hours ago
Building LinkedIn-ify: A Satirical AI Post Generator