···6060const CORS_HEADERS = {
6161 "Access-Control-Allow-Origin": "*",
6262 "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
6363- "Access-Control-Allow-Headers": "Content-Type, Authorization",
6363+ "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Client",
6464};
65656666const SLINGSHOT_URL =
···333333 .run();
334334}
335335336336-/** fire-and-forget: increment cumulative hit counter per origin domain */
336336+/** fire-and-forget: increment cumulative hit counter per client identity */
337337async function recordTrafficSource(db: TursoDB, request: Request): Promise<void> {
338338+ const client = request.headers.get("X-Client");
338339 const origin = request.headers.get("Origin");
339339- const domain = origin ? new URL(origin).hostname : "unknown";
340340+ const domain = client || (origin ? new URL(origin).hostname : "unknown");
340341 await db.prepare(
341342 `INSERT INTO traffic_sources (domain, hits)
342343 VALUES (?1, 1)
···14481449 <p>
14491450 extracting the base URL into a constant (or env var) makes it easy to switch back
14501451 if you ever need to.
14521452+ </p>
14531453+14541454+ <h2>identify your app</h2>
14551455+ <p>
14561456+ set the <code>X-Client</code> header so your app shows up by name in our
14571457+ <a href="/stats">traffic stats</a> instead of as "unknown":
14581458+ </p>
14591459+ <pre><code>const response = await fetch(
14601460+ \`\${TYPEAHEAD_URL}/xrpc/app.bsky.actor.searchActorsTypeahead?q=\${encodeURIComponent(query)}&limit=10\`,
14611461+ { headers: { 'X-Client': 'my-app.example.com' } }
14621462+);</code></pre>
14631463+ <p>
14641464+ use your domain or app name — whatever you want to be identified as.
14651465+ browser-based apps will also be identified automatically via the <code>Origin</code> header,
14661466+ but <code>X-Client</code> is preferred since it works everywhere (server-side, CLI, native apps).
14511467 </p>
1452146814531469 <h2>response comparison</h2>