Skip to content

Instantly share code, notes, and snippets.

@Lasalot
Last active February 2, 2026 10:17
Show Gist options
  • Select an option

  • Save Lasalot/1df0787456002cd89f821f987ea94cd5 to your computer and use it in GitHub Desktop.

Select an option

Save Lasalot/1df0787456002cd89f821f987ea94cd5 to your computer and use it in GitHub Desktop.
Proxy.js | Next.js 16+ integration for Prerender.io
import { NextResponse, type NextRequest } from "next/server";
export async function proxy(request: NextRequest) {
const userAgent = request.headers.get("user-agent");
const bots = [
"googlebot",
"yahoo! slurp",
"bingbot",
"yandex",
"baiduspider",
"facebookexternalhit",
"twitterbot",
"rogerbot",
"linkedinbot",
"embedly",
"quora link preview",
"showyoubot",
"outbrain",
"pinterest/0.",
"developers.google.com/+/web/snippet",
"slackbot",
"vkshare",
"w3c_validator",
"redditbot",
"applebot",
"whatsapp",
"flipboard",
"tumblr",
"bitlybot",
"skypeuripreview",
"nuzzel",
"discordbot",
"google page speed",
"qwantify",
"pinterestbot",
"bitrix link preview",
"xing-contenttabreceiver",
"chrome-lighthouse",
"telegrambot",
"oai-searchbot",
"chatgpt",
"gptbot",
"perplexity",
"claudeBot",
"amazonbot",
"integration-test", // Integration testing
];
const IGNORE_EXTENSIONS = [
".js", ".css", ".xml", ".less", ".png", ".jpg", ".jpeg", ".gif", ".pdf",
".doc", ".txt", ".ico", ".rss", ".zip", ".mp3", ".rar", ".exe", ".wmv",
".avi", ".ppt", ".mpg", ".mpeg", ".tif", ".wav", ".mov", ".psd", ".ai",
".xls", ".mp4", ".m4a", ".swf", ".dat", ".dmg", ".iso", ".flv", ".m4v",
".torrent", ".woff", ".ttf", ".svg", ".webmanifest",
];
const isBot =
!!userAgent && bots.some((bot) => userAgent.toLowerCase().includes(bot.toLowerCase()));
const isPrerender = request.headers.get("X-Prerender");
const pathname = new URL(request.url).pathname;
const extension = pathname.slice(((pathname.lastIndexOf(".") - 1) >>> 0) + 1);
const hasExtension = extension.length > 0;
const dottedExt = hasExtension ? `.${extension}` : "";
if (isPrerender || !isBot || (hasExtension && IGNORE_EXTENSIONS.includes(dottedExt))) {
return NextResponse.next();
}
// Bot path: proxy to prerender service
const newURL = `http://service.prerender.io/${request.url}`;
const newHeaders = new Headers(request.headers);
newHeaders.set("X-Prerender-Token", process.env.PRERENDER_TOKEN ?? "");
newHeaders.set("X-Prerender-Int-Type", "NextJS");
try {
const res = await fetch(
new Request(newURL, {
headers: newHeaders,
redirect: "manual",
})
);
const responseHeaders = new Headers(res.headers);
responseHeaders.set("X-Redirected-From", request.url);
responseHeaders.delete("content-encoding");
responseHeaders.delete("content-length");
responseHeaders.delete("transfer-encoding"); // harmless if absent
// Stream the body through
const { readable, writable } = new TransformStream();
if (res.body) {
res.body.pipeTo(writable);
}
return new NextResponse(readable, {
status: res.status,
statusText: res.statusText,
headers: responseHeaders,
});
} catch (error) {
return NextResponse.next();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment