Documentation

    Get Started With UpRender

    Everything you need to ship crawler-ready HTML in minutes — set up, plug in your stack, and start serving bots a fully-rendered page.

    1. Quick Start

    Five minutes from sign-up to serving crawler-ready HTML.

    1

    Create an account & add your domain

    Sign up at uprender.io, then add your website in the Domain Manager.

    2

    Copy your two access keys

    Open Domain Manager → Access Credentials to get a User Key and a Domain Key. Both are required on every request.

    3

    Install one integration

    Pick the integration that matches your stack — Cloudflare Workers, Next.js, Vercel, Express, Nginx, or Nuxt — and drop in the snippet from §3.

    4

    Verify with a test request

    Hit the cache endpoint with a bot user-agent and confirm you get back rendered HTML.

    Test it with cURL

    terminalbash
    curl -i \ -H "User-Agent: Googlebot" \ -H "X-UpRender-User-Key: YOUR_USER_KEY" \ -H "X-UpRender-Domain-Key: YOUR_DOMAIN_KEY" \ "https://api.uprender.io/api/v1/cache/get?url=https://your-website.com/"

    A successful response looks like:

    response.jsonjson
    { "success": true, "html": "<!doctype html>...fully rendered HTML...", "device_type": "desktop", "cached_at": "2026-05-21T08:14:22Z"
    }
    Tip:Don't have any cached HTML yet? Run your first crawl from Domain Manager → Render now, or call the cache endpoint with a fresh URL — UpRender will render it on demand.

    2. How It Works

    UpRender sits between your origin and bot traffic. Real users hit your site as usual. Bots — Googlebot, Bingbot, GPTBot, ClaudeBot, and friends — get a fully-rendered HTML snapshot from us instead of your raw JS bundle.

    1. Bot arrives

    Your edge layer (Cloudflare Worker, Next.js middleware, Nginx, etc.) checks the User-Agent.

    2. Route the bot

    If it's a bot, the request is forwarded to UpRender with your two access keys.

    3. Serve the cache

    UpRender returns the latest rendered HTML — or renders it on the fly if there's no cache yet.

    4. Humans pass through

    Anything that isn't a bot gets your original site, untouched.

    Desktop and mobile variants

    Plans with mobile rendering enabled render every page twice — once on a 1920×1080 desktop viewport and once on a 412×915 mobile viewport. UpRender automatically returns the matching variant based on the bot's User-Agent.

    3. Integration Guides

    Pick the guide that matches your stack. Every snippet is self-contained, under 50 lines, and ready to paste in.

    3.1 Cloudflare Workers (recommended)

    The fastest way to get started — runs at Cloudflare's edge, no server changes required.

    worker.jsjavascript
    const UPRENDER_API = 'https://api.uprender.io/api/v1/cache/get';
    const BOT_REGEX = /(googlebot|google-inspectiontool|google-extended|googleother|bingbot|bingpreview|gptbot|chatgpt-user|oai-searchbot|claudebot|claude-user|claude-searchbot|applebot|meta-externalagent|meta-externalfetcher|facebookexternalhit|slackbot|twitterbot|linkedinbot|facebot)/i; export default { async fetch(request, env) { const ua = request.headers.get('User-Agent') || ''; // Real user → straight to origin if (!BOT_REGEX.test(ua)) return fetch(request); // Bot → fetch the rendered HTML from UpRender const upstream = await fetch(`${UPRENDER_API}?url=${encodeURIComponent(request.url)}`, { headers: { 'X-UpRender-User-Key': env.UPRENDER_USER_KEY, 'X-UpRender-Domain-Key': env.UPRENDER_DOMAIN_KEY, 'User-Agent': ua, }, }); if (!upstream.ok) return fetch(request); // fall back to origin on error const { html } = await upstream.json(); return new Response(html, { headers: { 'Content-Type': 'text/html; charset=utf-8' }, }); },
    };

    Add your keys as encrypted secrets:

    terminalbash
    wrangler secret put UPRENDER_USER_KEY
    wrangler secret put UPRENDER_DOMAIN_KEY

    Finally, attach the Worker to your domain via a Cloudflare Worker Route (e.g. *yourdomain.com/*).

    3.2 Next.js (App or Pages Router)

    middleware.tstypescript
    import { NextRequest, NextResponse } from 'next/server'; const BOT_REGEX = /(googlebot|google-inspectiontool|google-extended|googleother|bingbot|bingpreview|gptbot|chatgpt-user|oai-searchbot|claudebot|claude-user|claude-searchbot|applebot|meta-externalagent|meta-externalfetcher|facebookexternalhit|slackbot|twitterbot|linkedinbot)/i; export async function middleware(req: NextRequest) { const ua = req.headers.get('user-agent') || ''; if (!BOT_REGEX.test(ua)) return NextResponse.next(); const resp = await fetch( `https://api.uprender.io/api/v1/cache/get?url=${encodeURIComponent(req.nextUrl.href)}`, { headers: { 'X-UpRender-User-Key': process.env.UPRENDER_USER_KEY!, 'X-UpRender-Domain-Key': process.env.UPRENDER_DOMAIN_KEY!, 'User-Agent': ua, }, } ); if (!resp.ok) return NextResponse.next(); const { html } = await resp.json(); return new NextResponse(html, { headers: { 'Content-Type': 'text/html; charset=utf-8' }, });
    } export const config = { matcher: '/((?!_next|api|favicon.ico).*)' };
    .env.localbash
    UPRENDER_USER_KEY=your_user_key
    UPRENDER_DOMAIN_KEY=your_domain_key
    Note:On Vercel, add the same variables under Project → Settings → Environment Variables.

    3.3 Vercel Edge Functions

    Use this for non-Next.js SPAs deployed on Vercel.

    api/bot-render.tstypescript
    export const config = { runtime: 'edge' }; const BOT_REGEX = /(googlebot|google-inspectiontool|google-extended|googleother|bingbot|bingpreview|gptbot|chatgpt-user|oai-searchbot|claudebot|claude-user|claude-searchbot|applebot|meta-externalagent|meta-externalfetcher)/i; export default async function handler(req: Request) { const ua = req.headers.get('user-agent') || ''; if (!BOT_REGEX.test(ua)) return fetch(req); const resp = await fetch( `https://api.uprender.io/api/v1/cache/get?url=${encodeURIComponent(req.url)}`, { headers: { 'X-UpRender-User-Key': process.env.UPRENDER_USER_KEY!, 'X-UpRender-Domain-Key': process.env.UPRENDER_DOMAIN_KEY!, }, } ); const { html } = await resp.json(); return new Response(html, { headers: { 'Content-Type': 'text/html' } });
    }
    vercel.jsonjson
    { "rewrites": [{ "source": "/(.*)", "destination": "/api/bot-render" }]
    }

    3.4 Express (Node.js)

    uprender-middleware.jsjavascript
    const BOT_REGEX = /(googlebot|google-inspectiontool|google-extended|googleother|bingbot|bingpreview|gptbot|chatgpt-user|oai-searchbot|claudebot|claude-user|claude-searchbot|applebot|meta-externalagent|meta-externalfetcher)/i; module.exports = function uprenderMiddleware() { return async (req, res, next) => { if (!BOT_REGEX.test(req.headers['user-agent'] || '')) return next(); try { const url = `${req.protocol}://${req.get('host')}${req.originalUrl}`; const resp = await fetch( `https://api.uprender.io/api/v1/cache/get?url=${encodeURIComponent(url)}`, { headers: { 'X-UpRender-User-Key': process.env.UPRENDER_USER_KEY, 'X-UpRender-Domain-Key': process.env.UPRENDER_DOMAIN_KEY, 'User-Agent': req.headers['user-agent'], }, } ); if (!resp.ok) return next(); const { html } = await resp.json(); res.set('Content-Type', 'text/html; charset=utf-8').send(html); } catch { next(); } };
    };
    server.jsjavascript
    const express = require('express');
    const uprender = require('./uprender-middleware'); const app = express();
    app.use(uprender());
    // ... your routes
    app.listen(3000);

    3.5 Nginx reverse proxy

    nginx.confnginx
    map $http_user_agent $is_bot { default 0; "~*(googlebot|google-inspectiontool|google-extended|googleother|bingbot|bingpreview|gptbot|chatgpt-user|oai-searchbot|claudebot|claude-user|claude-searchbot|applebot|meta-externalagent|meta-externalfetcher)" 1;
    } server { listen 80; server_name yourdomain.com; location / { if ($is_bot) { proxy_pass https://api.uprender.io/api/v1/cache/get?url=$scheme://$host$request_uri; } proxy_set_header X-UpRender-User-Key "$UPRENDER_USER_KEY"; proxy_set_header X-UpRender-Domain-Key "$UPRENDER_DOMAIN_KEY"; proxy_pass http://localhost:3000; # origin fallback }
    }
    Warning:Never hard-code keys in your nginx config. Load them from environment via set directives or a sidecar template.

    3.6 Vue / Nuxt 3

    server/middleware/uprender.tstypescript
    export default defineEventHandler(async (event) => { const ua = getHeader(event, 'user-agent') || ''; if (!/(googlebot|bingbot|gptbot|claudebot)/i.test(ua)) return; const url = getRequestURL(event).href; const resp = await $fetch<{ html: string }>( `https://api.uprender.io/api/v1/cache/get?url=${encodeURIComponent(url)}`, { headers: { 'X-UpRender-User-Key': process.env.UPRENDER_USER_KEY!, 'X-UpRender-Domain-Key': process.env.UPRENDER_DOMAIN_KEY!, }, } ); setHeader(event, 'Content-Type', 'text/html; charset=utf-8'); return resp.html;
    });

    4. Cache API

    These are the endpoints your edge integration calls. All requests need the two access-key headers.

    Authentication

    every requesthttp
    X-UpRender-User-Key: <your user access key>
    X-UpRender-Domain-Key: <your domain access key>

    Find both keys in Domain Manager → Access Credentials. Rotate either one any time — old keys stop working immediately.

    Get cached HTML

    GET /api/v1/cache/gethttp
    GET https://api.uprender.io/api/v1/cache/get?url=<full-url>
    X-UpRender-User-Key: <user key>
    X-UpRender-Domain-Key: <domain key>

    Response:

    200 OKjson
    { "success": true, "html": "<!doctype html>...", "device_type": "desktop", "cached_at": "2026-05-21T08:14:22Z"
    }

    Re-render a URL

    Trigger a fresh render — useful after publishing new content. Requires a logged-in dashboard session (Bearer token).

    POST /api/v1/cache/refreshhttp
    POST https://api.uprender.io/api/v1/cache/refresh
    Authorization: Bearer <your dashboard JWT>
    Content-Type: application/json { "url": "https://yourdomain.com/blog/new-post" }

    Clear by pattern

    Invalidate every URL matching a pattern. Handy after a site-wide redesign.

    POST /api/v1/cache/clearhttp
    POST https://api.uprender.io/api/v1/cache/clear
    Authorization: Bearer <your dashboard JWT>
    Content-Type: application/json { "pattern": "https://yourdomain.com/blog/*" }

    5. Configuration

    Every option below is controllable from the dashboard — no code changes needed.

    Domain settings

    Mobile rendering

    Render every page on both desktop and mobile viewports. Available on Starter and above.

    llms.txt

    Auto-publish a /llms.txt file listing your URLs for AI crawlers. Enabled by default.

    AI visibility

    Run LLM analysis on every render to score AEO/GEO and surface fixes in AI Audit Studio.

    Tracked Bots

    View AI, search, social, and other crawler traffic with trends, verification status, and recent requests.

    Sitemap management

    Sitemaps drive which URLs UpRender renders. You have four ways to get one in:

    • Auto-discover — UpRender scans robots.txt, your homepage, and 15 common paths.
    • Submit a URL — paste your sitemap URL directly.
    • Upload a file — drop in a .xml or .xml.gz sitemap.
    • Paste a URL list — one URL per line; we'll build a synthetic sitemap.

    If none of those produce a sitemap, UpRender will generate one for you from URLs discovered during your first crawl.

    Refreshing content after a deploy

    Three options depending on how much you changed:

    1. Single page — click Re-render on the URL row in Cache Manager.
    2. Pattern — Cache Manager → Clear by pattern → enter /blog/*.
    3. Everything — Cache Manager → Re-render all. Runs in the background; track progress in the activity log.

    6. Plans & Add-ons

    Pick a plan that fits your traffic. If you spike, top up with add-ons instead of upgrading.

    Free

    1 domain · 500 renders/mo · No mobile rendering

    Starter

    3 domains · 10 000 renders/mo · Mobile + AI visibility

    Pro

    10 domains · 100 000 renders/mo · Everything in Starter

    Enterprise

    Unlimited domains · negotiated quotas · SLA + support

    Add-ons

    Top-ups that stay valid until consumed — they never expire monthly.

    • URL Packs — extra render quota (10k, 50k, 100k, or custom).
    • AI Credit Packs — extra AI credits for AI visibility and audits.

    Buy them from Dashboard → Billing → Add-ons. Quota lifts within seconds of payment.

    Invoices & receipts

    Every payment generates an invoice and a receipt, both downloadable as PDFs from Billing → Transaction History. To include a GST or VAT number, fill in your tax ID under Settings → Billing Address before your next payment.

    Go to Billing

    7. FAQ

    How does UpRender know which requests are bots?

    We match the User-Agent against a curated list of known crawlers (Googlebot, Bingbot, GPTBot, ClaudeBot, Slackbot, etc.) plus header heuristics, then show the traffic in Tracked Bots.

    Will my human visitors notice anything?

    No. Your edge integration only routes bot traffic to UpRender — everyone else hits your origin exactly as before.

    How are renders counted against my quota?

    Each unique combination of (URL, device) renders against your monthly quota. Cache hits don't count. Re-renders triggered by a purge or sitemap update do.

    Can I upgrade in the middle of a billing period?

    Yes — you'll be prorated. Downgrades take effect at the next renewal.

    My renders look incomplete — what should I check?

    Make sure your page finishes loading within the render timeout (Settings → Rendering). Check the Render Detail panel for console errors. Cookies and auth headers are stripped by design, so anything behind login won't render.

    How do I purge the cache when I publish new content?

    Call POST /api/v1/cache/refresh from your CMS publish hook, or use the Re-render button on the URL row in Cache Manager.

    Where do I find my invoice?

    Dashboard → Billing → Transaction History. Each row has a Download Invoice button.

    Can I add a GST or VAT ID to my invoices?

    Yes — Settings → Billing Address has a Tax ID field. Anything paid after you save it includes the ID on the invoice.

    8. Support

    We're here when you need us. Most questions are answered within one business day.

    Response time: within one business day (Mon–Fri, IST). For urgent production issues on Pro or Enterprise plans, mark your email subject with [URGENT].

    Ready to integrate?

    Start with the free plan — no credit card needed.

    Get Started