WeWeb generates single-page applications (SPAs) with no server-side rendering as of 2026. Googlebot can index JavaScript-rendered content but with delays. Social media crawlers often cannot. Fix this with per-page meta tags in Page settings → SEO & Meta Tags, Prerender.io or SEO4Ajax for crawler-facing HTML snapshots, a custom sitemap for dynamic pages, and JSON-LD structured data via App Settings → Custom Code.
WeWeb SEO: Solving SPA Crawlability, Meta Tags, and Prerendering
WeWeb is a single-page application builder — it outputs a Vue.js SPA where all content is rendered client-side in the browser. As of 2026, WeWeb does not support server-side rendering (SSR) or static site generation (SSG). This creates two related SEO problems: Google can index JavaScript-rendered content but typically with a delay of days to weeks (its crawler renders JS, but not immediately on discovery); and social media crawlers (Twitter/X, Facebook, LinkedIn, Slack) generally do not execute JavaScript, meaning your Open Graph tags and content may not appear when users share links. This tutorial explains exactly what the limitations are, what you can do about them within WeWeb, and when it makes sense to use a separate platform for SEO-critical content.
Prerequisites
- A WeWeb project published with a custom domain
- Basic understanding of HTML meta tags and what Open Graph (OG) tags are
- A Google Search Console account (free, at search.google.com/search-console) to monitor indexing
- Optional: a Prerender.io account for the prerendering section
Step-by-step guide
Understand What Googlebot Actually Sees
Understand What Googlebot Actually Sees
WeWeb outputs an HTML file that looks like this to a crawler before JavaScript executes: a nearly empty <body> containing only a <div id='app'></div> and script tags. All your visible content, headings, and meta tags are injected by JavaScript after the page loads. Googlebot (Google's crawler) uses a Chromium-based renderer and CAN execute JavaScript — but it queues JavaScript rendering separately from initial crawl. This means: your pages will eventually be indexed, but there can be a delay of days to weeks between when Google discovers a URL and when it renders and indexes the JS-generated content. To verify what Google sees today: use Google Search Console → URL Inspection → enter your page URL → click 'Test Live URL' → click 'View tested page' → switch to 'Screenshot' tab to see the rendered page, and 'HTML' tab to see the rendered HTML including your meta tags.
Expected result: You understand the two-stage Googlebot process and can use Search Console's URL Inspection to verify your pages are indexed with correct meta tags.
Configure Per-Page Meta Tags
Configure Per-Page Meta Tags
In the WeWeb editor, click on any page in the Pages panel (left sidebar). Then click the gear icon that appears next to the page name, or right-click → Page settings. Navigate to the 'SEO & Meta Tags' tab. Fill in: Title Tag (the <title> element — appears in browser tabs and Google search results, max 60 characters), Meta Description (max 155 characters — shown in search snippets), Open Graph Title (og:title — for social sharing), Open Graph Description (og:description), Open Graph Image (og:image — minimum 1200x630px, must be a full URL including https://), Twitter Card type (set to 'summary_large_image' for most pages), and the Canonical URL if needed. These fields are injected as meta tags in the page's <head> when the JS renders. They are read by Googlebot (after rendering) but NOT by social media crawlers (which do not execute JS). For static pages like your homepage and landing pages, filling these fields is sufficient for Google. For social sharing meta tags, you need Prerender.io (Step 5).
Expected result: All major pages have unique Title Tags and Meta Descriptions. Open Graph fields are populated with correct image URLs.
Add Structured Data (JSON-LD) via Custom Code
Add Structured Data (JSON-LD) via Custom Code
Structured data (Schema.org JSON-LD) helps Google understand your content type and can enable rich results (star ratings, FAQ dropdowns, product prices in search). In WeWeb, you cannot inject per-page scripts natively — structured data must go in App Settings → Custom Code → Head section, which applies to all pages. For a site with multiple page types, use a JavaScript approach: inject a single <script type='application/ld+json'> tag that reads the current URL and outputs the appropriate schema. Alternatively, for static pages like your homepage, add a static JSON-LD block. For dynamic collection pages (e.g., /products/:id), JavaScript in the Head can read the URL parameter and output dynamic structured data by constructing the schema from window.location. Note that this approach requires the data to be available at render time — which it is, since WeWeb fetches collections before rendering.
1<!-- Injection point: App Settings → Custom Code → Head section -->2<!-- Static JSON-LD for homepage -->3<script type="application/ld+json">4{5 "@context": "https://schema.org",6 "@type": "WebSite",7 "name": "Your App Name",8 "url": "https://yourapp.com",9 "description": "Your app description here",10 "potentialAction": {11 "@type": "SearchAction",12 "target": "https://yourapp.com/search?q={search_term_string}",13 "query-input": "required name=search_term_string"14 }15}16</script>1718<!-- Dynamic JSON-LD for product pages (/products/:id) -->19<!-- Reads page title and description injected by WeWeb collections -->20<script>21 document.addEventListener('DOMContentLoaded', function() {22 const path = window.location.pathname;23 // Only inject product schema on product pages24 if (path.startsWith('/products/')) {25 // WeWeb will have populated the page title by now26 const title = document.title;27 const script = document.createElement('script');28 script.type = 'application/ld+json';29 script.text = JSON.stringify({30 '@context': 'https://schema.org',31 '@type': 'Product',32 'name': title,33 'url': window.location.href34 });35 document.head.appendChild(script);36 }37 });38</script>Expected result: Structured data is injected for relevant pages. Rich Results Test shows valid schema without errors.
Configure Your Sitemap
Configure Your Sitemap
WeWeb automatically generates a sitemap.xml for all your static pages. Access it at: yourapp.com/sitemap.xml. Verify it includes all your important pages and that URLs are correct. The auto-generated sitemap does NOT include dynamic collection pages (e.g., /products/123, /blog/post-title) because WeWeb has no knowledge of your backend data. For dynamic pages, you need a custom sitemap. Two approaches: (1) Generate a sitemap XML file from your backend data (Supabase query → format as XML → host at a static URL or through an Edge Function) and submit it in Google Search Console. (2) Use a service like Prerender.io's sitemap generator. To submit your sitemap to Google: Google Search Console → your property → Sitemaps → enter sitemap URL → Submit. Check the 'Discovered URLs' count matches your expected page count. Add the sitemap URL to your App Settings → Custom Code → Head: <link rel='sitemap' type='application/xml' href='/sitemap.xml'>.
1-- Injection point: Supabase Edge Function → generates dynamic sitemap2-- supabase/functions/sitemap/index.ts3-- Set up a reverse proxy or CNAME so yourapp.com/sitemap-products.xml calls this function45import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';67const supabase = createClient(8 Deno.env.get('SUPABASE_URL')!,9 Deno.env.get('SUPABASE_ANON_KEY')!10);1112Deno.serve(async () => {13 const { data: products } = await supabase14 .from('products')15 .select('id, updated_at')16 .eq('status', 'active');1718 const urls = (products || []).map(p => `19 <url>20 <loc>https://yourapp.com/products/${p.id}</loc>21 <lastmod>${p.updated_at?.split('T')[0]}</lastmod>22 <changefreq>weekly</changefreq>23 <priority>0.8</priority>24 </url>`);2526 const xml = `<?xml version="1.0" encoding="UTF-8"?>27<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">28${urls.join('')}29</urlset>`;3031 return new Response(xml, {32 headers: { 'Content-Type': 'application/xml' }33 });34});Expected result: WeWeb's auto-generated sitemap is submitted to Google Search Console. A custom sitemap for dynamic pages is generated and submitted separately.
Set Up Prerender.io for Social Media Crawlers
Set Up Prerender.io for Social Media Crawlers
Prerender.io (and similar services like SEO4Ajax) work as a middleware layer: when a crawler visits your site (identified by user-agent), it is redirected to a pre-rendered HTML snapshot of your page instead of the JavaScript SPA. This snapshot includes your Open Graph meta tags, allowing link previews to work correctly on Twitter/X, Facebook, LinkedIn, and Slack. Sign up at prerender.io (free tier available with limited pages). Get your Prerender token. For WeWeb Cloud deployments, you cannot modify the CDN/edge layer directly — use Prerender.io's JavaScript snippet approach: add the Prerender snippet to App Settings → Custom Code → Head (their docs provide the script). This approach has the JS prerender snippet detect crawlers and redirect them server-side. For self-hosted WeWeb (exported code on Cloudflare), you can use Cloudflare Workers to intercept crawler requests and fetch from Prerender.io's API, which is faster and more reliable.
1<!-- Injection point: App Settings → Custom Code → Head section -->2<!-- Prerender.io JavaScript snippet for crawler detection -->3<!-- Get your token from prerender.io dashboard -->4<script>5 window.prerenderReady = false;6</script>7<script>8 (function(w,d) {9 // Prerender.io snippet - replace YOUR_TOKEN with actual token10 var e = d.createElement('script');11 e.src = 'https://cdn.prerender.io/prerender.js';12 e.setAttribute('data-token', 'YOUR_PRERENDER_TOKEN');13 d.head.appendChild(e);14 })(window, document);15</script>1617<!-- Signal to Prerender that page is fully rendered -->18<!-- Add this to your On page load workflow's last Custom JavaScript action -->19<!-- Or set it in App Settings → Custom Code → Body -->20<script>21 document.addEventListener('DOMContentLoaded', function() {22 // Tell Prerender.io the page is ready after collections load23 // In production, move this to a workflow action after all collections fetch24 setTimeout(function() {25 window.prerenderReady = true;26 }, 2000);27 });28</script>Expected result: Sharing links from your WeWeb app on Twitter/X, LinkedIn, and Slack shows correct titles, descriptions, and preview images.
Optimize Meta Tags for Dynamic Collection Pages
Optimize Meta Tags for Dynamic Collection Pages
For pages using URL path parameters (e.g., /products/:id), meta tags need to be dynamic — the title and description should reflect the specific product being shown. In WeWeb, go to the dynamic page settings → SEO & Meta Tags. Instead of a static title, click the formula icon (plug icon 🔌) next to the Title Tag field and bind it to a formula using your collection: collections['currentProduct'].data[0].title + ' | Your App Name'. Similarly bind the Meta Description field to: collections['currentProduct'].data[0].description. For the Open Graph Image, bind to: collections['currentProduct'].data[0].image_url. These dynamic bindings use the JavaScript-rendered data — they are visible to Googlebot after rendering, but still invisible to social crawlers without Prerender.io. Ensure your collection is set up to fetch the product matching the URL parameter (Page URL variable :id → collection filter id = urlParam).
Expected result: Dynamic pages have unique, data-driven meta tags. Google Search Console URL Inspection shows the correct product title and description for individual product pages.
Consider a Separate Platform Strategy for SEO-Critical Content
Consider a Separate Platform Strategy for SEO-Critical Content
For marketing sites, blogs, and other SEO-heavy content where organic search is a primary acquisition channel, WeWeb's SPA architecture is a meaningful disadvantage compared to SSR-first platforms like WordPress, Webflow, or Nuxt.js. A practical hybrid strategy: host your marketing site and blog on a subdomain (blog.yourapp.com) using WordPress or Webflow, which provide native SSR and immediate indexing with no prerendering workarounds. Host your actual application (app.yourapp.com or /app path) in WeWeb where the SPA strengths — fast navigation, rich interactions, complex state — are most valuable. Link between the two for cross-pollination of authority. This is the same strategy used by many SaaS companies: a content-rich marketing site built for SEO plus a React/Vue SPA for the product. WeWeb is the product layer, not the content layer.
Expected result: Clear strategy for which content lives in WeWeb vs a separate SEO-optimized platform, with cross-linking between them.
Complete working example
1<!-- Injection point: App Settings → Custom Code → Head section -->2<!-- Comprehensive meta tag setup for WeWeb SPA -->3<!-- Replace all placeholder values with your actual content -->45<!-- Primary meta tags (also read by Googlebot after JS render) -->6<!-- Note: These are ALSO set per-page in Page settings → SEO & Meta Tags -->7<!-- The Custom Code below handles the fallback/global defaults -->89<!-- Open Graph fallback for social crawlers (static fallback only) -->10<!-- Dynamic values require Prerender.io to be set correctly -->11<meta property="og:site_name" content="Your App Name" />12<meta property="og:type" content="website" />13<meta property="og:locale" content="en_US" />1415<!-- Twitter Card defaults -->16<meta name="twitter:card" content="summary_large_image" />17<meta name="twitter:site" content="@yourhandle" />1819<!-- Canonical URL helper: prevents duplicate content on hash routes -->20<script>21 // Inject canonical URL dynamically based on current path22 (function() {23 function setCanonical() {24 var existing = document.querySelector('link[rel="canonical"]');25 if (!existing) {26 var link = document.createElement('link');27 link.rel = 'canonical';28 link.href = window.location.origin + window.location.pathname;29 document.head.appendChild(link);30 }31 }32 // Run on initial load33 if (document.readyState === 'loading') {34 document.addEventListener('DOMContentLoaded', setCanonical);35 } else {36 setCanonical();37 }38 // Run on SPA navigation (Vue Router history change)39 var _pushState = history.pushState;40 history.pushState = function() {41 _pushState.apply(history, arguments);42 setTimeout(setCanonical, 100);43 };44 })();45</script>4647<!-- Robots meta: adjust per environment -->48<!-- Remove or change to 'index, follow' for production -->49<!-- <meta name="robots" content="noindex, nofollow" /> -->5051<!-- Sitemap reference -->52<link rel="sitemap" type="application/xml" href="/sitemap.xml" />Common mistakes
Why it's a problem: Assuming that filling in WeWeb's Page settings → SEO & Meta Tags fields will fix social media link previews
How to avoid: WeWeb's meta tags are injected by JavaScript after page load. Social media crawlers (Twitter, Facebook, LinkedIn, Slack) do not execute JavaScript. Your OG tags are invisible to them. To fix social previews, you need Prerender.io or a similar HTML snapshot service. Google is the exception — it renders JS and will eventually see your tags.
Why it's a problem: Expecting the auto-generated sitemap.xml to include your dynamic collection pages (/products/123, /blog/post-slug)
How to avoid: WeWeb's sitemap only includes statically defined pages. Dynamic collection pages are not in the sitemap because WeWeb does not know which IDs exist in your database. Create a custom sitemap using a Supabase Edge Function that queries your database and generates XML, then submit it to Google Search Console separately.
Why it's a problem: Adding custom CSS in App Settings → Custom Code → Head and wondering why it does not appear in the preview
How to avoid: Custom CSS added in the Head section is NOT rendered in the WeWeb editor preview. You must publish your app to see Custom Code changes. Always publish to a staging environment (if on Scale plan) or directly to production, then check using Chrome DevTools or by viewing page source.
Why it's a problem: Setting window.prerenderReady = true too early before collections have finished loading
How to avoid: Prerender.io takes its HTML snapshot when window.prerenderReady is true. If you set it immediately on DOMContentLoaded, your content may not be loaded yet and the snapshot will be empty. Set it as the last action in your On page load workflow using a Custom JavaScript action, after all collections have been fetched.
Best practices
- Use unique Title Tags for every page — avoid duplicate titles which dilute SEO value and confuse Google
- Keep meta descriptions under 155 characters and make them actionable — they are your 'ad copy' in search results
- Submit your sitemap to Google Search Console and monitor 'Crawled - currently not indexed' pages which indicate content Google has seen but not indexed
- Use Google's URL Inspection tool in Search Console to verify each important page is indexed correctly with the right title and description
- For pages that should never be indexed (admin panels, internal tools, login pages), add a robots meta tag: set Page settings → SEO → no-index toggle, or add <meta name='robots' content='noindex'> for those pages via a page-specific method
- Test Open Graph previews using the LinkedIn Post Inspector (linkedin.com/post-inspector) and the Facebook Sharing Debugger (developers.facebook.com/tools/debug) after setting up Prerender.io
- Consider structured data (FAQ schema) for any page that has a FAQ section — it can earn Google's FAQ rich result which significantly increases click-through rate
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have a WeWeb SPA (no SSR support as of 2026) with product pages at /products/:id. Each product has a title, description, and image URL stored in Supabase. Write a Supabase Edge Function that generates a dynamic sitemap.xml for all active products, formatted correctly for Google Search Console submission.
My WeWeb app has dynamic product pages at /products/:id with a 'currentProduct' collection that fetches by URL parameter. Help me write the formula for the Page settings → SEO & Meta Tags → Title Tag field that outputs: '[Product Name] - Buy Online | My Store', using the currentProduct collection data.
Frequently asked questions
Does WeWeb support server-side rendering (SSR) in 2026?
No. As of March 2026, WeWeb does not support SSR or static site generation (SSG). All rendering happens client-side in the browser. WeWeb's team has mentioned SSR as a future consideration, but no release date has been announced. All WeWeb apps are Vue.js single-page applications. This is the fundamental reason for the SEO limitations described in this guide.
Will Google eventually index all my WeWeb pages even without SSR?
Yes, Google's Googlebot renders JavaScript and will index your pages — but with a delay. Initial discovery happens quickly; JavaScript rendering is queued separately and can take days to weeks. Once indexed, your pages appear in search results. The main issues are: (1) the indexing delay for new content, (2) dynamic meta tags may not be read on first crawl, and (3) link previews on social platforms will not work without Prerender.io.
Can I add Google Analytics to a WeWeb site?
Yes. The recommended approach is to install the Google Tag Manager plugin: Plugins → Extensions → Google Tag Manager → enter your GTM Container ID. Then configure GA4 inside GTM. Alternatively, add the GA4 script snippet directly in App Settings → Custom Code → Head section. WeWeb SPAs require special handling for page view tracking — use GTM's History Change trigger to fire page view events on SPA navigation.
How do I stop Google from indexing certain WeWeb pages (like my admin dashboard)?
In the WeWeb editor, go to the page's Page settings → SEO & Meta Tags tab and look for the 'No-index' toggle or robots field. Set it to 'noindex, nofollow' for pages you want excluded from Google. Alternatively, add a Custom JavaScript action On page load that checks if the current page is an admin page and injects a noindex meta tag. For the most reliable exclusion, also add the page to a robots.txt Disallow rule — add your robots.txt content in App Settings → Custom Code if WeWeb does not expose a robots.txt editor directly.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation