Proxy
Send browser events through your own endpoint, then forward them to server providers.
The Proxy sends browser events through an endpoint you control, then forwards them to your server providers. Because the request goes to your own domain, it bypasses ad-blockers, and your server can enrich or filter events before they reach a vendor.
The Proxy is not an analytics service. It is the transport between client analytics and server analytics: the browser batches events to your API, and your API replays them through whatever server providers you configure.
When to use it
- You want first-party delivery so ad-blockers and tracking-prevention features don’t drop browser events.
- You need to add server-side context (authenticated user, geography, feature flags) before events reach a vendor.
- You use a server provider that needs the incoming request, such as Pirsch, which reads headers to derive page views.
- You want provider API keys to stay on the server instead of shipping in your client bundle.
If none of these apply, send events straight to a client provider — the Proxy adds an extra hop you don’t need.
Installation
The Proxy ships with trakoo. There is no extra package to install. You do install the server providers you forward to (for example posthog-node for PostHog); Pirsch and EmitKit need no additional package.
Client-side usage
Add ProxyProvider to your client analytics and point it at the endpoint that will receive events. Events are buffered and flushed in batches.
import { createClientAnalytics } from 'trakoo/client';
import { ProxyProvider } from 'trakoo/providers/client';
import type { AppEvents } from './events';
export const analytics = createClientAnalytics<AppEvents>({
providers: [
new ProxyProvider({
endpoint: '/api/events',
batch: { size: 10, interval: 5000 }
})
]
});
analytics.track('button_clicked', { buttonId: 'signup-cta' });
Server-side usage
Your endpoint receives the batched events and replays them through server analytics. You have two options.
Let trakoo own the whole route with createProxyHandler:
import { createServerAnalytics } from 'trakoo/server';
import {
EmitKitServerProvider,
createProxyHandler
} from 'trakoo/providers/server';
const serverAnalytics = createServerAnalytics({
providers: [
new EmitKitServerProvider({
apiKey: process.env.EMITKIT_API_KEY!,
channelName: 'product-events'
})
]
});
export const POST = createProxyHandler(serverAnalytics);
Or keep your own handler and call ingestProxyEvents when you need to run auth, enrichment, or logging around ingestion:
import { createServerAnalytics } from 'trakoo/server';
import {
PirschServerProvider,
ingestProxyEvents
} from 'trakoo/providers/server';
const serverAnalytics = createServerAnalytics({
providers: [
new PirschServerProvider({
hostname: 'example.com',
clientSecret: process.env.PIRSCH_SECRET!
})
]
});
export async function POST(req: Request) {
await ingestProxyEvents(req, serverAnalytics);
return new Response('OK');
}
How events flow
Browser → ProxyProvider (batches) → your /api/events → server providers
The browser collects events and flushes a batch once batch.size is reached or batch.interval elapses, whichever comes first. Your endpoint hands the batch to server analytics, which fans it out to each configured server provider — the same routing rules from Providers apply on the server side.
Configuration
ProxyProvider takes the endpoint and an optional batching policy.
endpointstring
URL that receives batched events, usually a route on your own domain.
stringbatch?object
Controls how events are buffered before they are sent.
objectThe batch object accepts:
size?number
Number of events to buffer before flushing a batch.
numberinterval?number
Milliseconds to wait before flushing a partial batch.
number