Prerender and SEO for SPAs: be seen in search engines, AI and social networks.
Be seen in search engines, AI and social networks.
Jazui is a prerender and SEO service for SPAs (Angular, React, Vue, Blazor, Svelte...). It serves Google, AI bots (ChatGPT, Claude, Perplexity...) and social networks the already rendered HTML of your site, without touching your code. It also tells you who visits you and what is failing, and spreads your content with a blog, AI with your own key and metrics. People never go through Jazui: they keep using your usual app. Jazui is built with AstrolUI.
In a SPA the initial HTML is almost empty and the content is built by JavaScript in the browser (in Blazor WebAssembly the .NET runtime is downloaded first, too). Many bots don't run JavaScript, or run it late and with limits: the result is incomplete indexing, generic titles and descriptions, empty previews when a link is shared and AI answers that never cite your site.
Prerendering hands each bot an already rendered HTML version of the page, with its content, its meta and Open Graph tags and the real status code (200, 404, redirect...), without changing anything in the app.
To start: create the account, add the site, verify the domain (DNS or meta tag) and connect the integration.
Choose where bots are recognized. Each card opens its guide in the Jazui documentation.
Blazor served by ASP.NET Core (hosted WebAssembly or Blazor Web App): install Jazui.AspNetCore from the same AstrolUI feed and add the middleware before the static files and the fallback. It is the most robust option: if Jazui is slow or fails, the bot gets the normal page. The token goes in the Jazui__Token environment variable.
dotnet nuget add source https://nuget.astrolui.com/v3/index.json --name AstrolUIdotnet add package Jazui.AspNetCore// Program.cs of the ASP.NET Core app that serves the Blazor WebAssembly clientbuilder.Services.AddJazui(builder.Configuration); // section "Jazui": Token, SiteUrl, Timeout... var app = builder.Build();app.UseForwardedHeaders(); // only behind a proxy or CDNapp.UseJazui(); // before the static files and the SPA fallbackapp.UseStaticFiles();app.MapFallbackToFile("index.html");app.Run(); // Token: environment variable Jazui__Token (never in appsettings.json)Static Blazor WebAssembly on IIS: add the «Jazui» rule as the first rule of the web.config the site already has (don't replace it: it carries the MIME types and Blazor's rules) and enable the ARR proxy and the server variables once per server. Behind Cloudflare, the bot IP comes from {HTTP_CF_CONNECTING_IP}. Turn the rule on once the site is verified in Jazui: with ARR, if Jazui answers with an error, the bot gets that error.
<!-- First rule of <rewrite><rules>, before the Blazor SPA fallback. Full bot list: https://docs.jazui.com/example_config/iis_web.xml --><rule name="Jazui" stopProcessing="true"> <match url=".*" /> <conditions logicalGrouping="MatchAll"> <add input="{HTTP_USER_AGENT}#{QUERY_STRING}" pattern="^[^#]*(?:googlebot|bingbot|gptbot|chatgpt|claudebot|perplexity|facebookexternalhit|linkedinbot|whatsapp|...)|#.*_escaped_fragment_" /> <add input="{REQUEST_METHOD}" pattern="^(GET|HEAD)$" /> <add input="{HTTP_X_JAZUI}" pattern=".+" negate="true" /> <add input="{URL}" pattern="\.(js|mjs|css|map|json|xml|txt|ico|png|jpg|svg|woff|woff2|wasm|dll|dat|blat|br|gz|pdf)$" negate="true" /> </conditions> <serverVariables> <set name="HTTP_AUTHORIZATION" value="Bearer [JAZUI_TOKEN]" /> <set name="HTTP_X_JAZUI_URL" value="https://{HTTP_HOST}{UNENCODED_URL}" /> <set name="HTTP_X_JAZUI_CLIENT_IP" value="{REMOTE_ADDR}" /> <!-- behind Cloudflare: {HTTP_CF_CONNECTING_IP} --> <set name="HTTP_COOKIE" value="" /> </serverVariables> <action type="Rewrite" url="https://api.jazui.com/Render" appendQueryString="false" /></rule>rem Once per server, as administrator: ARR proxy and the server variables the rule writes%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/proxy /enabled:"True" /commit:apphost%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/rewrite/allowedServerVariables /+"[name='HTTP_AUTHORIZATION']" /+"[name='HTTP_X_JAZUI_URL']" /+"[name='HTTP_X_JAZUI_CLIENT_IP']" /+"[name='HTTP_COOKIE']" /commit:apphostOn every page, so the SEO score goes up and previews look right:
<PageTitle>Product X | MyStore</PageTitle><AstrolTitle Icon="astrol-basket" Text="Product X"> <HeadContent> <meta name="description" content="Short description that will appear in Google" /> <meta property="og:title" content="Product X" /> <meta property="og:description" content="Preview text for WhatsApp, LinkedIn, X..." /> <meta property="og:image" content="https://mystore.com/img/product-x.jpg" /> <link rel="canonical" href="https://mystore.com/product/x" /> </HeadContent></AstrolTitle>Every integration calls GET https://api.jazui.com/Render?url= with the full encoded URL (or in the X-Jazui-Url header) and Authorization: Bearer with the account render token or a site token, kept by convention in the JAZUI_TOKEN variable (or Jazui__Token in .NET). Optional: botAgent, X-Jazui-Client-IP (the bot IP) and If-None-Match. The response is delivered to the bot only if it carries X-Jazui: true; with X-Jazui-Blocked the bot is blocked (403) and in any other case the normal site is served. To avoid loops, integrations let through requests that already carry the X-Jazui header. Never expose the token on the client.
There are also cache APIs (re-cache, purge), signed webhooks, blog and site files: see docs.jazui.com/api.
curl "https://api.jazui.com/Render?url=https%3A%2F%2Fexample.com%2F&botAgent=integration-test" \ -H "Authorization: Bearer $JAZUI_TOKEN" -i # Deliver the response to the bot only if it carries X-Jazui: true (any status: 200, 301, 404...).# X-Jazui-Blocked = blocked bot (403). Anything else, or a timeout: serve the normal site.Jazui has a free plan and monthly or yearly paid plans with a free trial. Prices and the limits of each plan are always up to date at jazui.com/plan.