04 · Tracking
Das Skript über deine eigene Domain ausliefern
Zwei Pfade auf deiner Website, an Tally weitergeleitet, sorgen dafür, dass das Skript und seine Events First-Party bleiben.
01Warum selbst ausliefern
Werbeblocker blockieren Analytics anhand der Adresse, von der sie geladen werden. Über deine eigene Domain ausgeliefert, stehen das Skript und seine Events nicht auf ihren Listen. Das Besucher-Cookie hängt nicht davon ab: Das Skript setzt es so oder so auf der Domain deiner Seite.
02Zwei Pfade weiterleiten
| Auf deiner Website | Leitet weiter an |
|---|---|
/js/script.js | https://t.tallybyoutpost.com/script.js |
/api/event | https://t.tallybyoutpost.com/api/event |
Lade das Skript dann von deiner Website. Es sendet Events an /api/event unter seiner eigenen Adresse, sonst ändert sich also nichts:
<script defer data-site="k3xq2mfa7twp" src="/js/script.js"></script>Wenn deine Website schon ein /api/event hat, leite einen anderen Pfad weiter und richte das Skript mit data-api="/your/path" darauf aus.
03Was jeder Proxy tun muss
- Reiche den User-Agent durch: Darüber werden Bots herausgefiltert.
- Leite die IP-Adresse des Besuchers weiter, in
X-Forwarded-For: Sie ermittelt seine Stadt (und zählt ihn auf einer Website ohne Cookies) und wird dann verworfen. Ein Server, der seine Besucher weiterleitet, bekommt das größere Event-Kontingent eines Proxys, damit sie sich nicht das eines einzelnen Browsers teilen. - Leite keine Cookies weiter: Sie werden nicht gelesen.
- Antworte dem Browser ruhig sofort (
202): Das Skript ignoriert jede Antwort.
04Auf deinem Server
// next.config.js
module.exports = {
async rewrites() {
return [
{ source: '/js/script.js', destination: 'https://t.tallybyoutpost.com/script.js' },
{ source: '/api/event', destination: 'https://t.tallybyoutpost.com/api/event' },
];
},
};
Auf Vercel trägt der Rewrite X-Forwarded-For. Eine eigene Route /api/event der App hat Vorrang: Nutze dann einen anderen Pfad und data-api.
{
"rewrites": [
{ "source": "/js/script.js", "destination": "https://t.tallybyoutpost.com/script.js" },
{ "source": "/api/event", "destination": "https://t.tallybyoutpost.com/api/event" }
]
}
vercel.json, für eine Website auf Vercel ohne Next.js.
# netlify.toml
[[redirects]]
from = "/js/script.js"
to = "https://t.tallybyoutpost.com/script.js"
status = 200
force = true
[[redirects]]
from = "/api/event"
to = "https://t.tallybyoutpost.com/api/event"
status = 200
force = true
location = /js/script.js {
proxy_pass https://t.tallybyoutpost.com/script.js;
proxy_set_header Host t.tallybyoutpost.com;
proxy_ssl_server_name on;
}
location = /api/event {
proxy_pass https://t.tallybyoutpost.com/api/event;
proxy_set_header Host t.tallybyoutpost.com;
proxy_ssl_server_name on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie "";
}
yoursite.com {
handle /js/script.js {
rewrite * /script.js
reverse_proxy https://t.tallybyoutpost.com {
header_up Host {upstream_hostport}
}
}
handle /api/event {
reverse_proxy https://t.tallybyoutpost.com {
header_up Host {upstream_hostport}
header_up -Cookie
}
}
# … the site's own handlers
}
Caddy setzt X-Forwarded-For selbst.
// Routed on yoursite.com/js/script.js and yoursite.com/api/event.
const UPSTREAM = {
'/js/script.js': 'https://t.tallybyoutpost.com/script.js',
'/api/event': 'https://t.tallybyoutpost.com/api/event',
};
export default {
async fetch(request) {
const upstream = UPSTREAM[new URL(request.url).pathname];
if (!upstream) return fetch(request);
const headers = new Headers(request.headers);
headers.set('X-Forwarded-For', request.headers.get('CF-Connecting-IP') || '');
headers.delete('Cookie');
return fetch(upstream, { method: request.method, headers, body: request.body });
},
};
// Node 18 or later.
const express = require('express');
const UPSTREAM = 'https://t.tallybyoutpost.com';
const app = express();
app.set('trust proxy', true); // when Express runs behind a proxy, so req.ip is the visitor's
app.get('/js/script.js', async (req, res) => {
const upstream = await fetch(UPSTREAM + '/script.js');
res.set('Content-Type', 'application/javascript; charset=utf-8');
res.set('Cache-Control', upstream.headers.get('cache-control') || 'public, max-age=3600');
res.send(await upstream.text());
});
app.post('/api/event', express.text({ type: '*/*', limit: '8kb' }), (req, res) => {
fetch(UPSTREAM + '/api/event', {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
'User-Agent': req.get('user-agent') || '',
'X-Forwarded-For': req.ip,
},
body: req.body,
}).catch(() => {});
res.status(202).end();
});
05Prüfen, ob es geklappt hat
Fehlt etwas, oder sieht es bei dir anders aus? Schreib an support@tallybyoutpost.com und nenne die Seite.