Generic Proxy Setup
Framework-agnostic guide to proxy Rybbit tracking through your own domain
This guide covers the core concepts for setting up a Rybbit proxy with any reverse proxy or server framework. If your specific framework has a dedicated guide, we recommend following that instead for optimized instructions.
Prerequisites
Before setting up the proxy, ensure you have:
- A domain or subdomain where you'll serve the proxied scripts (e.g.,
yourdomain.comoranalytics.yourdomain.com) - SSL/TLS certificate for HTTPS (required for modern browsers)
- Server or platform with reverse proxy capabilities
- Your Rybbit instance URL:
- Cloud:
https://app.rybbit.io - Self-hosted: Your Rybbit instance URL (e.g.,
https://analytics.yourcompany.com)
- Cloud:
- Your Rybbit site ID (found in your Rybbit dashboard)
Understanding the Endpoints
Rybbit uses several endpoints for tracking. You can choose between a minimal setup or full proxy:
Required endpoints for basic tracking:
| Endpoint | Method | Purpose | Cache |
|---|---|---|---|
/api/script.js | GET | Main tracking script | 1 hour |
/api/track | POST | Event tracking endpoint | No cache |
This minimal setup enables basic pageview and event tracking, but won't support session replay or some advanced features.
All endpoints for complete functionality:
| Endpoint | Method | Purpose | Cache |
|---|---|---|---|
/api/script.js | GET | Main tracking script (minified) | 1 hour |
/api/replay.js | GET | Session replay recording script | 1 day |
/api/metrics.js | GET | Web Vitals metrics script | 1 day |
/api/track | POST | Event tracking endpoint | No cache |
/api/identify | POST | User identification endpoint | No cache |
/api/session-replay/record/:siteId | POST | Session replay data upload | No cache |
/api/site/tracking-config/:siteId | GET | Site configuration | 5 minutes |
This setup supports all Rybbit features including session replay, Web Vitals, and custom events.
The session replay and metrics scripts (/api/replay.js and /api/metrics.js) are loaded dynamically by the main script when those features are enabled in your site settings. You don't need to include them in your HTML.
Implementation Steps
Configure Your Proxy Rules
Set up your reverse proxy to forward requests from your chosen path (e.g., /analytics/*) to the Rybbit server.
Generic proxy configuration pattern:
Your domain path → Rybbit backend
----------------- ---------------
/analytics/script.js → https://app.rybbit.io/api/script.js
/analytics/track → https://app.rybbit.io/api/track
/analytics/replay.js → https://app.rybbit.io/api/replay.js
... and so onKey requirements:
- Preserve the HTTP method (GET or POST)
- Forward the browser's original request headers — pass through all incoming headers except
Hostand hop-by-hop headers (Connection,Content-Length), rather than hand-picking a few. See Request Header Forwarding for why this matters. - Maintain request/response body for POST requests
- Set appropriate Content-Type headers
- Forward the visitor IP in
X-Forwarded-For - Enable the First-Party Proxy toggle for your site (see below)
Enable First-Party Proxy in Site Settings
In your Rybbit dashboard, open Site Settings → Privacy & Security and enable First-Party Proxy. This tells Rybbit that requests for this site arrive via your proxy, so the visitor IP in X-Forwarded-For is trusted directly instead of being inferred from network topology. Without it, Rybbit may attribute traffic to your proxy server's IP — producing wrong geolocation and merging all visitors into a few users.
Configure Caching (Optional but Recommended)
Implement caching to reduce load on Rybbit servers and improve performance:
Recommended cache durations:
- Scripts (
.jsfiles): 1 hour (3600 seconds)- These change infrequently but may be updated for bug fixes
- Site configuration (
/api/site/tracking-config/*): 5 minutes (300 seconds)- Updated when you change settings in the dashboard
- Tracking endpoints (POST requests): Never cache
- Each request contains unique event data
Example cache headers to set:
Cache-Control: public, max-age=3600 # For scripts
Cache-Control: public, max-age=300 # For config
Cache-Control: no-store # For tracking POSTsUpdate Your Tracking Script
Change your script tag to load from your proxied domain instead of directly from Rybbit:
Before (direct loading):
<script src="https://app.rybbit.io/api/script.js" async data-site-id="YOUR_SITE_ID"></script>After (proxied):
<script src="https://yourdomain.com/analytics/script.js" async data-site-id="YOUR_SITE_ID"></script>How Auto-Discovery Works: The Rybbit script automatically extracts the analytics host from its own src attribute by splitting on /script.js. This means when it loads from https://yourdomain.com/analytics/script.js, it automatically sends all tracking data to https://yourdomain.com/analytics/* endpoints.
Verify the Setup
Test your proxy configuration to ensure everything works correctly:
- Open your website in a browser with Developer Tools open
- Go to the Network tab and filter by "script" or your proxy path
- Verify the script loads:
- You should see a request to
yourdomain.com/analytics/script.js - Status should be
200 OK - Content-Type should be
application/javascript
- You should see a request to
- Verify tracking works:
- Navigate to another page or trigger an event
- You should see POST requests to
yourdomain.com/analytics/track - Check the response is successful (200 OK)
- Check your Rybbit dashboard:
- Wait 1-2 minutes for data to process
- Verify your session appears in real-time dashboard
Configure Security Headers (Optional)
Add security headers to protect your proxy:
Recommended headers:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-originCORS headers (should be preserved from Rybbit):
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-TypeRequest Header Forwarding
Forward the browser's original headers to the Rybbit backend. The simplest and most robust approach is to pass through every incoming request header except Host and hop-by-hop headers (Connection, Content-Length — let your HTTP client recompute those).
Why this matters: Rybbit's bot detection scores requests on headers that every real browser sends. A proxy that forwards only User-Agent and the visitor IP produces requests that look exactly like a script — the events return 200 OK but are classified as bot traffic and never appear in your dashboard.
If you must whitelist headers instead of passing everything through, this is the minimum set:
| Header | Purpose | Required |
|---|---|---|
User-Agent | Device and browser detection | Yes |
X-Forwarded-For | Visitor IP for geolocation and user identification | Yes |
Accept-Language | Language detection, bot filtering | Yes |
Accept | Bot filtering | Yes |
Accept-Encoding | Bot filtering (must include gzip) | Yes |
Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest | Bot filtering (sent by all Chromium browsers) | Yes |
Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform | Browser detection | Recommended |
Referer | Referrer tracking | Recommended |
Content-Type | POST body parsing | Yes (POSTs) |
IP Forwarding: Rybbit uses IP addresses for geolocation (country/city) and creating anonymous user identifiers (hashed IP + User Agent). If you don't forward the visitor IP in X-Forwarded-For, all traffic will appear to come from your proxy server's IP.
Forwarded IP Headers
Set X-Forwarded-For to the original visitor IP before forwarding the request to Rybbit, and enable the First-Party Proxy toggle in your site settings so Rybbit trusts it unconditionally.
Use X-Forwarded-For, not X-Real-IP. On Rybbit Cloud, X-Real-IP is consumed by our edge network (Cloudflare treats it as an internal header) and never reaches the backend — a proxy that relies on it will silently fall back to the wrong IP. X-Forwarded-For passes through intact. Coincidentally, AWS CloudFront also cannot send X-Real-IP (it's on the origin custom-header denylist). Setting X-Real-IP as well does no harm on self-hosted instances, but never make it the only IP header.
Cloudflare Worker example:
const clientIp = request.headers.get('CF-Connecting-IP') || '0.0.0.0';
const proxyHeaders = new Headers(request.headers);
proxyHeaders.set('X-Real-IP', clientIp);
proxyHeaders.set('X-Forwarded-For', clientIp);CloudFront example:
- Set
X-Forwarded-Forto the viewer IP from a CloudFront Function/Lambda@Edge (CloudFront cannot forwardX-Real-IP) - Forward
User-Agent,Referer, andAccept-Language
// CloudFront Function (viewer-request)
function handler(event) {
event.request.headers["x-forwarded-for"] = { value: event.viewer.ip };
return event.request;
}Bandwidth Considerations
Proxying adds bandwidth usage to your infrastructure. Here's what to expect:
Typical bandwidth per session:
- Initial script load: ~18 KB (one-time per session)
- Pageview tracking: ~0.5-2 KB per pageview
- Custom events: ~0.5-3 KB per event
- Session replay: 50-500 KB per session (if enabled, varies by session length)
- Web Vitals: ~1-2 KB per page
Estimated monthly bandwidth for a site with 100,000 monthly sessions:
- Without session replay: ~5-10 GB/month
- With session replay: ~30-80 GB/month
Most modern hosting plans can handle this easily, but verify your bandwidth limits if you have high traffic or session replay enabled.
Performance Optimization
Use a CDN
If your server has CDN capabilities (like Cloudflare, Fastly, or AWS CloudFront), configure it to cache the static scripts:
- Cache scripts at edge locations worldwide
- Reduce latency for global users
- Offload bandwidth from your origin server
Enable Compression
Ensure your proxy enables gzip or brotli compression:
Content-Encoding: gzipThis can reduce script size by 60-70%, improving load times and reducing bandwidth.
Connection Reuse
Configure your proxy to maintain persistent connections to Rybbit's backend to reduce latency on repeated requests.
Common Proxy Patterns
Use a dedicated subdomain for analytics:
https://analytics.yourdomain.com/script.js → https://app.rybbit.io/api/script.js
https://analytics.yourdomain.com/track → https://app.rybbit.io/api/trackPros:
- Clean separation of concerns
- Easy to manage SSL certificate
- Can use separate CDN configuration
Cons:
- Additional DNS lookup (minor performance impact)
- Need to manage subdomain DNS
Use a path on your main domain:
https://yourdomain.com/analytics/script.js → https://app.rybbit.io/api/script.js
https://yourdomain.com/analytics/track → https://app.rybbit.io/api/trackPros:
- No additional DNS lookup
- Single SSL certificate
- Truly first-party from browser perspective
Cons:
- Must ensure proxy path doesn't conflict with your app routes
Security Considerations
Rate Limiting
Consider adding rate limiting to prevent abuse:
- Limit POST requests to tracking endpoints (e.g., 100 requests per minute per IP)
- Whitelist your Rybbit backend IP if possible
- Monitor for unusual traffic patterns
Request Size Limits
Set appropriate request body size limits:
/api/track,/api/identify: 1 MB max/api/session-replay/record/*: 10 MB max (session replay can send large payloads)
HTTPS Only
Always serve your proxy over HTTPS:
- Modern browsers require HTTPS for many features
- Protects user data in transit
- Required for accurate tracking in secure contexts
Troubleshooting
If something isn't working, check:
- Script loads but no events tracked: Verify all tracking endpoints (
/api/track, etc.) are proxied - CORS errors: Ensure CORS headers are preserved from Rybbit backend
- 404 errors: Check that URL paths exactly match expected format
- Incorrect geolocation: Verify
X-Forwarded-Foris set to the visitor IP and the First-Party Proxy toggle is enabled in site settings /trackreturns 200 but nothing appears in the dashboard: Your proxy is probably forwarding too few headers and events are being classified as bot traffic — forward the full browser header set (see Request Header Forwarding)- Session replay not working: Add
/api/replay.jsand/api/session-replay/record/:siteIdendpoints
For more detailed troubleshooting, see our troubleshooting guide.
Next Steps
Now that you understand the generic concepts, choose your specific framework or platform for detailed implementation instructions: