Skip to main content
Server-side code and HTTP functions powering advanced SEO features in Velo by Wix
Module 20·Lesson 11 of 17·30 min read

Custom HTTP functions and advanced server-side SEO with Velo

Velo HTTP functions let you create custom API endpoints on Wix. This lesson shows advanced techniques including programmatic sitemap generation, redirect management, and server-side rendering considerations.

What you will learn in this Wix SEO lesson

  • Creating custom sitemaps with Velo HTTP functions
  • Building a dynamic redirect system on Wix
  • Implementing server-side logic for SEO A/B testing
  • Custom 404 handling with Velo routers
  • Rate limiting and caching for custom SEO endpoints

Most Wix SEO work happens in the frontend: setting meta tags, generating schema, optimizing content. But some of the most powerful SEO techniques require server-side logic that runs before the page is ever delivered to the browser or the bot. Velo HTTP functions let you create custom API endpoints on your Wix site, and Velo routers let you intercept URL requests with server-side logic. Together, these tools enable custom sitemaps, programmatic redirect systems, SEO A/B testing, and intelligent 404 handling that would otherwise require a standalone server.

How-to diagram showing Wix Studio and Velo advanced SEO capabilities including dynamic meta tags, custom schema markup, CMS database pages, multilingual hreflang, and A/B testing
Wix Studio and Velo unlock advanced SEO capabilities that go far beyond what the standard Wix editor provides.

Understanding Velo HTTP Functions for SEO

Velo HTTP functions are server-side endpoints you create in the backend/http-functions.js file. Each function corresponds to a URL pattern on your site: a function named get_customSitemap becomes accessible at yoursite.com/_functions/customSitemap via GET request. These functions execute on Wix servers, have access to your CMS data, and can return any HTTP response including XML, JSON, or plain text.

For SEO, the key advantage is that HTTP functions run entirely server-side with no client JavaScript rendering required. Search engine bots receive the response directly, exactly as your function constructs it. This makes HTTP functions ideal for generating XML sitemaps, serving robots.txt modifications, creating JSON API endpoints for external SEO tools, and building webhook receivers for content syndication platforms.

import { ok, notFound, serverError } from 'wix-http-functions';
import wixData from 'wix-data';

export async function get_customSitemap(request) {
  try {
    const result = await wixData.query('Products')
      .eq('isPublished', true)
      .ne('noIndex', true)
      .limit(1000)
      .find();

    const baseUrl = 'https://www.yourstore.com';
    let xml = '<?xml version="1.0" encoding="UTF-8"?>';
    xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';

    result.items.forEach(item => {
      xml += '<url>';
      xml += '<loc>' + baseUrl + '/products/' + item.slug + '</loc>';
      xml += '<lastmod>' + new Date(item._updatedDate).toISOString().split('T')[0] + '</lastmod>';
      xml += '<changefreq>weekly</changefreq>';
      xml += '<priority>0.8</priority>';
      xml += '</url>';
    });

    xml += '</urlset>';

    return ok({
      headers: { 'Content-Type': 'application/xml' },
      body: xml
    });
  } catch (error) {
    return serverError({ body: 'Sitemap generation failed' });
  }
}

Building a Custom Sitemap System

The default Wix sitemap works well for most sites, but it has limitations. It includes all published pages regardless of their SEO value, does not support custom priority or changefreq values per URL, and cannot include URLs from external systems or custom routing logic. A custom sitemap built with HTTP functions gives you complete control over which URLs are included, their metadata, and how the sitemap is structured.

For large sites with more than 50,000 URLs, you need a sitemap index that references multiple individual sitemaps. The sitemap protocol limits each sitemap file to 50,000 URLs and 50MB uncompressed. Your HTTP function can generate a sitemap index that points to paginated sitemap files, each of which is also served by an HTTP function with offset and limit parameters.

export async function get_sitemapIndex(request) {
  const collections = [
    { name: 'Products', count: 5000 },
    { name: 'BlogPosts', count: 800 },
    { name: 'Locations', count: 200 }
  ];

  const baseUrl = 'https://www.yourstore.com';
  let xml = '<?xml version="1.0" encoding="UTF-8"?>';
  xml += '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';

  collections.forEach(col => {
    const pages = Math.ceil(col.count / 1000);
    for (let i = 0; i < pages; i++) {
      xml += '<sitemap>';
      xml += '<loc>' + baseUrl + '/_functions/sitemap_' + col.name.toLowerCase() + '?page=' + i + '</loc>';
      xml += '<lastmod>' + new Date().toISOString().split('T')[0] + '</lastmod>';
      xml += '</sitemap>';
    }
  });

  xml += '</sitemapindex>';

  return ok({
    headers: { 'Content-Type': 'application/xml' },
    body: xml
  });
}

Dynamic Redirect Systems with HTTP Functions

URL redirects are essential during site migrations, product discontinuations, and URL restructuring. While Wix offers a built-in redirect manager, it has a limit on the number of redirects and does not support pattern-based or conditional redirects. A Velo-powered redirect system stores redirect rules in a CMS collection and evaluates them server-side, supporting thousands of redirects with pattern matching and conditional logic.

Store your redirect rules in a collection with fields for source URL pattern, destination URL, redirect type (301 permanent or 302 temporary), and an active/inactive flag. Your HTTP function or router queries this collection on each request and returns the appropriate redirect response. This approach scales to tens of thousands of redirects and can be updated by non-technical team members through the CMS interface.

import { ok, redirect, notFound } from 'wix-router';
import wixData from 'wix-data';

export async function products_Router(request) {
  const slug = request.path[0];

  const redirectResult = await wixData.query('Redirects')
    .eq('sourceSlug', slug)
    .eq('isActive', true)
    .find();

  if (redirectResult.items.length > 0) {
    const rule = redirectResult.items[0];
    return redirect(rule.destinationUrl, rule.redirectType === '301' ? '301' : '302');
  }

  const productResult = await wixData.query('Products')
    .eq('slug', slug)
    .eq('isPublished', true)
    .find();

  if (productResult.items.length === 0) {
    return notFound();
  }

  return ok('product-page', productResult.items[0]);
}

Server-Side Logic for SEO A/B Testing

SEO A/B testing allows you to test different title tags, meta descriptions, or page content variations to determine which version produces better rankings or click-through rates. Unlike traditional A/B testing where you split traffic between two page versions, SEO A/B testing assigns a variation to a page permanently (for the duration of the test) so that Googlebot consistently sees the same version and can evaluate it fairly.

Implement this by creating a CMS collection that maps page slugs to test variations. The router or page-level Velo code queries this collection and applies the assigned variation. Each variation includes its own title, meta description, and any other elements being tested. After sufficient time (typically 4-8 weeks), compare rankings and CTR data in Google Search Console to determine the winner.

import wixData from 'wix-data';
import wixSeo from 'wix-seo';

$w.onReady(async function () {
  const routerData = $w('#dynamicDataset').getCurrentItem();
  const slug = routerData.slug;

  const testResult = await wixData.query('SeoTests')
    .eq('pageSlug', slug)
    .eq('isActive', true)
    .find();

  if (testResult.items.length > 0) {
    const test = testResult.items[0];
    wixSeo.title = test.testTitle;
    wixSeo.metaTags = [
      { name: 'description', content: test.testDescription }
    ];
  } else {
    wixSeo.title = routerData.seoTitle || routerData.name + ' | YourBrand';
    wixSeo.metaTags = [
      { name: 'description', content: routerData.metaDescription }
    ];
  }
});

A/B Testing Tip

Only test one SEO element at a time to isolate its impact. If you change both the title and meta description simultaneously, you will not know which change drove the result. Start with title tag testing because it has the most direct impact on both rankings and CTR, then test meta descriptions in a separate experiment.

Custom 404 Handling with Velo Routers

A well-designed 404 system does more than show an error page. It logs missing URLs to help you identify broken links and redirect opportunities, suggests relevant content to keep users on your site, and returns the correct HTTP status code so search engines know the page is genuinely gone rather than temporarily unavailable. Velo routers give you full control over this behavior.

When a router cannot find a matching item for the requested slug, instead of returning a generic 404, query your CMS for similar items and pass them to a custom 404 page template. Log the requested URL to a "BrokenUrls" collection for later review. If the URL matches a known pattern from a previous site structure, automatically redirect to the new equivalent.

import { ok, notFound, redirect } from 'wix-router';
import wixData from 'wix-data';

