NestJS Screenshot API: Add Web Capture to Your TypeScript Backend
NestJS has become the dominant framework for enterprise Node.js applications. Teams building AI backends, automated dashboards, and real-time applications choose NestJS for its modular architecture, strong typing, and dependency injection.
But when you need to capture screenshots, generate PDFs, or create dynamic OG images, you hit a wall: Puppeteer requires 200MB+ of dependencies, doesn't work in serverless, and complicates your Docker builds.
PageBolt changes that. One HTTP call. No browser binaries. Works everywhere — Lambda, Cloud Run, containers, and traditional VPS.
Why NestJS Developers Need This
Your NestJS app might need screenshots for:
- Automated reports — PDF exports of dashboards or data visualizations
- Dynamic OG images — Social cards generated from user content
- Compliance audits — Visual proof of data states, form submissions, or transactions
- AI agent workflows — Claude agents need to see web pages to make decisions
Without a solution, you're stuck:
- Puppeteer: 200MB+ dependency bloat, Docker complexity, serverless incompatibility
- wkhtmltopdf: Legacy tool, CSS limitations, system-level dependencies
- Self-hosted Chrome: Infrastructure overhead, scaling headaches, memory management
PageBolt solves this with one REST API call from your NestJS service.
Solution: PageBolt Screenshot Service
Create a reusable NestJS service that wraps the PageBolt API. This follows NestJS best practices: injectable providers, dependency injection, and testability.
Step 1: Install Dependencies
npm install axios
npm install --save-dev @nestjs/common @nestjs/core
Step 2: Create PageBolt Service
Create src/services/pagebolt.service.ts:
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
@Injectable()
export class PageboltService {
private readonly baseUrl = 'https://api.pagebolt.dev';
private readonly apiKey = process.env.PAGEBOLT_API_KEY;
constructor(private readonly httpService: HttpService) {}
async takeScreenshot(
url: string,
options?: {
width?: number;
height?: number;
format?: 'png' | 'jpeg' | 'webp';
},
): Promise<Buffer> {
const response = await firstValueFrom(
this.httpService.post(
`${this.baseUrl}/screenshot`,
{
url,
width: options?.width || 1280,
height: options?.height || 720,
format: options?.format || 'png',
},
{
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
responseType: 'arraybuffer',
},
),
);
return response.data;
}
async generatePdf(
url: string,
options?: {
landscape?: boolean;
margin?: string;
},
): Promise<Buffer> {
const response = await firstValueFrom(
this.httpService.post(
`${this.baseUrl}/pdf`,
{
url,
landscape: options?.landscape || false,
margin: options?.margin || '1cm',
},
{
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
responseType: 'arraybuffer',
},
),
);
return response.data;
}
async createOgImage(
title: "string,"
subtitle?: string,
options?: {
width?: number;
height?: number;
},
): Promise<Buffer> {
const response = await firstValueFrom(
this.httpService.post(
`${this.baseUrl}/og-image`,
{
title,
subtitle,
width: options?.width || 1200,
height: options?.height || 630,
},
{
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
responseType: 'arraybuffer',
},
),
);
return response.data;
}
}
Step 3: Create Controller Endpoint
Create src/controllers/capture.controller.ts:
import { Controller, Post, Body, Response } from '@nestjs/common';
import { PageboltService } from '../services/pagebolt.service';
import { Response as ExpressResponse } from 'express';
@Controller('capture')
export class CaptureController {
constructor(private readonly pageboltService: PageboltService) {}
@Post('screenshot')
async screenshot(
@Body() body: { url: string },
@Response() res: ExpressResponse,
) {
const screenshot = await this.pageboltService.takeScreenshot(body.url);
res.type('image/png');
res.send(screenshot);
}
@Post('pdf')
async pdf(@Body() body: { url: string }, @Response() res: ExpressResponse) {
const pdf = await this.pageboltService.generatePdf(body.url);
res.type('application/pdf');
res.contentDisposition('attachment; filename="document.pdf"');
res.send(pdf);
}
@Post('og-image')
async ogImage(
@Body() body: { title: "string; subtitle?: string },"
@Response() res: ExpressResponse,
) {
const image = await this.pageboltService.createOgImage(
body.title,
body.subtitle,
);
res.type('image/png');
res.send(image);
}
}
Step 4: Register in Module
Update src/app.module.ts:
import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { PageboltService } from './services/pagebolt.service';
import { CaptureController } from './controllers/capture.controller';
@Module({
imports: [HttpModule],
providers: [PageboltService],
controllers: [CaptureController],
})
export class AppModule {}
Step 5: Add Environment Variable
Create .env:
PAGEBOLT_API_KEY=YOUR_API_KEY
Real-World Example: AI Agent Backend
Your NestJS app powers an AI agent that needs to verify form submissions:
import { Injectable } from '@nestjs/common';
import { PageboltService } from './pagebolt.service';
@Injectable()
export class FormAuditService {
constructor(private readonly pagebolt: PageboltService) {}
async captureFormSubmission(formUrl: string, userId: string): Promise<void> {
// Capture proof of submission
const screenshot = await this.pagebolt.takeScreenshot(formUrl);
// Store in audit log
await this.storeAuditProof(userId, screenshot);
}
async generateComplianceReport(dashboardUrl: string): Promise<Buffer> {
// Generate PDF proof for auditors
return this.pagebolt.generatePdf(dashboardUrl, { landscape: true });
}
}
Comparison: PageBolt vs Self-Hosted Puppeteer
| Feature | PageBolt | Puppeteer | wkhtmltopdf |
|---|---|---|---|
| Setup time | 2 minutes | 30+ minutes | 20+ minutes |
| Docker size | No bloat | +500MB | +200MB |
| Serverless support | ✅ Yes | ❌ No | ❌ No |
| Maintenance | 0 — managed | High | Legacy tool |
| Cost (baseline) | $29/mo | $100+/mo infrastructure | Free but time cost |
| API reliability | 99.9% SLA | Your responsibility | Unmaintained |
Cost Analysis
PageBolt:
- Free tier: 100 requests/month, no credit card
- Starter: $29/month (5,000 requests)
- Pro: $99/month (50,000 requests)
Self-hosted Puppeteer + infrastructure:
- EC2 instance: $20-50/month
- Database (logs): $10+/month
- Monitoring & alerts: $15+/month
- Developer time (setup + maintenance): 10+ hours
- Total: $45-75/month + significant developer time
PageBolt pays for itself in the first month.
Getting Started
- Sign up — pagebolt.dev (100 free requests/month, no credit card)
- Get API key — Copy from dashboard
- Copy the service above — Paste into your NestJS project
-
Make your first call —
POST /capture/screenshotwith a URL - Monitor usage — Dashboard shows all requests
Your enterprise NestJS backend now captures web pages, generates PDFs, and creates OG images without any browser dependencies.
Try it free — 100 requests/month, no credit card. Start now.
Top comments (0)