> ## Documentation Index
> Fetch the complete documentation index at: https://docs.glood.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Event System

> Complete guide to event tracking, pixel transmission, and analytics integration

# Event System

The Glood SDK's event system automatically transforms Shopify Analytics events into Glood pixel data and transmits them to configured endpoints with full privacy compliance.

## Architecture Overview

The event system follows this flow:

```mermaid theme={null}
graph TD
    A[Shopify Analytics] --> B[GloodProvider]
    B --> C[Event Distribution]
    C --> D[Event Transformation]
    D --> E[Consent Check]
    E --> F[Pixel Queue]
    F --> G[HTTP Transmission]
    G --> H[Glood Endpoints]
```

### Components

1. **Event Subscription** - Automatically subscribes to Shopify Analytics events
2. **Event Distribution** - Routes events to interested apps
3. **Data Transformation** - Converts Shopify data to Glood pixel format
4. **Consent Checking** - Verifies customer privacy permissions
5. **Pixel Queue** - Manages immediate transmission with retry logic
6. **Error Handling** - Comprehensive error handling and logging

## Event Types

The SDK tracks these Shopify Analytics events:

### Core Events

| Event Type          | Description          | Triggered When                   |
| ------------------- | -------------------- | -------------------------------- |
| `page_viewed`       | Page navigation      | User visits any page             |
| `product_viewed`    | Product page view    | User views product details       |
| `collection_viewed` | Collection page view | User browses product collections |
| `cart_viewed`       | Shopping cart view   | User opens shopping cart         |
| `search_submitted`  | Search query         | User performs search             |

### Commerce Events

| Event Type                  | Description      | Triggered When                 |
| --------------------------- | ---------------- | ------------------------------ |
| `product_added_to_cart`     | Add to cart      | User adds product to cart      |
| `product_removed_from_cart` | Remove from cart | User removes product from cart |
| `custom_promotion_viewed`   | Promotion view   | User sees promotional content  |

## Event Transformation

The SDK transforms Shopify Analytics events into Glood pixel format using sophisticated data transformation:

### Shopify → Glood Transformation

```typescript theme={null}
// Shopify Analytics Event
{
  eventType: 'product_viewed',
  products: [{
    id: 'gid://shopify/Product/123',
    title: 'Cool T-Shirt',
    price: '29.99',
    variantId: 'gid://shopify/ProductVariant/456',
    // ... other Shopify data
  }],
  shop: { currency: 'USD' },
  // ... other event data
}

// Transformed to Glood Pixel
{
  event: {
    id: 'evt_abc123',
    name: 'product_viewed',
    type: 'standard',
    timestamp: '2024-03-15T10:30:00.000Z',
    clientId: 'client_xyz789',
    context: {
      page: { url: '/products/cool-t-shirt', title: 'Cool T-Shirt' },
      userAgent: 'Mozilla/5.0...',
      screen: { width: 1920, height: 1080 }
    },
    data: {
      productVariant: {
        id: '456',
        title: 'Cool T-Shirt',
        price: { amount: 29.99, currencyCode: 'USD' },
        product: {
          id: '123',
          title: 'Cool T-Shirt',
          url: '/products/cool-t-shirt'
        }
      }
    }
  },
  rkUid: 'rk_user_id',
  data: {
    customer: null,
    cart: null,
    shop: {
      name: 'My Store',
      myshopifyDomain: 'my-store.myshopify.com',
      paymentSettings: { currencyCode: 'USD' }
    }
  },
  customerPrivacy: {
    analyticsProcessingAllowed: true,
    marketingAllowed: true,
    preferencesProcessingAllowed: true,
    saleOfDataAllowed: false
  },
  sessionId: 'session_def456',
  cartIdentifier: null
}
```

### Event-Specific Transformations

#### Product Viewed

```typescript theme={null}
// Extracted product data
data: {
  productVariant: {
    id: '456',
    title: 'Cool T-Shirt - Blue',
    price: { amount: 29.99, currencyCode: 'USD' },
    product: {
      id: '123',
      title: 'Cool T-Shirt',
      vendor: 'Fashion Brand',
      url: '/products/cool-t-shirt',
      type: 'Apparel'
    },
    sku: 'TSH-BLUE-M',
    image: { src: 'https://example.com/image.jpg' }
  }
}
```

