WPMozo: add-ons and tools for WordPress and Elementor
⚡ Cloudflare · Client-side · No data sent to server

Cloudflare Workers Snippets

Browse ready-to-deploy Cloudflare Workers patterns: routing, CORS, A/B testing, redirects, rate limiting, caching, and header manipulation. Click to copy.

19 of 19 snippets

Routing & Responses

Route Matcher
routingurlpath
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    const path = url.pathname;

    if (path === '/' || path === '/home') {
      return new Response('Welcome to the homepage', {
        headers: { 'Content-Type': 'text/plain' },
      });
    }

    if (path.startsWith('/api/')) {
      return new Response('API endpoint hit: ' + path, {
        headers: { 'Content-Type': 'text/plain' },
      });
    }

    if (path === '/about') {
      return new Response('About page', {
        headers: { 'Content-Type': 'text/plain' },
      });
    }

    // Unmatched - pass through to origin
    return fetch(request);
  },
};
JSON API Response
jsonapicors
export default {
  async fetch(request, env, ctx) {
    const data = {
      success: true,
      message: 'Hello from the edge',
      timestamp: Date.now(),
      region: request.cf?.colo ?? 'unknown',
    };

    return new Response(JSON.stringify(data, null, 2), {
      status: 200,
      headers: {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*',
        'Cache-Control': 'no-store',
      },
    });
  },
};
Static HTML Response
htmlresponsestatic
const HTML = `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Edge Page</title>
</head>
<body>
  <h1>Hello from Cloudflare Workers</h1>
  <p>Served at the edge.</p>
</body>
</html>`;

export default {
  async fetch(request, env, ctx) {
    return new Response(HTML, {
      headers: { 'Content-Type': 'text/html;charset=UTF-8' },
    });
  },
};
404 Handler
404errorrouting
const KNOWN_ROUTES = new Set(['/', '/about', '/contact', '/blog']);

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);

    if (!KNOWN_ROUTES.has(url.pathname)) {
      const body = JSON.stringify({
        error: 'Not Found',
        path: url.pathname,
        status: 404,
      });
      return new Response(body, {
        status: 404,
        headers: { 'Content-Type': 'application/json' },
      });
    }

    // Pass known routes to origin
    return fetch(request);
  },
};

Headers & Security

Add Security Headers
securityheaderscsphsts
export default {
  async fetch(request, env, ctx) {
    const response = await fetch(request);

    // Clone so we can mutate headers
    const newResponse = new Response(response.body, response);
    const h = newResponse.headers;

    h.set('X-Frame-Options', 'SAMEORIGIN');
    h.set('X-Content-Type-Options', 'nosniff');
    h.set('Referrer-Policy', 'strict-origin-when-cross-origin');
    h.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
    h.set(
      'Content-Security-Policy',
      "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';"
    );
    h.set(
      'Strict-Transport-Security',
      'max-age=63072000; includeSubDomains; preload'
    );

    return newResponse;
  },
};
CORS Headers
corspreflightheaders
const ALLOWED_ORIGIN = 'https://yourdomain.com';

const CORS_HEADERS = {
  'Access-Control-Allow-Origin': ALLOWED_ORIGIN,
  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization',
  'Access-Control-Max-Age': '86400',
};

export default {
  async fetch(request, env, ctx) {
    // Handle preflight
    if (request.method === 'OPTIONS') {
      return new Response(null, { status: 204, headers: CORS_HEADERS });
    }

    const response = await fetch(request);
    const newResponse = new Response(response.body, response);

    for (const [key, value] of Object.entries(CORS_HEADERS)) {
      newResponse.headers.set(key, value);
    }

    return newResponse;
  },
};
Remove Sensitive Headers
securityheadersx-powered-by
const SENSITIVE_HEADERS = [
  'X-Powered-By',
  'Server',
  'X-AspNet-Version',
  'X-AspNetMvc-Version',
];

