Skip to main content

Overview

Beyond basic installation, the Tinybird tracker offers advanced configuration options for proxying, storage, multi-tenancy, and custom attributes.

Proxy Configuration

Route tracking requests through your own domain for improved privacy and ad-blocker bypass.

Why Use a Proxy?

Privacy Compliance

Keep analytics data within your domain for GDPR and privacy regulations

Ad-Blocker Bypass

Reduce tracking blocked by ad-blockers that target third-party analytics domains

First-Party Cookies

Extend cookie lifetime with first-party domain cookies

Control

Full control over the tracking endpoint and middleware

Simple Proxy

Use data-proxy to specify your domain. The tracker appends /api/tracking automatically:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-proxy="https://yourdomain.com"
></script>
Requests will be sent to: https://yourdomain.com/api/tracking

Custom Proxy URL

Use data-proxy-url for full control over the endpoint:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-proxy-url="https://yourdomain.com/custom/tracking/endpoint"
></script>
Cannot use both: data-proxy and data-proxy-url are mutually exclusive. The script will throw an error if both are present.

Implementation

From the source code (middleware/src/index.js:23-27):
// Check if both proxy and proxyUrl are specified
if (proxy && proxyUrl) {
  console.error('Error: Both data-proxy and data-proxy-url are specified. Please use only one of them.')
  throw new Error('Both data-proxy and data-proxy-url are specified. Please use only one of them.')
}

Proxy Middleware

Implement a proxy endpoint that forwards requests to Tinybird. Example from middleware/api/tracking.js:
import fetch from 'node-fetch';

export const config = {
    runtime: 'experimental-edge',
};

const DATASOURCE = 'analytics_events';

const _postEvent = async event => {
    const options = {
        method: 'post',
        body: event,
        headers: {
            'Authorization': `Bearer ${process.env.TINYBIRD_TOKEN}`,
            'Content-Type': 'application/json'
        }
    };
    const response = await fetch(
      `https://api.tinybird.co/v0/events?name=${DATASOURCE}`, 
      options
    );
    if (!response.ok) {
        throw response.statusText;
    }
    return response.json();
};

export default async (req) => {
    await _postEvent(req.body);
    return new Response('ok', {
        headers: {
            'access-control-allow-credentials': true,
            'access-control-allow-origin': process.env.CORS_ALLOW_ORIGIN || '*',
            'access-control-allow-methods': 'OPTIONS,POST',
            'access-control-allow-headers': 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version',
            'content-type': 'text/html'
        },
    });
};
Deploy the middleware as a Vercel Edge Function:
// api/tracking.js
export const config = {
  runtime: 'edge',
};