#### Search Submitted

```typescript theme={null}
// Search query and results
data: {
  searchResult: {
    query: 'blue shirt',
    productVariants: [
      {
        id: '456',
        title: 'Blue Cotton Shirt',
        price: { amount: 39.99, currencyCode: 'USD' },
        product: {
          id: '123',
          title: 'Cotton Shirt',
          url: '/products/cotton-shirt'
        }
      }
      // ... more search results
    ]
  }
}
```

#### Cart Viewed

```typescript theme={null}
// Complete cart contents
data: {
  cart: {
    id: 'cart_123',
    cost: {
      totalAmount: { amount: 89.97, currencyCode: 'USD' }
    },
    lines: [
      {
        cost: { totalAmount: { amount: 29.99, currencyCode: 'USD' } },
        merchandise: {
          id: '456',
          title: 'Cool T-Shirt - Blue',
          price: { amount: 29.99, currencyCode: 'USD' },
          product: {
            id: '123',
            title: 'Cool T-Shirt',
            url: '/products/cool-t-shirt'
          }
        },
        quantity: 1
      }
      // ... more cart lines
    ],
    totalQuantity: 3
  }
}
```

## Pixel Transmission

### Immediate Transmission

The SDK uses immediate pixel transmission with retry logic:

```typescript theme={null}
class PixelQueue {
  add(item: PixelEvent): void {
    // Send event immediately
    this.sendEventWithRetry(item.endpoint, item.data, 0);
  }

  private async sendEventWithRetry(
    endpoint: string,
    event: Record<string, any>,
    retryCount: number
  ): Promise<void> {
    try {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(event),
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
    } catch (error) {
      // Retry with exponential backoff
      if (retryCount < this.retryDelays.length) {
        setTimeout(() => {
          this.sendEventWithRetry(endpoint, event, retryCount + 1);
        }, this.retryDelays[retryCount]);
      }
    }
  }
}
```

### Retry Strategy

* **Retry Delays**: `[1000, 2000, 4000, 8000]` milliseconds
* **Max Retries**: 4 attempts total (initial + 3 retries)
* **Backoff**: Exponential backoff strategy
* **Error Logging**: Comprehensive error logging with debug details

### Network Resilience

```typescript theme={null}
// Automatic retry on network failures
const retryDelays = [1000, 2000, 4000, 8000]; // 1s, 2s, 4s, 8s

// Error scenarios handled:
// - Network timeouts
// - HTTP 5xx server errors
// - HTTP 4xx client errors (logged but not retried)
// - JSON serialization errors
// - CORS issues
```

## Consent Management

### Automatic Consent Checking

The SDK automatically checks customer consent before sending pixels:

```typescript theme={null}
function checkConsent(
  requiredConsents: ConsentType[],
  canTrack: any,
  analytics: any
): boolean {
  if (!requiredConsents || requiredConsents.length === 0) {
    return true; // No consent required
  }

  return requiredConsents.every(consentType => {
    switch (consentType) {
      case 'analytics':
        return analytics.customerPrivacy?.analyticsProcessingAllowed();
      case 'marketing':
        return analytics.customerPrivacy?.marketingAllowed();
      case 'preferences':
        return analytics.customerPrivacy?.preferencesProcessingAllowed();
      case 'sale_of_data':
        return analytics.customerPrivacy?.saleOfDataAllowed();
      default:
        return false;
    }
  });
}
```

### Consent Requirements by App

| App                 | Default Consent Requirements   | Description                                            |
| ------------------- | ------------------------------ | ------------------------------------------------------ |
| **Recommendations** | `['analytics', 'marketing']`   | Analytics for tracking + marketing for personalization |
| **Search**          | `['analytics']`                | Only analytics for search improvement                  |
| **Wishlist**        | `['analytics', 'preferences']` | Analytics + preferences for wishlist personalization   |

### Privacy Scenarios