export default {
  async fetch(request, env, ctx) {
    const response = await fetch(request);
    const newResponse = new Response(response.body, response);

    for (const header of SENSITIVE_HEADERS) {
      newResponse.headers.delete(header);
    }

    return newResponse;
  },
};
Rate Limit by IP
rate-limitipsecurity
// Note: in-memory counters reset per isolate restart.
// For persistent rate limiting across all edge nodes, use Workers KV or Durable Objects.
const LIMIT = 60;          // max requests
const WINDOW_MS = 60000;   // per 60 seconds

const counters = new Map();

export default {
  async fetch(request, env, ctx) {
    const ip = request.headers.get('CF-Connecting-IP') ?? 'unknown';
    const now = Date.now();
    const entry = counters.get(ip);

    if (!entry || now - entry.start > WINDOW_MS) {
      counters.set(ip, { count: 1, start: now });
    } else {
      entry.count++;
      if (entry.count > LIMIT) {
        return new Response('Too Many Requests', {
          status: 429,
          headers: {
            'Retry-After': '60',
            'Content-Type': 'text/plain',
          },
        });
      }
    }

    return fetch(request);
  },
};

Redirects

Bulk Redirects
redirect301bulk
// Map of old path -> new full URL (or path)
const REDIRECTS = new Map([
  ['/old-page', 'https://example.com/new-page'],
  ['/blog/2020/post-title', 'https://example.com/posts/post-title'],
  ['/products', 'https://example.com/shop'],
  ['/contact-us', 'https://example.com/contact'],
]);

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    const destination = REDIRECTS.get(url.pathname);

    if (destination) {
      return Response.redirect(destination, 301);
    }

    return fetch(request);
  },
};
Trailing Slash Redirect
redirecttrailing-slashcanonical
// Set to true to ADD trailing slash, false to REMOVE it
const ADD_SLASH = false;

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    const path = url.pathname;

    // Skip root, files with extensions, and already-correct paths
    if (path === '/') return fetch(request);
    const hasExt = path.includes('.');
    if (hasExt) return fetch(request);

    if (!ADD_SLASH && path.endsWith('/')) {
      url.pathname = path.slice(0, -1);
      return Response.redirect(url.toString(), 301);
    }

    if (ADD_SLASH && !path.endsWith('/')) {
      url.pathname = path + '/';
      return Response.redirect(url.toString(), 301);
    }

    return fetch(request);
  },
};
www to non-www Redirect
redirectwwwdomain
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);

    // Redirect www.example.com -> example.com
    if (url.hostname.startsWith('www.')) {
      url.hostname = url.hostname.slice(4);
      return Response.redirect(url.toString(), 301);
    }

    return fetch(request);
  },
};

Caching

Cache API - Serve from Cache
cachecache-apiperformance
export default {
  async fetch(request, env, ctx) {
    // Only cache GET requests
    if (request.method !== 'GET') return fetch(request);

    const cacheKey = new Request(request.url, request);
    const cache = caches.default;

    // Try cache first
    let response = await cache.match(cacheKey);
    if (response) {
      // Add a header so you can verify cache hit in DevTools
      const hit = new Response(response.body, response);
      hit.headers.set('X-Cache', 'HIT');
      return hit;
    }

    // Cache miss - fetch from origin
    response = await fetch(request);

    // Only cache successful responses
    if (response.ok) {
      const toCache = new Response(response.body, response);
      toCache.headers.set('Cache-Control', 'public, max-age=3600');
      ctx.waitUntil(cache.put(cacheKey, toCache.clone()));
      toCache.headers.set('X-Cache', 'MISS');
      return toCache;
    }

    return response;
  },
};
Set Cache TTL
cachettlcache-control
// Override TTL for different content types
const TTL_MAP = {
  'text/html': 300,           // 5 minutes
  'application/json': 60,     // 1 minute
  'text/css': 86400,          // 1 day
  'application/javascript': 86400,
  'image/': 2592000,          // 30 days (prefix match)
};