export async function blog_Router(request) {
  const slug = request.path[0];

  const postResult = await wixData.query('BlogPosts')
    .eq('slug', slug)
    .eq('isPublished', true)
    .find();

  if (postResult.items.length > 0) {
    return ok('blog-post-page', postResult.items[0]);
  }

  const redirectResult = await wixData.query('Redirects')
    .eq('sourceSlug', slug)
    .find();

  if (redirectResult.items.length > 0) {
    return redirect(redirectResult.items[0].destinationUrl, '301');
  }

  await wixData.insert('BrokenUrls', {
    requestedUrl: '/blog/' + slug,
    referrer: request.referrer || 'direct',
    timestamp: new Date(),
    resolved: false
  });

  const relatedPosts = await wixData.query('BlogPosts')
    .eq('isPublished', true)
    .descending('publishDate')
    .limit(5)
    .find();

  return notFound('custom-404-page', {
    requestedSlug: slug,
    suggestedPosts: relatedPosts.items
  });
}

Rate Limiting and Caching for Server-Side SEO Functions

HTTP functions that generate sitemaps or handle redirects can receive significant traffic, both from search engine bots and from malicious scrapers. Without caching, every request triggers a fresh database query, which can exhaust your Wix data quotas and slow down response times. Implement simple in-memory caching by storing the generated response in a module-level variable with a timestamp, and serving the cached version until it expires.

For sitemaps specifically, a cache duration of 1-6 hours is appropriate. Your product catalog does not change every minute, and search engines typically re-fetch sitemaps on a daily or weekly basis. For redirect lookups, consider loading all active redirects into memory on the first request and refreshing the cache every 30 minutes, rather than querying the database on every single page request.

import { ok } from 'wix-http-functions';
import wixData from 'wix-data';

let cachedSitemap = null;
let cacheTimestamp = 0;
const CACHE_DURATION = 3600000;

export async function get_productSitemap(request) {
  const now = Date.now();

  if (cachedSitemap && (now - cacheTimestamp) < CACHE_DURATION) {
    return ok({
      headers: { 'Content-Type': 'application/xml' },
      body: cachedSitemap
    });
  }

  const result = await wixData.query('Products')
    .eq('isPublished', true)
    .limit(1000)
    .find();

  const baseUrl = 'https://www.yourstore.com';
  let xml = '<?xml version="1.0" encoding="UTF-8"?>';
  xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';

  result.items.forEach(item => {
    xml += '<url>';
    xml += '<loc>' + baseUrl + '/products/' + item.slug + '</loc>';
    xml += '<lastmod>' + new Date(item._updatedDate).toISOString().split('T')[0] + '</lastmod>';
    xml += '</url>';
  });

  xml += '</urlset>';

  cachedSitemap = xml;
  cacheTimestamp = now;

  return ok({
    headers: { 'Content-Type': 'application/xml' },
    body: xml
  });
}

Server-Side SEO Power

HTTP functions and routers are the most underused SEO tools in the Velo ecosystem. Most Wix developers never touch them, which means most Wix sites miss out on custom sitemaps, intelligent redirects, and server-side logic that can give you a significant competitive edge. If you are comfortable with JavaScript, these backend tools transform Wix from a simple website builder into a fully programmable SEO platform.



Complete How-To Guide: Building Custom HTTP Functions and Routers for SEO

This guide walks you through creating custom sitemaps, programmatic redirect systems, and intelligent 404 handling using Velo HTTP functions and routers on your Wix site.

