# How the Tracking Service Integrates with Supabase for Download Analytics

> Discover how the tracking service integrates with Supabase to power download analytics. Learn about the three-layer architecture and its data flow for component downloads and stats.

- Repository: [Daniel Avila/claude-code-templates](https://github.com/davila7/claude-code-templates)
- Tags: how-to-guide
- Published: 2026-04-26

---

**The tracking service integrates with Supabase through a three-layer architecture where the CLI’s `TrackingService` sends anonymized JSON payloads to a Vercel API endpoint, which validates requests, enriches them with geolocation data, and writes to both `component_downloads` and `download_stats` tables.**

The `davila7/claude-code-templates` repository implements a privacy-respecting download analytics pipeline that tracks component installations without blocking the CLI workflow. Understanding how the tracking service integrates with Supabase reveals a fire-and-forget system designed for minimal latency while maintaining detailed usage statistics and aggregated counters.

## CLI Layer: Building and Sending Payloads

In [`cli-tool/src/tracking-service.js`](https://github.com/davila7/claude-code-templates/blob/main/cli-tool/src/tracking-service.js), the `TrackingService` class manages the client-side logic for capturing download events through three distinct phases.

### Privacy Controls and Opt-Out Handling

The service respects user privacy through the `shouldEnableTracking()` method, which checks for `CCT_NO_TRACKING`, `CCT_NO_ANALYTICS`, or `CI` environment variables. When any are set, tracking disables entirely before any network requests occur.

### Payload Creation and Session Management

The `createTrackingPayload()` method constructs a lightweight JSON object containing:
- Component `type` and `name`
- Generated session ID and timestamp
- Runtime environment information
- Optional metadata object

Component types must belong to the allowed enum: `agent`, `command`, `mcp`, `setting`, `hook`, `template`, or `skill`.

### Fire-and-Forget Transmission

The `sendTrackingData()` method posts to `https://www.aitmpl.com/api/track-download-supabase` with a 5-second abort timeout. The `trackDownload()` wrapper catches all errors silently unless `CCT_DEBUG=true`, ensuring analytics never bubble up to the user or delay installation flows.

```javascript
// cli-tool/src/tracking-service.js
async trackDownload(componentType, componentName, metadata = {}) {
    if (!this.trackingEnabled) return;
    const trackingData = this.createTrackingPayload(componentType, componentName, metadata);
    this.sendTrackingData(trackingData).catch(err => {
        if (process.env.CCT_DEBUG === 'true') console.debug('📊 Tracking info (non‑critical):', err.message);
    });
}

```

## API Layer: Validation and Data Enrichment

The [`api/track-download-supabase.js`](https://github.com/davila7/claude-code-templates/blob/main/api/track-download-supabase.js) endpoint processes incoming requests before database insertion.

### Request Validation and CORS Guards

The endpoint accepts only `POST` requests (with `OPTIONS` pre-flight support). The `validateComponentData()` function verifies that `type` and `name` exist and that `type` matches the allowed component list.

### Client Data Enrichment

Before Supabase insertion, the endpoint enriches payloads with:
- **IP extraction**: `getClientIP()` parses Vercel forwarding headers (`x-forwarded-for`, `x-real-ip`)
- **Geolocation**: `getCountry()` extracts the two-letter country code from `x-vercel-ip-country`
- **User-agent**: Captured directly from request headers

### Supabase Client Initialization

The `getSupabaseClient()` function creates a client using `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` environment variables, throwing immediately if either is missing from the Vercel environment.

## Database Layer: Dual-Table Storage Strategy

The integration implements a write pattern that supports both granular event logging and fast aggregated queries.

### Raw Event Logging

Every validated request inserts a row into `component_downloads` with columns for:
- `component_type`, `component_name`, `component_path`, `category`
- `download_timestamp`, `cli_version`
- `user_agent`, `ip_address`, `country`

### Aggregated Statistics with Upsert Logic

Simultaneously, the endpoint upserts into `download_stats` to maintain counters without duplicate rows:

```javascript
// api/track-download-supabase.js
const { error: upsertError } = await supabase
  .from('download_stats')
  .upsert({
    component_type: type,
    component_name: name,
    total_downloads: 1,
    last_download: new Date().toISOString(),
    updated_at: new Date().toISOString()
  }, {
    onConflict: 'component_type,component_name',
    ignoreDuplicates: false
  });

```

The `onConflict` clause targets the composite unique key `(component_type, component_name)`, incrementing `total_downloads` and refreshing timestamps for existing components.

## Environment Configuration

The integration requires specific environment variables:

**API Layer (Vercel):**
- `SUPABASE_URL`: Project URL
- `SUPABASE_SERVICE_ROLE_KEY`: Service role key for authenticated writes

**CLI Layer (User Machine):**
- `CCT_NO_TRACKING` or `CCT_NO_ANALYTICS`: Disables tracking when set
- `CI`: Automatically disables tracking in continuous integration environments
- `CCT_DEBUG`: Enables console logging for tracking debug information

## Usage Examples

### Tracking a Component Download from Node.js

```javascript
const { trackingService } = require('../cli-tool/src/tracking-service');

// Track installation of the "security-audit" agent
trackingService.trackDownload('agent', 'security-audit', {
  target_directory: '/path/to/project',
  category: 'security'
});

```

### Testing the Endpoint with cURL

```bash
curl -X POST https://www.aitmpl.com/api/track-download-supabase \
  -H "Content-Type: application/json" \
  -d '{
        "type":"agent",
        "name":"test-agent",
        "path":"test/path",
        "category":"testing",
        "cliVersion":"1.20.0"
      }'

```

Both methods result in a detailed row in `component_downloads` and an incremented counter in `download_stats`.

## Summary

- **Three-layer architecture**: CLI service → Vercel API → Supabase database enables separation of concerns between data collection, validation, and storage
- **Privacy-first design**: Automatic opt-out via environment variables and fire-and-forget requests ensure no blocking or data leakage when users disable tracking
- **Dual-table strategy**: `component_downloads` stores granular event data for analysis while `download_stats` provides fast aggregated lookups via upsert operations
- **Zero-impact error handling**: Network failures or Supabase outages are silently caught (or logged only in debug mode) without interrupting the CLI workflow
- **Schema documentation**: Full table definitions and architectural details are documented in [`cli-tool/docs_to_claude/DOWNLOAD_TRACKING.md`](https://github.com/davila7/claude-code-templates/blob/main/cli-tool/docs_to_claude/DOWNLOAD_TRACKING.md)

## Frequently Asked Questions

### How does the tracking service handle user privacy and opt-outs?

The `shouldEnableTracking()` method in [`cli-tool/src/tracking-service.js`](https://github.com/davila7/claude-code-templates/blob/main/cli-tool/src/tracking-service.js) checks for `CCT_NO_TRACKING`, `CCT_NO_ANALYTICS`, or `CI` environment variables. If any are present, the service sets `trackingEnabled` to false and returns immediately from `trackDownload()` without sending network requests, ensuring complete opt-out from analytics collection.

### What component types does the tracking system accept?

According to the `validateComponentData()` function in [`api/track-download-supabase.js`](https://github.com/davila7/claude-code-templates/blob/main/api/track-download-supabase.js), the system validates that `type` belongs to a specific whitelist: `agent`, `command`, `mcp`, `setting`, `hook`, `template`, or `skill`. Requests with invalid types receive validation errors before any database writes occur.

### How does the Supabase integration prevent duplicate download counts?

The `download_stats` table uses an atomic upsert operation with `onConflict: 'component_type,component_name'`. Rather than inserting duplicate rows for every download of the same component, this clause increments the `total_downloads` counter and updates the `last_download` timestamp on the existing row, maintaining accurate aggregated statistics without data duplication.

### What happens if the Supabase write operation fails?

Because the CLI implements a fire-and-forget pattern with `sendTrackingData().catch()`, any network timeouts, validation errors, or Supabase connection issues are caught silently. Errors surface in the console only when the user sets `CCT_DEBUG=true`, ensuring that analytics failures never block or slow down component installations.