export default {
  async fetch(request, env, ctx) {
    const response = await fetch(request);
    if (!response.ok) return response;

    const contentType = response.headers.get('Content-Type') ?? '';
    let ttl = 0;

    for (const [type, seconds] of Object.entries(TTL_MAP)) {
      if (contentType.startsWith(type)) {
        ttl = seconds;
        break;
      }
    }

    const newResponse = new Response(response.body, response);
    if (ttl > 0) {
      newResponse.headers.set('Cache-Control', 'public, max-age=' + ttl);
    }
    return newResponse;
  },
};
Bypass Cache for Logged-in Users
cachecookieauthwordpress
// Cookie name prefixes that indicate a logged-in user
const AUTH_COOKIE_PREFIXES = [
  'wordpress_logged_in',
  'wp-settings',
  'woocommerce_cart_hash',
  'PHPSESSID',
  'laravel_session',
];

function isLoggedIn(cookieHeader) {
  if (!cookieHeader) return false;
  return AUTH_COOKIE_PREFIXES.some((prefix) =>
    cookieHeader.includes(prefix)
  );
}

export default {
  async fetch(request, env, ctx) {
    const cookies = request.headers.get('Cookie') ?? '';

    if (isLoggedIn(cookies)) {
      // Bypass Cloudflare cache for authenticated users
      const bypassRequest = new Request(request, {
        headers: new Headers(request.headers),
      });
      bypassRequest.headers.set('Cache-Control', 'no-cache');
      return fetch(bypassRequest);
    }

    return fetch(request);
  },
};

A/B Testing

50/50 A/B Split
a/b testsplitcookie
const COOKIE_NAME = 'ab_variant';
const VARIANT_A_URL = 'https://example.com/';
const VARIANT_B_URL = 'https://example.com/variant-b/';

function getVariantFromCookie(cookieHeader) {
  if (!cookieHeader) return null;
  const match = cookieHeader.match(new RegExp(COOKIE_NAME + '=([^;]+)'));
  return match ? match[1] : null;
}

export default {
  async fetch(request, env, ctx) {
    const cookies = request.headers.get('Cookie') ?? '';
    let variant = getVariantFromCookie(cookies);
    let isNew = false;

    if (!variant) {
      variant = Math.random() < 0.5 ? 'a' : 'b';
      isNew = true;
    }

    const targetUrl = variant === 'a' ? VARIANT_A_URL : VARIANT_B_URL;
    const originRequest = new Request(targetUrl, request);
    const response = await fetch(originRequest);
    const newResponse = new Response(response.body, response);

    if (isNew) {
      // Sticky for 7 days
      newResponse.headers.set(
        'Set-Cookie',
        COOKIE_NAME + '=' + variant + '; Max-Age=604800; Path=/; SameSite=Lax'
      );
    }

    return newResponse;
  },
};
Cookie-based Variant
a/b testcookievariant
const VARIANTS = {
  control: 'https://example.com/landing-a/',
  treatment: 'https://example.com/landing-b/',
};

export default {
  async fetch(request, env, ctx) {
    const cookieHeader = request.headers.get('Cookie') ?? '';
    const match = cookieHeader.match(/experiment=([^;]+)/);
    const variant = match ? match[1] : null;

    // If the variant cookie exists and maps to a known URL, serve it
    if (variant && VARIANTS[variant]) {
      return fetch(new Request(VARIANTS[variant], request));
    }

    // No cookie - serve control and do not set a new cookie
    // (let your experiment platform assign variants separately)
    return fetch(new Request(VARIANTS.control, request));
  },
};

Utilities

GeoIP Redirect
geocountryredirect
// Map of ISO 3166-1 alpha-2 country codes to redirect URLs
const GEO_REDIRECTS = new Map([
  ['GB', 'https://uk.example.com/'],
  ['DE', 'https://de.example.com/'],
  ['FR', 'https://fr.example.com/'],
  ['AU', 'https://au.example.com/'],
]);

export default {
  async fetch(request, env, ctx) {
    const country = request.cf?.country ?? null;

    if (country && GEO_REDIRECTS.has(country)) {
      const url = new URL(request.url);
      const destination = new URL(GEO_REDIRECTS.get(country));
      // Preserve the path and query string
      destination.pathname = url.pathname;
      destination.search = url.search;
      return Response.redirect(destination.toString(), 302);
    }

    return fetch(request);
  },
};
User-Agent Detect
user-agentmobilebot
const BOT_PATTERN = /bot|crawl|slurp|spider|mediapartners|google|bingbot|facebookexternalhit/i;
const MOBILE_PATTERN = /mobile|android|iphone|ipod|blackberry|windows phone/i;