How to implement server-side SEO tools with Velo

  1. 1Step 1: Enable Velo on your Wix site. In the code editor, navigate to the backend folder. Create a new file called http-functions.js if it does not already exist. This is where all your HTTP function endpoints will live.
  2. 2Step 2: Build your first custom sitemap function. Import ok, notFound, and serverError from wix-http-functions and wixData from wix-data. Create an exported async function named get_customSitemap that queries your Products collection filtered by isPublished equals true.
  3. 3Step 3: In the sitemap function, build an XML string following the sitemaps.org protocol. Start with the XML declaration and urlset element. Loop through query results, adding a url element for each item with loc, lastmod (from the item _updatedDate), changefreq, and priority values.
  4. 4Step 4: Return the XML using ok() with Content-Type set to application/xml. Wrap the entire function in a try-catch block returning serverError on failure. Test the endpoint by visiting yoursite.com/_functions/customSitemap.
  5. 5Step 5: For sites with more than 1000 URLs, build a sitemap index function. Create get_sitemapIndex that lists individual sitemap files for each collection. Each individual sitemap function accepts a page query parameter for pagination with 1000 items per page.
  6. 6Step 6: Add caching to your sitemap function. Declare a module-level variable for the cached XML and a timestamp. On each request, check if the cache is still valid (less than 1 hour old). Serve the cached version if valid, otherwise regenerate and update the cache.
  7. 7Step 7: Build a CMS-driven redirect system. Create a Redirects collection in your CMS with fields for sourceSlug, destinationUrl, redirectType (301 or 302), and isActive boolean. Create a router file (routers.js) that queries this collection on each request.
  8. 8Step 8: In your router function, first check the Redirects collection for a matching source slug. If found, return redirect() with the destination URL and the specified redirect type. If not found, proceed to query the main content collection for the requested item.
  9. 9Step 9: Implement intelligent 404 handling. When no matching item is found and no redirect exists, log the broken URL to a BrokenUrls collection with the requested path, referrer, timestamp, and a resolved boolean set to false.
  10. 10Step 10: Before returning the 404 response, query your main collection for the 5 most recent published items. Pass these as suggested content to a custom 404 page template using notFound('custom-404-page', { suggestedPosts: relatedItems }).
  11. 11Step 11: Submit your custom sitemap URL to Google Search Console. Navigate to Sitemaps in GSC and add yoursite.com/_functions/customSitemap. Monitor the submission status and fix any reported errors.
  12. 12Step 12: Set up a monthly routine to review the BrokenUrls collection. Sort by frequency of hits and create redirects for the most-requested broken URLs. Check if any represent content gaps that you should fill by creating new pages at those URLs.

HTTP Function Testing

Test HTTP functions by visiting the endpoint URL directly in your browser. For XML responses like sitemaps, use a browser extension or copy the URL into an XML validator to verify the output is well-formed. For router functions, test with both valid and invalid slugs to verify the redirect, content serving, and 404 handling logic all work correctly.

Finished this lesson?

Mark it complete to track your course progress.

AI Lesson Tutor

AI Powered

Got a question about this lesson? Ask the AI tutor for a quick explanation or practical examples.

Your Course Resources

11 downloadable PDFs -- checklists, templates, worksheets and your certificate

Course Progress0/561 lessons

Checklists

Wix SEO Audit ChecklistPDF

20-point site-wide audit covering technical, on-page, content and local SEO

On-Page SEO ChecklistPDF

37-point per-page checklist: titles, headings, content, images, links, schema

Technical SEO Deep-DivePDF

50-point technical audit: crawlability, Core Web Vitals, speed, security, Wix-specific

Local SEO Setup ChecklistPDF

42-point local checklist: Google Business Profile, NAP, citations, reviews, local links

Site Launch SEO ChecklistPDF

48-point pre-launch and post-launch guide for new Wix sites going live

Templates & Worksheets

Keyword Research TemplatePDF

Printable tracker with columns for volume, difficulty, intent, priority and notes

Monthly SEO Report TemplatePDF

Client-ready report covering traffic, rankings, technical health and action plan

Content Brief TemplatePDF

Plan every page: target keywords, outline, competitor analysis, internal links, CTAs

Backlink Outreach TrackerPDF

Campaign log with status tracking plus 3 proven outreach email templates

Competitor Analysis WorksheetPDF

14-metric comparison table, content gap analysis and SEO SWOT framework

Achievement

Certificate of CompletionLocked

Complete all lessons to unlock (0/561 done)

Lesson Tools

No part of this Wix SEO Course content may be reproduced, copied, or distributed without the written consent of Michael Andrews.

This lesson on Custom HTTP functions and advanced server-side SEO with Velo is part of Module 20: Wix Studio & Velo Advanced SEO in The Most Comprehensive Complete Wix SEO Course in the World (2026 Edition). It covers Wix SEO optimization (US) and optimisation (UK) strategies applicable to businesses in the United Kingdom, United States, Australia, Canada, New Zealand, Ireland and worldwide. Created by Michael Andrews, the UK's No.1 Wix SEO Expert with 14 years of hands-on experience, 750+ completed Wix SEO projects and 425+ verified five-star reviews. This is lesson 228 of 561 in the most affordable, most comprehensive Wix SEO training programme available in 2026.