Proxying Flowsery Analytics with Astro

Route Flowsery Analytics through your Astro application using middleware to prevent adblocker interference and capture more accurate visitor data.

1. Create the Middleware

Create a middleware file at src/middleware.js (or src/middleware.ts for TypeScript projects):

// src/middleware.js
export async function onRequest(context, next) {
  const { request } = context;
  const url = new URL(request.url);

  // Proxy the Flowsery Analytics tracking script
  if (url.pathname === '/js/script.js') {
    const response = await fetch('https://analytics.flowsery.com/js/script.js');
    const script = await response.text();

    return new Response(script, {
      headers: {
        'Content-Type': 'application/javascript',
        'Cache-Control': 'public, max-age=31536000',
      },
    });
  }

  // Proxy the event collection endpoint
  if (url.pathname === '/api/events' && request.method === 'POST') {
    const body = await request.text();

    // Resolve the real visitor IP for accurate geolocation
    const clientIp =
      request.headers.get('x-real-ip') || request.headers.get('x-forwarded-for')?.split(',')[0] || request.headers.get('cf-connecting-ip') || '';

    const response = await fetch('https://analytics.flowsery.com/events', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'User-Agent': request.headers.get('User-Agent') || '',
        Origin: request.headers.get('Origin') || url.origin,
        'x-flowsery-ip': clientIp,
      },
      body: body,
    });

    const responseText = await response.text();

    return new Response(responseText, {
      status: response.status,
      headers: {
        'Content-Type': 'application/json',
      },
    });
  }

  return next();
}

2. Enable Server-Side Rendering in Astro

Update your astro.config.mjs to support SSR (required for middleware):

// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
  output: 'server', // or 'hybrid'
  adapter: node({
    mode: 'standalone',
  }),
});

You will also need the Node.js adapter: npm install @astrojs/node

3. Alternative: Static Site with API Routes

If you prefer keeping your site fully static, create API routes instead of middleware:

Script Proxy Route

Create src/pages/js/script.js.js:

// src/pages/js/script.js.js
export async function GET() {
  const response = await fetch('https://analytics.flowsery.com/js/script.js');
  const script = await response.text();

  return new Response(script, {
    headers: {
      'Content-Type': 'application/javascript',
      'Cache-Control': 'public, max-age=31536000',
    },
  });
}

Events Proxy Route

Create src/pages/api/events.js:

// src/pages/api/events.js
export async function POST({ request }) {
  const body = await request.text();
  const url = new URL(request.url);

  // Resolve the real visitor IP for accurate geolocation
  const clientIp =
    request.headers.get('x-real-ip') || request.headers.get('x-forwarded-for')?.split(',')[0] || request.headers.get('cf-connecting-ip') || '';

  const response = await fetch('https://analytics.flowsery.com/events', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'User-Agent': request.headers.get('User-Agent') || '',
      Origin: request.headers.get('Origin') || url.origin,
      'x-flowsery-ip': clientIp,
    },
    body: body,
  });

  const responseText = await response.text();

  return new Response(responseText, {
    status: response.status,
    headers: {
      'Content-Type': 'application/json',
    },
  });
}

Note: If your project already uses an /api/events route, add data-api to the Flowsery Analytics script tag to redirect events elsewhere. For example, data-api="/flowsery-events" sends data to /flowsery-events instead.

Important: If every visitor appears to be in the same location in your dashboard, confirm that the x-flowsery-ip header is set to the real visitor IP (not the proxy server IP) when forwarding requests to the Flowsery Analytics /events endpoint.

4. Modify the Script Tag

Replace the original Flowsery Analytics snippet in your layout with the proxied version:

---
// src/layouts/Layout.astro
const { title } = Astro.props;
---

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>{title}</title>
    <script
      defer
      data-fl-website-id="flid_******"
      data-domain="your_domain.com"
      src="/js/script.js"
    ></script>
  </head>
  <body>
    <slot />
  </body>
</html>

5. Deploy

After deploying, the proxy configuration takes effect automatically. Verify that your hosting provider supports:

  • Server-side rendering (for the middleware approach)
  • API routes (for the static site approach)

Common Astro-compatible hosts include Vercel, Netlify, and Cloudflare Pages.

Confirming It Works

To validate that the proxy is functioning correctly:

  1. Navigate to your website
  2. Open your browser's developer tools and switch to the Network tab
  3. Verify that analytics requests are served from your domain rather than analytics.flowsery.com

Note: The middleware approach requires server-side rendering, whereas API routes work with both static and server-rendered sites.

Troubleshooting

Every visitor appears from the same location

When all visitors show a single geographic location (typically your server's region), the proxy is not forwarding real visitor IPs correctly.

Resolution:

  1. Ensure your proxy includes the x-flowsery-ip header containing the actual visitor IP address (not the server IP) when forwarding requests to the Flowsery Analytics /events endpoint