```typescript theme={null}
// Example consent scenarios
const consentScenarios = {
  noConsent: {
    analyticsProcessingAllowed: false,
    marketingAllowed: false,
    preferencesProcessingAllowed: false,
    saleOfDataAllowed: false,
  },
  analyticsOnly: {
    analyticsProcessingAllowed: true,
    marketingAllowed: false,
    preferencesProcessingAllowed: false,
    saleOfDataAllowed: false,
  },
  fullConsent: {
    analyticsProcessingAllowed: true,
    marketingAllowed: true,
    preferencesProcessingAllowed: true,
    saleOfDataAllowed: true,
  },
};

// Results for each app:
// Recommendations: noConsent ❌, analyticsOnly ❌, fullConsent ✅
// Search:          noConsent ❌, analyticsOnly ✅, fullConsent ✅
// Wishlist:        noConsent ❌, analyticsOnly ❌, fullConsent ✅
```

## Session & Identity Management

### Client ID Generation

```typescript theme={null}
class CookieStorage {
  static getOrGenerateClientId(): string {
    const existingId = this.getCookie('glood_client_id');
    if (existingId) return existingId;

    const newId = `client_${this.generateRandomId()}`;
    this.setCookie('glood_client_id', newId, 365); // 1 year
    return newId;
  }
}
```

### Session Management

```typescript theme={null}
// Session ID (browser session)
static getOrGenerateSessionId(): string {
  const existingId = sessionStorage.getItem('glood_session_id');
  if (existingId) return existingId;

  const newId = `session_${this.generateRandomId()}`;
  sessionStorage.setItem('glood_session_id', newId);
  return newId;
}

// RK UID (analytics user ID)
static getOrGenerateRkUid(analytics: any): string {
  // Try to get from analytics first
  const analyticsId = analytics?.customerId || analytics?.customData?.userId;
  if (analyticsId) return analyticsId;

  // Fallback to cookie-based ID
  return this.getOrGenerateClientId();
}
```

### Browser Context

```typescript theme={null}
const browserContext = {
  getContext(): BrowserContext {
    return {
      page: {
        url: window.location.href,
        title: document.title,
        referrer: document.referrer,
      },
      userAgent: navigator.userAgent,
      screen: {
        width: screen.width,
        height: screen.height,
      },
      language: navigator.language,
      timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    };
  }
};
```

## Debug Logging

### Debug Mode Events

Enable debug mode to see detailed event flow:

```typescript theme={null}
const glood = createGlood({
  apiKey: process.env.GLOOD_API_KEY!,
  myShopifyDomain: 'your-store.myshopify.com',
  debug: true, // Enable debug logging
});
```

### Debug Log Examples

```
[Glood Debug] Setting up event subscriptions for apps: ['recommendations', 'search']
[Glood Debug] App recommendations subscribes to events: ['page_viewed', 'product_viewed', ...]
[Glood Debug] All unique event types: ['page_viewed', 'product_viewed', 'search_submitted']
[Glood Debug] Setting up centralized subscription for product_viewed
[Glood Debug] Received product_viewed event, distributing to interested apps
[Glood Debug] Apps interested in product_viewed: ['recommendations']
[Glood Debug] Processing product_viewed event for recommendations: { products: [...] }
[Glood Debug] Consent granted for recommendations, processing event
[Glood Debug] recommendations app sending pixel: { event: { ... } }
[Glood Debug] Sending pixel event immediately: { endpoint: 'https://events.glood.ai', data: {...} }
[Glood Debug] Sending event to https://events.glood.ai (attempt 1): { event: {...} }
[Glood Debug] Successfully sent event to https://events.glood.ai
```

### Error Debug Logs

```
[Glood Debug] Consent not granted for recommendations, skipping event
[Glood Debug] Retrying event in 2000ms (attempt 2)
[Glood Debug] Failed event: { event: {...} }
[Glood] Failed to send pixel event after all retries: NetworkError
```

## Performance Considerations

### Event Deduplication

Events are subscribed to only once per event type:

```typescript theme={null}
// Single subscription per event type, distributed to multiple apps
allEventTypes.forEach((eventType: EventType) => {
  subscribe(eventType, (eventData: any) => {
    // Find all interested apps
    const interestedApps = enabledAppsWithPixel.filter(app =>
      app.subscribedEvents.includes(eventType)
    );

    // Distribute to all interested apps
    interestedApps.forEach(app => {
      app.handleEvent(eventType, eventData, client);
    });
  });
});
```

### Immediate Transmission

No batching delays - events are sent immediately:

