For Developers

Production-ready integration guides for teams that need crawler-safe HTML delivery on JavaScript-heavy websites.

Quick start

The fastest model is to place SeoRender in front of your app for crawler traffic only. Human traffic continues to your origin.

  1. Create your account and API token in panel.seorender.io.
  2. Set up crawler detection in middleware, Nginx, or edge proxy.
  3. Forward crawler requests to the /edge endpoint with full URL context.
  4. Enable recache triggers after content publishing events.

Supported platforms

SeoRender works with React, Vue, Angular, Svelte, and custom JavaScript stacks because rendering is handled at the edge layer.

Edge proxy (Node.js)

Configure environment variables and run the edge proxy in front of your origin.

typescriptmiddleware.ts

Next.js middleware example

1// middleware.ts (Next.js App Router)
2import { NextRequest, NextResponse } from "next/server";
3
4const BOT_PATTERN = /(googlebot|bingbot|duckduckbot|chatgpt-user|perplexitybot)/i;
5
6export async function middleware(request: NextRequest) {
7 const userAgent = request.headers.get("user-agent") ?? "";
8 if (!BOT_PATTERN.test(userAgent)) return NextResponse.next();
9
10 const edgeUrl = `https://bot.seorender.io/edge/${encodeURIComponent(request.nextUrl.toString())}`;
11
12 const prerender = await fetch(edgeUrl, {
13 headers: {
14 "X-SeoRender-Token": process.env.SEORENDER_TOKEN ?? "YOUR_TOKEN",
15 "X-Forwarded-Host": request.headers.get("host") ?? "",
16 },
17 });
18
19 if (!prerender.ok) return NextResponse.next();
20 const html = await prerender.text();
21 return new NextResponse(html, {
22 status: 200,
23 headers: { "content-type": "text/html; charset=utf-8" },
24 });
25}
26
27export const config = {
28 matcher: ["/((?!api|_next|.*\\..*).*)"],
29};
typescript.env.local + proxy

Node.js middleware example

1// .env.local
2ORIGIN_BASE_URL=https://your-app.com
3API_BASE_URL=https://bot.seorender.io
4SEORENDER_TOKEN=your-token
5EDGE_PROXY_PORT=8080
6
7// Start proxy
8npm run dev:proxy
javascriptworker.js

Cloudflare Worker example

1export default {
2 async fetch(request, env) {
3 const ua = request.headers.get("user-agent") || "";
4 const isBot = /(googlebot|bingbot|duckduckbot|yandex|chatgpt-user)/i.test(ua);
5
6 if (!isBot) {
7 return fetch(request);
8 }
9
10 const target = `https://bot.seorender.io/edge/${encodeURIComponent(request.url)}`;
11
12 return fetch(target, {
13 headers: {
14 "x-seorender-token": env.SEORENDER_TOKEN,
15 "x-forwarded-host": new URL(request.url).host
16 }
17 });
18 }
19};

Nginx configuration

Add crawler conditions and forward bot requests while keeping human traffic on your application path.

nginxnginx.conf

Nginx bot-routing example

1map $http_user_agent $is_crawler {
2 default 0;
3 ~*googlebot 1;
4 ~*bingbot 1;
5 ~*duckduckbot 1;
6 ~*chatgpt-user 1;
7 ~*perplexitybot 1;
8}
9
10location / {
11 if ($is_crawler = 1) {
12 proxy_pass https://bot.seorender.io/edge/$scheme://$host$uri;
13 proxy_set_header X-SeoRender-Token YOUR_TOKEN;
14 proxy_set_header X-Forwarded-Host $host;
15 break;
16 }
17 proxy_pass http://app_upstream;
18}

API reference

Use recache and render endpoints to keep indexed content fresh after every publish event.

shellapi-check.sh

REST endpoint quick check (cURL)

1# POST /recache
2curl -X POST "https://bot.seorender.io/recache" \
3 -H "Content-Type: application/json" \
4 -H "X-SeoRender-Token: YOUR_TOKEN" \
5 -d '{"url":"https://example.com/page"}'
6
7# GET /render
8curl "https://bot.seorender.io/render?url=https://example.com" \
9 -H "X-SeoRender-Token: YOUR_TOKEN"
10
11# GET /edge
12curl "https://bot.seorender.io/edge/https%3A%2F%2Fexample.com" \
13 -H "X-SeoRender-Token: YOUR_TOKEN" \
14 -H "User-Agent: googlebot"

Client examples

Use your preferred language to trigger recache and verify rendered output.

javascriptrecache.js

Node.js (fetch)

1const endpoint = "https://bot.seorender.io/recache";
2const token = process.env.SEORENDER_TOKEN;
3const url = "https://example.com/pricing";
4
5const response = await fetch(endpoint, {
6 method: "POST",
7 headers: {
8 "content-type": "application/json",
9 "x-seorender-token": token ?? ""
10 },
11 body: JSON.stringify({ url })
12});
13
14if (!response.ok) {
15 throw new Error("Recache failed: " + response.status);
16}
pythonrecache.py

Python (requests)

1import requests
2
3endpoint = "https://bot.seorender.io/recache"
4token = "YOUR_TOKEN"
5payload = {"url": "https://example.com/pricing"}
6
7response = requests.post(
8 endpoint,
9 headers={"X-SeoRender-Token": token},
10 json=payload,
11 timeout=10,
12)
13response.raise_for_status()
gorecache.go

Go (net/http)

1package main
2
3import (
4 "bytes"
5 "net/http"
6)
7
8func main() {
9 body := []byte(`{"url":"https://example.com/pricing"}`)
10 req, _ := http.NewRequest("POST", "https://bot.seorender.io/recache", bytes.NewBuffer(body))
11 req.Header.Set("Content-Type", "application/json")
12 req.Header.Set("X-SeoRender-Token", "YOUR_TOKEN")
13
14 client := &http.Client{}
15 resp, err := client.Do(req)
16 if err != nil { panic(err) }
17 defer resp.Body.Close()
18}
phprecache.php

PHP (cURL)

1<?php
2$ch = curl_init("https://bot.seorender.io/recache");
3
4curl_setopt_array($ch, [
5 CURLOPT_POST => true,
6 CURLOPT_HTTPHEADER => [
7 "Content-Type: application/json",
8 "X-SeoRender-Token: YOUR_TOKEN"
9 ],
10 CURLOPT_POSTFIELDS => json_encode(["url" => "https://example.com/pricing"]),
11 CURLOPT_RETURNTRANSFER => true
12]);
13
14$result = curl_exec($ch);
15curl_close($ch);

Implementation checklist

  • Canonical tags and hreflang configuration are consistent on rendered pages.
  • Robots directives allow indexing on critical pages.
  • Critical templates are covered by recache hooks after content updates.
  • Search Console and analytics are monitored after go-live.

Troubleshooting

  • If bots receive empty HTML, verify user-agent detection and proxy conditions.
  • If old content appears in SERP snippets, trigger recache for affected URLs.
  • If only one locale indexes, validate locale-specific canonicals and alternates.

Need implementation help? Contact our team.

Contact support