export default async function handler(req) {
  const response = await fetch(
    `https://api.tinybird.co/v0/events?name=analytics_events`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.TINYBIRD_TOKEN}`,
        'Content-Type': 'application/json'
      },
      body: req.body
    }
  );
  return new Response('ok', { status: 200 });
}

Storage Configuration

Control how session IDs are stored in the browser.

Storage Methods

Stores session ID in a cookie with 30-minute expiration.Pros: Works across tabs and windowsCons: Subject to cookie policies and browser restrictions
localStorage
Stores session ID in localStorage with 30-minute expiration.Pros: Not affected by cookie policies, larger storage limitCons: Same-origin only, not accessible from server
sessionStorage
Stores session ID in sessionStorage with 30-minute expiration.Pros: Automatically clears when tab closesCons: Not shared across tabs

Usage

<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-storage="cookie"
></script>

Implementation Details

From the source code (middleware/src/index.js:70-148):
function _getSessionId() {
  if (
    [storageMethods.localStorage, storageMethods.sessionStorage].includes(
      STORAGE_METHOD
    )
  ) {
    const storage =
      STORAGE_METHOD === storageMethods.localStorage
        ? localStorage
        : sessionStorage
    const serializedItem = storage.getItem(STORAGE_KEY)

    if (!serializedItem) {
      return null
    }

    let item = null;

    try {
      item = JSON.parse(serializedItem)
    } catch (error) {
      return null
    }

    if (typeof item !== 'object' || item === null) {
      return null
    }

    const now = new Date()

    if (now.getTime() > item.expiry) {
      storage.removeItem(STORAGE_KEY)
      return null
    }

    return item.value
  }

  return _getSessionIdFromCookie()
}

Global Attributes

Add custom attributes that are included in every event.

Syntax

Use the data-tb-* prefix on the script tag:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-tb-app-version="2.1.0"
  data-tb-environment="production"
  data-tb-user-segment="premium"
  data-tb-feature-flags="new-checkout,dark-mode"
></script>

Result

These attributes are merged into every event payload:
{
  "action": "page_hit",
  "payload": {
    "user-agent": "Mozilla/5.0...",
    "pathname": "/products",
    "app_version": "2.1.0",
    "environment": "production",
    "user_segment": "premium",
    "feature_flags": "new-checkout,dark-mode"
  }
}
Hyphens in attribute names are automatically converted to underscores.

Implementation

From the source code (middleware/src/index.js:33-40):
let globalAttributes = {}

for (const attr of document.currentScript.attributes) {
  if (attr.name.startsWith('tb_')) {
    globalAttributes[attr.name.slice(3).replace(/-/g, '_')] = attr.value
  }
  if (attr.name.startsWith('data-tb-')) {
    globalAttributes[attr.name.slice(8).replace(/-/g, '_')] = attr.value
  }
}

Use Cases

Track which variant users are seeing:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-tb-ab-test="checkout-v2"
  data-tb-variant="treatment"
></script>
Distinguish between environments:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-tb-environment="staging"
  data-tb-build="build-1234"
></script>
Track user segments or plans:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-tb-plan="enterprise"
  data-tb-account-type="business"
></script>
Track enabled features:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-tb-features="dark-mode,new-nav,ai-chat"
></script>

Multi-Tenancy

Support multiple tenants or domains in a single data source.

Configuration

<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-domain="acme.com"
  data-tenant-id="tenant-123"
></script>

Data Structure

Tenant and domain are included at the top level:
{
  "timestamp": "2024-03-11T14:23:45.123Z",
  "action": "page_hit",
  "tenant_id": "tenant-123",
  "domain": "acme.com",
  "payload": { ... }
}

JWT Token Filtering

Filter endpoints by tenant using JWT tokens with fixed params:
{
  "exp": 1735689600,
  "iat": 1704067200,
  "token": "dashboard_token",
  "fixed_params": {
    "tenant_id": "tenant-123"
  }
}
Learn more: JWT Tokens in Tinybird

Use Cases

Track analytics for multiple customers:
// Dynamically set tenant ID
const tenantId = getCurrentTenantId();

const script = document.createElement('script');
script.src = 'https://unpkg.com/@tinybirdco/flock.js';
script.setAttribute('data-token', 'YOUR_TOKEN');
script.setAttribute('data-tenant-id', tenantId);
document.head.appendChild(script);

Custom Data Source

Override the default analytics_events data source:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-datasource="custom_analytics"
></script>
Useful when you’ve customized the landing data source or want to send events to multiple data sources.

Regional Endpoints

Specify your Tinybird region:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-host="https://api.us-east.tinybird.co"
></script>

Payload Stringification

Control whether payloads are stringified:
<script
  src="https://unpkg.com/@tinybirdco/flock.js"
  data-token="YOUR_TOKEN"
  data-stringify-payload="false"
></script>
{
  "payload": "{\"pathname\":\"/home\",\"locale\":\"en-US\"}"
}
Payload is stored as a JSON string.
Ensure your data source schema matches your chosen format.

Complete Configuration Example

Here’s a full example using many configuration options:
<!DOCTYPE html>
<html>
  <head>
    <title>Enterprise Analytics</title>
    
    <!-- Tinybird Analytics - Full Configuration -->
    <script
      defer
      src="https://unpkg.com/@tinybirdco/flock.js"
      data-token="p.eyJ1IjogImFiY2QxMjM0In0..."
      data-host="https://api.us-east.tinybird.co"
      data-proxy="https://analytics.mycompany.com"
      data-datasource="company_analytics"
      data-domain="mycompany.com"
      data-tenant-id="tenant-enterprise-001"
      data-storage="localStorage"
      web-vitals="true"
      data-tb-app-version="3.2.1"
      data-tb-environment="production"
      data-tb-plan="enterprise"
      data-tb-region="us-east"
      data-tb-ab-test="new-dashboard"
      data-tb-variant="treatment"
    ></script>
  </head>
  <body>
    <h1>My Application</h1>
  </body>
</html>

Security Considerations

  • Use tracker tokens, not admin tokens
  • Tracker tokens should only have write access to the data source
  • Rotate tokens periodically
  • Consider using proxy to hide tokens from client
When using a proxy, configure CORS properly:
return new Response('ok', {
  headers: {
    'access-control-allow-origin': 'https://yourdomain.com',
    'access-control-allow-methods': 'POST',
    'access-control-allow-headers': 'Content-Type',
  },
});
  • Never track passwords or credit card numbers
  • Automatic PII masking is a safeguard, not a replacement for proper data handling
  • Review tracked data regularly
  • Implement data retention policies

Troubleshooting

Check:
  1. Browser console for errors
  2. Network tab for failed requests
  3. Token permissions
  4. CORS configuration (if using proxy)
  5. Data source name spelling
Check:
  1. Proxy endpoint is accessible
  2. CORS headers are set correctly
  3. Environment variables are set
  4. Request is being forwarded to Tinybird
  5. Response status codes
Check:
  1. Storage method is supported in browser
  2. Cookies are not being blocked
  3. localStorage is not full
  4. Domain is set correctly (for cookies)

Next Steps

Page Views

Learn about automatic page tracking

Custom Events

Track custom user interactions

Build docs developers (and LLMs) love