```typescript theme={null}
// No queuing delays
pixelQueue.add({
  endpoint: this.pixel.endpoint,
  data: transformedPixelData,
}); // Sends immediately
```

### Memory Management

* **No accumulation** - Events are not stored in memory
* **Immediate processing** - Events are transformed and sent immediately
* **Cleanup** - Event handlers are properly cleaned up on unmount

## Error Handling

### Network Errors

```typescript theme={null}
// Automatic retry with exponential backoff
catch (error) {
  if (retryCount < this.retryDelays.length) {
    const delay = this.retryDelays[retryCount];
    setTimeout(() => {
      this.sendEventWithRetry(endpoint, event, retryCount + 1);
    }, delay);
  } else {
    console.error('[Glood] Failed to send pixel event after all retries:', error);
  }
}
```

### Consent Errors

```typescript theme={null}
// Graceful handling when consent is denied
if (!checkConsent(app.pixel.consent, canTrack, analytics)) {
  if (debug) {
    console.log(`[Glood Debug] Consent not granted for ${app.name}, skipping event`);
  }
  return; // Skip event processing
}
```

### Transformation Errors

```typescript theme={null}
// Safe transformation with fallbacks
try {
  const pixelData = this.transformEventData(eventType, eventData, client);
  this.sendPixel(pixelData, client);
} catch (error) {
  console.error(`[Glood] Error transforming ${eventType} event:`, error);
  if (client.debug) {
    console.error('[Glood Debug] Original event data:', eventData);
  }
}
```

## Custom Event Handling

### Accessing Raw Events

```typescript theme={null}
import { useGloodAnalytics } from '@glood/hydrogen';

function CustomAnalytics() {
  const glood = useGloodAnalytics();

  useEffect(() => {
    if (!glood) return;

    const recommendationsApp = glood.getApp('recommendations');
    if (!recommendationsApp) return;

    // Custom event handling
    const originalHandler = recommendationsApp.handleEvent.bind(recommendationsApp);
    recommendationsApp.handleEvent = (eventType, eventData, client) => {
      // Custom processing
      console.log('Custom event processing:', { eventType, eventData });

      // Call original handler
      originalHandler(eventType, eventData, client);
    };
  }, [glood]);

  return null;
}
```

### Custom Data Enrichment

```typescript theme={null}
// Extend event data before transformation
function enrichEventData(eventData: any): any {
  return {
    ...eventData,
    customField: 'custom value',
    timestamp: new Date().toISOString(),
    sessionData: getSessionData(),
  };
}
```

## Best Practices

### 1. Debug Mode in Development

```typescript theme={null}
const glood = createGlood({
  apiKey: process.env.GLOOD_API_KEY!,
  myShopifyDomain: process.env.SHOPIFY_DOMAIN!,
  debug: process.env.NODE_ENV === 'development',
});
```

### 2. Monitor Network Errors

```typescript theme={null}
// Add global error handler for pixel transmission issues
window.addEventListener('unhandledrejection', (event) => {
  if (event.reason?.message?.includes('Glood')) {
    console.error('Glood pixel transmission error:', event.reason);
    // Report to error tracking service
  }
});
```

### 3. Validate Consent Configuration

```typescript theme={null}
// Ensure appropriate consent for each app
const glood = createGlood({
  apps: {
    recommendations: {
      pixel: {
        consent: ['analytics', 'marketing'], // Appropriate for personalization
      },
    },
    search: {
      pixel: {
        consent: ['analytics'], // Minimal for search improvement
      },
    },
  },
});
```

### 4. Test Event Flow

```typescript theme={null}
// Verify events are flowing correctly
const glood = createGlood({
  debug: true, // Enable to see event flow
});

// Check browser console for:
// - Event subscriptions setup
// - Event reception and distribution
// - Consent checking results
// - Pixel transmission success/failure
```

## See Also

* [App Modules](/for-developers/glood-hydrogen-sdk/api-reference/app-modules) - App configuration and event subscriptions
* [Components](/for-developers/glood-hydrogen-sdk/api-reference/components) - GloodProvider setup
* [Utilities](/for-developers/glood-hydrogen-sdk/api-reference/utilities) - Consent and data transformation utilities
* [Content Security Policy](/for-developers/glood-hydrogen-sdk/content-security-policy) - CSP configuration for pixel transmission
