Skip to content

App Attribution

Attribute your API usage to your app with HTTP-Referer and X-AnyRouter headers and appear in public rankings and analytics.

By default your API traffic is anonymous — AnyRouter can't tell which of your apps made which call, and none of it surfaces publicly. App attribution ties each request to the app that made it, so your app earns a spot in AnyRouter's public rankings and model leaderboards, and you get per-app usage analytics. It's driven by one header you probably already send — HTTP-Referer — plus optional X-AnyRouter-* headers for display metadata and marketplace categories.

Overview

Send HTTP-Referer on your requests and AnyRouter creates an app page keyed to your origin. Add the optional headers to control the display name, platform, version, and marketplace categories.

When your app is attributed:

  • Public app rankings — your app appears on the rankings page with daily, weekly, and monthly views, sorted by total token consumption.
  • Model leaderboards — your app shows up in the "Apps" tab on individual model pages.
  • Per-app analytics — model-usage breakdowns, token consumption, and adoption metrics scoped to your app.
  • Marketplace visibility — categorized apps surface in topic pages for discovery.

HTTP-Referer is required. Without it, no app page is created and your usage never appears in any leaderboard.

How it works

The HTTP-Referer identifier

HTTP-Referer identifies your app's URL and is the primary identifier for rankings. Your normalized Referer URL becomes the app's unique identifier:

  • The host is lowercased and the path is dropped — https://myapp.com/playground and https://myapp.com/docs attribute to the same app https://myapp.com.
  • The scheme is preserved — https://myapp.com and http://myapp.com are different apps.
  • The port is preserved when non-default — https://myapp.com:8443 is a distinct app.

Localhost / loopback URLs. Apps on localhost, 127.0.0.1, ::1, or any *.localhost host must also send X-AnyRouter-Title to be tracked — otherwise different developers on the same local port would collapse into one shared app. With a title, the local app is registered under local://<title-slug>.

Optional headers

HeaderPurpose
X-AnyRouter-TitleSets your app's display name in rankings and analytics. Without it, your Referer host is used.
X-TitleThe OpenRouter display-name header, read as a fallback for X-AnyRouter-Title so apps migrating from OpenRouter keep attribution with no changes. If both are sent, X-AnyRouter-Title wins.
X-AnyRouter-SourceFree-form platform/channel id (web-app, desktop, vscode-extension). Used for filtering in the dashboard. Not part of the dedup key. Spelling doesn't matter — Claude Code, claude-code and claude_code are recorded as the same app.
X-AnyRouter-AppAlias for X-AnyRouter-Source, for tools that already send this name. X-AnyRouter-Source wins when both are present.
X-AnyRouter-VersionYour app's version string, for comparing usage across releases. Semver (1.2.3) recommended.
X-AnyRouter-CategoriesComma-separated marketplace categories — up to 2 per request. Lowercase, hyphen-separated, each ≤30 chars. Unrecognized values are silently ignored.

Categories are merged with whatever your app has accumulated across requests, capped at 10 total. You don't need to resend the full list each time — one or two new categories on a single request is enough to add them.

Category catalog

GroupCategoryFor
Codingcli-agentTerminal-based coding assistants
ide-extensionEditor / IDE integrations
cloud-agentCloud-hosted coding agents
programming-appProgramming apps
native-app-builderMobile and desktop app builders
Creativecreative-writingCreative writing tools
video-genVideo generation apps
image-genImage generation apps
Productivitywriting-assistantAI-powered writing tools
general-chatGeneral chat apps
personal-agentPersonal AI agents
EntertainmentroleplayRoleplay apps and character chat
gameGaming and interactive entertainment

Only recognized categories are accepted; unrecognized values are silently dropped. If your app doesn't fit, email support@anyrouter.dev and we'll evaluate adding it.

Configure

Add the attribution headers to your existing request. HTTP-Referer is required; the rest are optional display metadata.

// TypeScript / JavaScript
fetch('https://anyrouter.dev/api/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk-ar-your-key',
    'Content-Type': 'application/json',
    // Required for attribution
    'HTTP-Referer': 'https://myapp.com',
    // Optional display metadata
    'X-AnyRouter-Title': 'My AI Assistant',
    'X-AnyRouter-Source': 'web-app',
    'X-AnyRouter-Version': '1.0.0',
    'X-AnyRouter-Categories': 'general-chat,personal-agent',
  },
  body: JSON.stringify({
    model: 'google/gemma-4-26b-a4b-it',
    messages: [{ role: 'user', content: 'Hello, world!' }],
  }),
});
# Python
import requests

response = requests.post(
    url='https://anyrouter.dev/api/v1/chat/completions',
    headers={
        'Authorization': 'Bearer sk-ar-your-key',
        'Content-Type': 'application/json',
        # Required for attribution
        'HTTP-Referer': 'https://myapp.com',
        # Optional display metadata
        'X-AnyRouter-Title': 'My AI Assistant',
        'X-AnyRouter-Source': 'web-app',
        'X-AnyRouter-Version': '1.0.0',
        'X-AnyRouter-Categories': 'general-chat,personal-agent',
    },
    json={
        'model': 'google/gemma-4-26b-a4b-it',
        'messages': [{'role': 'user', 'content': 'Hello, world!'}],
    },
)
# cURL
curl https://anyrouter.dev/api/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-ar-your-key" \
  -H "HTTP-Referer: https://myapp.com" \
  -H "X-AnyRouter-Title: My AI Assistant" \
  -H "X-AnyRouter-Source: web-app" \
  -H "X-AnyRouter-Version: 1.0.0" \
  -H "X-AnyRouter-Categories: general-chat,personal-agent" \
  -d '{
    "model": "google/gemma-4-26b-a4b-it",
    "messages": [
      { "role": "user", "content": "Hello, world!" }
    ]
  }'

Best practices

  • Always send HTTP-Referer — without it the request is unattributed and your app is invisible to rankings.
  • Pin the Referer to your canonical origin (https://yourapp.com), not a deep page URL — paths are dropped anyway, but a stable origin makes attribution predictable.
  • Send X-AnyRouter-Title for a friendly display name; otherwise the host is shown.
  • Send X-AnyRouter-Categories to surface in marketplace topic pages.
  • For local development, include X-AnyRouter-Title so your loopback app doesn't collide with other developers'.
  • Use semver for versions — useful for comparing rollouts.

Frequently asked questions

Where does my app appear once attributed?

On the main rankings page (daily/weekly/monthly, sorted by token consumption) and in the "Apps" tab of each model page it uses.

My app was logged under two Referer URLs — can I merge them?

Yes. If you migrated (e.g. myapp.com → myapp.io), email support@anyrouter.dev with both URLs and we'll merge them into one canonical record. The same address handles splitting an entry if you need the inverse.

Is any of my request data exposed by attribution?

No. Attribution headers carry identity only — they don't expose anything about your request payloads. Your app's Referer, title, and chosen categories are publicly visible in rankings; the prompts and completions are not.