function classify(ua) {
  if (!ua) return 'unknown';
  if (BOT_PATTERN.test(ua)) return 'bot';
  if (MOBILE_PATTERN.test(ua)) return 'mobile';
  return 'desktop';
}

export default {
  async fetch(request, env, ctx) {
    const ua = request.headers.get('User-Agent') ?? '';
    const deviceType = classify(ua);

    // Example: serve bots a simplified page
    if (deviceType === 'bot') {
      const url = new URL(request.url);
      url.searchParams.set('_lite', '1');
      return fetch(new Request(url.toString(), request));
    }

    // Add device hint header for the origin to use
    const newRequest = new Request(request);
    newRequest.headers.set('X-Device-Type', deviceType);
    return fetch(newRequest);
  },
};
Request Logger
loggingdebugworkers logs
export default {
  async fetch(request, env, ctx) {
    const startTime = Date.now();
    const url = new URL(request.url);

    // Log request metadata before forwarding
    const reqLog = {
      method: request.method,
      path: url.pathname + url.search,
      country: request.cf?.country ?? '-',
      colo: request.cf?.colo ?? '-',
      ip: request.headers.get('CF-Connecting-IP') ?? '-',
      ua: (request.headers.get('User-Agent') ?? '-').slice(0, 80),
    };

    const response = await fetch(request);

    const durationMs = Date.now() - startTime;

    // Logs are visible in Cloudflare dashboard under Workers - Logs
    console.log(JSON.stringify({
      ...reqLog,
      status: response.status,
      durationMs,
      ts: new Date().toISOString(),
    }));

    return response;
  },
};
100% private. All snippets are stored in this page - no code is sent to any server and no data ever leaves your browser.

About this tool

Cloudflare Workers is a serverless execution environment that runs JavaScript (and other languages via WebAssembly) at Cloudflare's global edge network - currently spanning over 300 cities worldwide. When a request hits a Worker, it executes within milliseconds of the visitor because it runs in the same data centre that serves their traffic, not in a remote origin server. This edge computing model means typical Worker response times are in the single-digit milliseconds range, often 10-50x faster than a traditional server-side request that has to travel across the internet.

Workers use the modern ES module syntax shown in all snippets above: export default { async fetch(request, env, ctx) {...} }. The request object is a standard Fetch API Request, env holds bindings to KV stores, Durable Objects, R2 buckets, and secrets you configure in the dashboard, and ctx provides waitUntil() for deferred work like cache writes after the response is sent. This API surface is deliberately minimal and runs in the same V8 isolate model used by Chrome - many Node.js built-ins are not available, but the Web Platform APIs (Fetch, Cache, URL, Headers, TextEncoder, crypto) all are.

When should you choose Workers over Cloudflare Page Rules or Transform Rules? Page Rules and Transform Rules are point-and-click configuration tools suited for simple redirects, cache settings, and header tweaks on a per-URL basis. Workers are the right choice when you need conditional logic, multiple steps, external API calls, or anything that cannot be expressed as a single rule - A/B testing, geo-routing with path rewriting, dynamic JSON responses, rate limiting, or request authentication. For bulk static redirects (thousands of paths), Cloudflare's native Bulk Redirects feature is often simpler than a Worker because it is evaluated before the Worker runs.

On the free plan, Workers receive 100,000 requests per day (across all your Workers) with a CPU time limit of 10ms per invocation. Paid plans start at $5/month for 10 million requests and 30ms CPU time per request. The CPU time limit counts only active execution time - waiting for a fetch() to return does not count. For most use cases like header manipulation, redirects, and lightweight routing, the 10ms limit is more than enough. CPU-intensive work like image processing or complex cryptography typically requires the paid tier or moving that work to an API the Worker calls.

All snippets in this library use the modern ES module format and are ready to paste directly into the Cloudflare Workers dashboard editor or into a src/index.js file in a Wrangler project. Replace the placeholder URLs, cookie names, and constants with your own values, then test using Cloudflare's built-in quick edit preview or wrangler dev locally before deploying.

DiviExtended: premium Divi child themes and plugins