How I Built a Serverless Dynamic Social Media Card Generator with n8n, Express & Puppeteer
Automation

How I Built a Serverless Dynamic Social Media Card Generator with n8n, Express & Puppeteer

How I built a zero-storage, serverless social media card generator using n8n, Express, Puppeteer, and Vercel while working within a tight client budget.

Most engineering stories begin with a cool tech stack. This one began with “we don’t have the budget.” What looked like a simple Facebook automation project quickly turned into a series of architectural roadblocks no VPS, no object storage, and even Vercel refusing to run a headless browser. Every solution created a new problem, forcing me to rethink the architecture from first principles instead of throwing more infrastructure at it. The result wasn’t just a working automation it was a completely serverless image generation pipeline that creates branded social media cards on demand without storing a single file. This is the story of how a tiny budget led to one of my favorite engineering solutions.

One of my recent freelance projects looked simple on the surface:

“Automatically post news articles to Facebook.”

In reality, the biggest challenge wasn’t automation.

It was generating beautiful social media cards without spending money on infrastructure.

This is the story of how a lack of budget forced me to rethink the entire architecture and ultimately led to a better solution.

The Project

The client owns a news website that publishes articles throughout the day.

The goal was to automate the entire Facebook publishing process.

The workflow needed to:

  • Detect a newly published article
  • Fetch the article title and featured image
  • Generate a branded Facebook news card
  • Publish it automatically to Facebook

The automation itself was straightforward.

I built everything inside n8n, which handled the complete workflow perfectly.

Then came the real challenge.

The Problem Nobody Thinks About

Facebook posts perform much better with a custom-designed image rather than simply sharing the article URL.

The client wanted every article to have a branded news card containing:

  • The article title
  • The featured image
  • Their brand styling
  • Consistent layout

The catch?

Everything had to be generated automatically.

My First Idea: Python Image Generation

My initial plan was the traditional approach.

Create the image using Python libraries such as Pillow.

The process would look something like this:

  1. Fetch article data
  2. Generate image
  3. Save image
  4. Upload image
  5. Post to Facebook

Technically, it works.

But there was one problem.

The client didn’t have the budget for a VPS.

Without a server running 24/7, maintaining a Python image generation service wasn’t practical.

So I scrapped that idea.

Second Challenge: Image Storage

Even after switching away from Python, another issue appeared.

Generated images need to live somewhere.

Normally you would upload them to:

  • AWS S3
  • Cloud Storage
  • A VPS
  • Local storage

Again…

No budget.

The client didn’t want to pay for storage just to keep temporary images that would only be used once.

So I started thinking differently.

A Different Perspective

Instead of asking:

“Where should I store the generated image?”

I asked:

“Do I even need to store it?”

That single question completely changed the architecture.

The HTML + CSS Trick

Rather than drawing pixels manually with Canvas or Python, I decided to design the news card exactly like a web page.

Using standard HTML and CSS gave me enormous flexibility.

I could create responsive layouts, typography, gradients, shadows, overlays, and branding using tools I already use every day.

Then came the clever part.

Instead of exporting the design manually…

I simply took a screenshot of it.

Building the Image API

I built a lightweight Express API.

The API accepts parameters such as:

  • Article title
  • Featured image URL

Behind the scenes, it:

  1. Creates an HTML page
  2. Injects the title and image
  3. Opens the page in a headless browser
  4. Takes a screenshot
  5. Returns the screenshot directly as a PNG response

No temporary files.

No uploads.

No storage.

No cleanup.

The image exists only long enough to be sent back to the workflow.

That’s it.

Another Problem Appears

Just when I thought everything was finished…

Another issue surfaced.

I wanted to deploy the API on Vercel because:

  • It’s free
  • Easy to deploy
  • Perfect for small APIs
  • The project only generates around 30–40 images per day

It seemed like the perfect fit.

Except…

Vercel doesn’t include a full Chrome installation required by Puppeteer.

The API failed immediately.

Back to square one.

The Game Changer

After some research, I discovered one of the most useful packages I’ve used recently:

  • @sparticuz/chromium
  • puppeteer-core

This combination provides a lightweight Chromium build specifically designed for serverless environments such as Vercel.

Instead of relying on a locally installed browser, Puppeteer launches the bundled Chromium provided by @sparticuz/chromium.

One small dependency completely solved the deployment problem.

Sometimes the best solutions come from the open-source community.

The Final Architecture

The workflow became surprisingly clean.

News Published


      n8n


Express Screenshot API


HTML + CSS Template


Headless Chromium


PNG Response


Facebook Auto Post

No VPS.

No image storage.

No scheduled cleanup jobs.

No unnecessary infrastructure.

Just a lightweight serverless API that creates images on demand.

Why I Like This Approach

Looking back, I actually prefer this architecture over my original idea.

Using HTML and CSS instead of manually drawing images makes the design process dramatically easier.

Need to change the font?

Edit the CSS.

Need a new layout?

Modify the HTML.

Need animations while testing?

They work naturally.

Everything feels like building a normal webpage rather than generating graphics programmatically.

Even better, the API stays completely stateless.

Each request creates an image, returns it, and immediately forgets about it.

Nothing remains on disk.

Lessons Learned

This project reminded me that technical constraints often lead to better engineering decisions.

If the client had paid for a VPS from day one, I probably would have built a traditional image generation service.

Instead, the budget forced me to think differently.

The result was a simpler, cheaper, and more scalable solution.

Sometimes the best architecture isn’t the one with the most services.

It’s the one that removes unnecessary services entirely.

Final Thoughts

One of the most enjoyable parts of software engineering is solving problems with creativity rather than throwing infrastructure at them.

This project started as “automate Facebook posts.”

It ended with a serverless image generation pipeline powered by n8n, Express, HTML, CSS, Puppeteer, and @sparticuz/chromium.

A small project.

A tiny budget.

But a solution I’m genuinely proud of.