Astro proxy
Proxy attribu.tech analytics through your Astro application using middleware.
See Proxy the tracking script for an overview of why and how proxying works.
Step 1: Create middleware
Create src/middleware.js (or .ts) to intercept requests and proxy them to attribu.tech:
export async function onRequest({ request, url }, next) {
// Proxy the tracking script
if (url.pathname === "/js/script.js" && request.method === "GET") {
const res = await fetch("https://attribu.tech/js/script.js");
return new Response(res.body, {
status: res.status,
headers: {
"Content-Type": "application/javascript",
"Cache-Control": "public, max-age=3600",
},
});
}
// Proxy the event API
if (url.pathname === "/api/proxy/events" && request.method === "POST") {
const body = await request.text();
const res = await fetch("https://attribu.tech/api/events", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Forwarded-For":
request.headers.get("x-forwarded-for") ||
request.headers.get("cf-connecting-ip") ||
"",
},
body,
});
return new Response(res.body, {
status: res.status,
headers: { "Content-Type": "application/json" },
});
}
return next();
}Step 2: Configure Astro for server output
Middleware requires server-side rendering. Update astro.config.mjs:
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
export default defineConfig({
output: "server",
adapter: node({
mode: "standalone",
}),
});Install the Node adapter if you haven't already:
npx astro add nodeAlternative: Static site with API routes
If you prefer a static Astro site with output: "hybrid", you can use API routes instead of middleware. Create these two files:
src/pages/js/script.js.js:
export async function GET() {
const res = await fetch("https://attribu.tech/js/script.js");
return new Response(res.body, {
status: res.status,
headers: {
"Content-Type": "application/javascript",
"Cache-Control": "public, max-age=3600",
},
});
}
export const prerender = false;src/pages/api/proxy/events.js:
export async function POST({ request }) {
const body = await request.text();
const res = await fetch("https://attribu.tech/api/events", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Forwarded-For":
request.headers.get("x-forwarded-for") ||
request.headers.get("cf-connecting-ip") ||
"",
},
body,
});
return new Response(res.body, {
status: res.status,
headers: { "Content-Type": "application/json" },
});
}
export const prerender = false;Step 3: Update your script tag
Point the script src to your proxied path and set data-api-url to your proxied API endpoint:
<script
defer
data-website-id="YOUR_SITE_ID"
data-domain="yourdomain.com"
data-api-url="/api/proxy/events"
src="/js/script.js"
></script>Replace
YOUR_SITE_ID with your actual Website ID from attribu.tech. Replace yourdomain.com with your website's root domain.Verify installation
- Visit your site in an incognito/private window.
- Open your browser's Developer Tools and go to the Network tab.
- Confirm the script loads from
/js/script.json your domain. - Confirm the pageview POST goes to
/api/proxy/eventson your domain. - Check your attribu.tech dashboard. A new pageview should appear within a few seconds.
Troubleshooting
- All visitors show the same location - Make sure your middleware or API route forwards the visitor's IP via
X-Forwarded-For. If deployed behind Cloudflare, usecf-connecting-ip. - Middleware not running - Confirm your Astro config uses
output: "server"oroutput: "hybrid". Static builds do not execute middleware. - API routes returning 404 - Ensure each API route file exports
prerender = falseso Astro handles them at runtime.
What's next
- Back to proxy overview
- Nginx proxy setup
- Connect Stripe to attribute revenue to traffic sources.