Last active
February 16, 2025 11:15
-
-
Save DavydeVries/90a1123824e906771466886f4fd6314c to your computer and use it in GitHub Desktop.
Serverless screenshot API with Puppeteer and Chromium
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // /src/app/api/screenshot/route.ts | |
| import puppeteer from 'puppeteer-core' | |
| import chromium from '@sparticuz/chromium-min' | |
| import { NextRequest } from 'next/server' | |
| export const isPreviewOrProduction = | |
| process.env.VERCEL_ENV === 'preview' || | |
| process.env.VERCEL_ENV === 'production' | |
| async function getBrowser() { | |
| return puppeteer.launch({ | |
| args: [ | |
| ...chromium.args, | |
| '--hide-scrollbars', | |
| '--disable-web-security', | |
| '--no-sandbox', | |
| '--disable-setuid-sandbox', | |
| ], | |
| defaultViewport: chromium.defaultViewport, | |
| executablePath: isPreviewOrProduction | |
| ? await chromium.executablePath( | |
| 'https://github.com/Sparticuz/chromium/releases/download/v130.0.0/chromium-v130.0.0-pack.tar', | |
| ) | |
| : | |
| // To install local Chromium for screenshots run: | |
| // `npx @puppeteer/browsers install chromium@latest --path /tmp/localChromium` | |
| // After that, move the Chromium binary to a persistent location, e.g., `/usr/local/chromium`, | |
| // and update the path accordingly in the script. | |
| '/usr/local/chromium/mac_arm-1390993/chrome-mac/Chromium.app/Contents/MacOS/Chromium', | |
| headless: isPreviewOrProduction | |
| ? chromium.headless === 'new' | |
| ? true | |
| : (chromium.headless as boolean | 'shell') | |
| : false, | |
| }) | |
| } | |
| export async function GET(req: NextRequest) { | |
| const { searchParams } = new URL(req.url) | |
| let url = searchParams.get('url') | |
| if (!url) { | |
| return new Response(JSON.stringify({ error: 'Missing `url` parameter' }), { status: 400 }) | |
| } | |
| if (!url.startsWith('http://') && !url.startsWith('https://')) { | |
| url = `https://${url}` | |
| } | |
| console.info( | |
| 'Try to screenshot with: ' + | |
| (isPreviewOrProduction | |
| ? 'https://github.com/Sparticuz/chromium/releases/download/v130.0.0/chromium-v130.0.0-pack.tar' | |
| : '/usr/local/chromium/mac_arm-1390852/chrome-mac/Chromium.app/Contents/MacOS/Chromium'), | |
| ) | |
| let browser | |
| try { | |
| browser = await getBrowser() | |
| const page = await browser.newPage() | |
| await page.setUserAgent( | |
| 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36', | |
| ) | |
| await page.setExtraHTTPHeaders({ | |
| AcceptLanguage: 'en-US,en;q=0.9', | |
| Referer: url, | |
| locale: 'en-US', | |
| }) | |
| await page.goto(url, { | |
| waitUntil: ['load', 'domcontentloaded', 'networkidle2'], | |
| }) | |
| const screenshot = await page.screenshot({ fullPage: true }) | |
| await browser.close() | |
| return new Response(screenshot, { | |
| status: 200, | |
| headers: { | |
| 'Content-Type': 'image/png', | |
| }, | |
| }) | |
| } catch (error) { | |
| console.error('Error capturing screenshot:', error) | |
| if (browser) await browser.close() | |
| return new Response(JSON.stringify({ error: 'Failed to capture screenshot' }), { status: 500 }) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment