Blog 7 min read

The Real Cost of Self-Hosting Website Screenshots: It's Not Free

I tracked every hour and dollar I spent running Puppeteer in production for six months. Self-hosting screenshots cost me $400/month. Here's the full breakdown.

SnapRender Team
|

The Real Cost of Self-Hosting Website Screenshots

Nobody ever budgets for the screenshots.

You need website thumbnails for your directory, or link previews for your app, or scheduled captures for compliance. You are a developer. Puppeteer exists. The math seems obvious: spin up headless Chrome, write a script, run it on a cheap VPS. Free screenshots forever.

I thought the same thing. Then I tracked what it actually cost me over six months, and the number was not what I expected.

The server costs alone are not trivial

Chromium uses 200-300MB of RAM just to launch. Before you render a single page. Each open tab adds another 50-150MB depending on the site. A page with heavy JavaScript, multiple iframes, or large images can push a single tab past 300MB on its own.

A $4/month DigitalOcean droplet with 512MB of RAM is not going to work. A $6/month droplet with 1GB will get OOM-killed the moment you try to render more than one page at a time. I learned this the hard way when my 1GB instance lasted exactly 11 hours before the kernel killed Chrome.

In practice you need at minimum 2GB, and more realistically 4GB if you want to run even 3-5 concurrent screenshots without constant memory pressure. On DigitalOcean, the 4GB basic droplet is $24/month. On AWS, a comparable t3.medium is around $30/month. Hetzner is cheaper at roughly €7/month for 4GB, but you are still paying for a server whose only job is running a browser.

So right away, "free screenshots" cost $24-48/month in hosting. Not a dealbreaker, but already not free.

The costs nobody thinks about

This is where the real money is.

Setup time. Getting Puppeteer running in dev takes maybe 2 hours. Getting it running in production with proper error handling, timeouts, process cleanup, a job queue, and restart logic takes 8-16 hours. I know because I timed myself. My first "production-ready" setup took 14 hours across three days, and it still had bugs I found the following week.

Chrome updates. Puppeteer pins to a specific Chromium version. Every few months a new version ships, and sometimes things break. Puppeteer issue #5893 (Chrome memory leak) has 55+ upvotes and has been open since 2020. Issue #7507 (screenshot hangs forever) was reported in 2021. These are not theoretical problems, they are things you will hit if you run this in production long enough.

The slow memory leak. This one is documented extensively. Even with proper page.close() calls, Chromium's memory usage ticks up by roughly 0.5MB per second under sustained load. Over an hour, that is 1.8GB of accumulated garbage that the garbage collector may or may not clean up. On a 4GB server, you are looking at a restart every few hours unless you build rotation logic.

Ongoing maintenance. I tracked my hours for six months. The average was 3.2 hours per month. Some months were 45 minutes (just updating dependencies and checking logs). Two months were over 8 hours each, because I was chasing down why specific sites were returning blank screenshots and why my process cleanup cron was not catching all the zombie Chrome instances.

The actual math

I know developers hate hand-wavy cost arguments, so here are real numbers. Plug in your own hourly rate where mine does not fit.

Server: $24/month for a 4GB DigitalOcean droplet. This handles maybe 3-5 concurrent screenshots before performance degrades. If you need more concurrency, you need a bigger box or multiple servers, and the cost scales fast.

Initial setup: 14 hours of my time to get a production-ready setup. At $100/hour (a conservative blended rate for a mid-level dev including salary, benefits, and overhead), that is $1,400 as a one-time cost. Amortized over 24 months, that adds $58/month.

Maintenance: 3.2 hours/month average. At $100/hour, that is $320/month. This is the number that shocks people. It does not feel like 3 hours because it is spread across checking logs, restarting things, investigating edge cases, and updating dependencies. But when I actually logged it, the hours were there.

Monthly cost at $100/hour (mid-level developer)

Category Cost
Server (4GB droplet) $24/mo
Amortized setup (14h ÷ 24mo) $58/mo
Maintenance (3.2h avg) $320/mo
Total $402/mo

Monthly cost at $50/hour (junior dev or discounted founder time)

Category Cost
Server (4GB droplet) $24/mo
Amortized setup $29/mo
Maintenance (3.2h avg) $160/mo
Total $213/mo

If you genuinely value your time at $0, self-hosting costs $24/month and beats any API. But most developers I know don't have unlimited free hours, and the 3.2 hours per month is a real number, not a guess.

And that is for a setup that handles maybe 5,000-10,000 screenshots per month before you need to start building real infrastructure.

What the alternative looks like

A managed screenshot API costs $9-79/month depending on volume. At SnapRender, the Starter plan is $9/month for 2,000 screenshots. Growth is $29/month for 10,000. Most competitors (ScreenshotOne, CaptureKit, Urlbox) are in the $17-49/month range for similar volumes.

Approach 2,000 screenshots/mo 10,000 screenshots/mo Maintenance hours
Self-hosted Puppeteer $213-402/mo $213-402/mo + scaling costs 3.2h/mo average
Screenshot API $9-19/mo $29-49/mo 0h/mo

At 10,000 screenshots/month, you are comparing $29-49/month for an API versus $213-402/month for self-hosting. The API is 5-20x cheaper, and you spend zero hours per month on maintenance.

That is not a pitch. It is just arithmetic.

The scaling trap

There is a trap I fell into, and I see other developers fall into it constantly. You build the Puppeteer setup for your MVP. It works fine for 500 screenshots a month. Your product grows. Now you need 5,000. Then 20,000.

Here is the thing about scaling a self-hosted screenshot setup: it is not linear at all. You cannot just add more RAM. At 20+ concurrent screenshots you need:

  • A browser pool managing multiple Chrome instances
  • A job queue (Bull, BullMQ) so requests do not pile up and crash everything
  • Probably horizontal scaling across multiple servers
  • Shared storage so screenshots are accessible from any node
  • Health check logic to detect and replace crashed browsers

I know this because I built all of it. It took about six weeks. Each piece is a small project on its own, but together they are a significant engineering effort. And the whole time you are building this, you are not building the features your users actually care about. You are building screenshot infrastructure.

I talked to a founder last month who spent five weeks on screenshot infra for a product where screenshots were literally one feature on one page of their app. Five weeks of a solo founder's time on a sub-feature.

When self-hosting actually makes sense

I do not think self-hosting is always wrong. It makes sense in specific situations:

Scenario Why self-hosting wins
Internal URLs Pages behind a VPN or on localhost. An external API cannot reach them
Compliance Healthcare, finance, government. Your legal team says no third-party services
Very high volume 100K+ screenshots/month, where API pricing starts to add up (though infrastructure costs get significant too)
Screenshots are the product Your entire business IS a screenshot service. You need the control and the margins

For everyone else, and that is most developers building SaaS products where screenshots are a feature and not the core, the self-hosting tax is usually not worth paying.

Quick decision framework

Estimate how many hours per month you spend (or would spend) maintaining your screenshot setup. Multiply by your effective hourly rate. If the number is higher than what an API would cost at your volume, use an API.

For most developers I have talked to, the breakeven lands at around 1-2 hours per month of maintenance. Anything above that, and you are paying more for the privilege of running it yourself than you would pay someone else to handle it.

If you want to test whether an API works for your use case, SnapRender has a free tier with 500 screenshots/month, no credit card required. Enough to validate before committing to anything.

Try SnapRender Free

500 free screenshots/month, no credit card required.

Sign up free