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

# Advanced SDK Topics

> Identity resolution, batching, offline queues, and advanced SDK features

Advanced SDK features and patterns for identity resolution, performance optimization, and complex tracking scenarios.

## What It Covers

**Advanced Topics:**

* Identity resolution and linking
* Event batching and queuing
* Offline support
* Performance optimization
* Error handling and retries
* Plugin architecture
* Custom integrations

## Identity Resolution

### Understanding Identity

DATALYR uses multiple identifiers to track users across sessions and devices:

**Identity Fields:**

* `anonymousId`: Persistent anonymous identifier (set by SDK)
* `visitorId`: Browser/device visitor ID (Web/Mobile SDKs)
* `userId`: Your application's user ID (after login)
* `distinctId`: Resolved ID (userId if available, else anonymousId)

### Anonymous Tracking

**Web SDK:**

```javascript theme={null}
// Automatically creates anonymousId on first visit
datalyr.init({ workspaceId: 'abc123' });

// Get anonymous ID
const anonId = datalyr.getAnonymousId();
// Returns: "anon_abc123xyz"
```

**Server SDK:**

```javascript theme={null}
// SDK creates persistent anonymousId
const datalyr = new Datalyr('dk_your_api_key');

// Track with anonymous ID
await datalyr.track({
  anonymousId: datalyr.getAnonymousId(),
  event: 'page_view'
});
```

**Mobile SDKs:**

```swift theme={null}
// iOS: Automatically creates anonymousId
let anonId = DatalyrSDK.shared.getAnonymousId()

// React Native
const anonId = Datalyr.getAnonymousId();
```

### Linking Anonymous to Known Users

**Scenario:** User visits site anonymously, then signs up.

**Step 1: Anonymous Tracking (Web SDK)**

```javascript theme={null}
// User visits site - Web SDK tracks anonymously
datalyr.track('product_view', {
  product_id: 'prod_123'
});
// anonymousId: "anon_abc123"
```

**Step 2: User Signs Up**

```javascript theme={null}
// User creates account
datalyr.identify('user_456', {
  email: 'user@example.com',
  name: 'John Doe'
});
// Links anonymousId "anon_abc123" to userId "user_456"
```

**Result:** All previous anonymous activity now attributed to `user_456`.

### Cross-Platform Identity

**Web to Server:**

```javascript theme={null}
// Client-side (Web SDK)
const anonymousId = datalyr.getAnonymousId();

// Send to server on signup
fetch('/api/signup', {
  method: 'POST',
  body: JSON.stringify({
    email: 'user@example.com',
    anonymousId: anonymousId
  })
});

// Server-side (Server SDK)
app.post('/api/signup', async (req, res) => {
  const userId = await createUser(req.body.email);

  // Link anonymous to known user
  await datalyr.track({
    userId: userId,
    anonymousId: req.body.anonymousId,
    event: 'signup',
    properties: {
      email: req.body.email
    }
  });
});
```

**Mobile to Server:**

```javascript theme={null}
// Mobile app (React Native)
const anonymousId = Datalyr.getAnonymousId();

// Send to backend
const response = await fetch('/api/purchase', {
  method: 'POST',
  body: JSON.stringify({
    userId: currentUser.id,
    anonymousId: anonymousId,
    orderId: order.id
  })
});

// Server processes webhook
await datalyr.track({
  userId: req.body.userId,
  anonymousId: req.body.anonymousId,
  event: 'purchase',
  properties: {
    order_id: req.body.orderId
  }
});
```

### Aliasing

**Use Case:** User has multiple IDs (email, phone, external ID).

```javascript theme={null}
// Web SDK: Connect new ID to existing
datalyr.alias('user_new_id', 'user_old_id');

// Server SDK
await datalyr.track({
  event: 'alias',
  userId: 'user_new_id',
  anonymousId: 'user_old_id'
});
```

**Result:** Both IDs resolve to same canonical user.

## Event Batching

### How Batching Works

SDKs batch events for efficiency instead of sending individually.

**Default Behavior:**

* Events queued in memory
* Batch sent when `flushAt` size reached
* Or when `flushInterval` elapsed
* Automatically flushed on page unload/app background

### Configuration

**Web SDK:**

```javascript theme={null}
datalyr.init({
  workspaceId: 'abc123',
  batchSize: 10,           // Events per batch
  flushInterval: 5000,     // Flush every 5 seconds
  flushAt: 10              // Auto-flush at 10 events
});
```

**Server SDK:**

```javascript theme={null}
const datalyr = new Datalyr({
  apiKey: 'dk_your_api_key',
  flushAt: 20,             // Larger batches for server
  flushInterval: 10000
});
```

**Mobile SDKs:**

```javascript theme={null}
await Datalyr.initialize({
  apiKey: 'dk_your_api_key',
  batchSize: 10,
  flushInterval: 30000
});
```

### Manual Flushing

**Force Immediate Send:**

```javascript theme={null}
// Web SDK
await datalyr.flush();

// Server SDK
await datalyr.flush();

// Mobile SDKs
await Datalyr.flush();
```

**Use Cases:**

* Before page navigation
* Before app closes
* After critical events
* Before serverless function exits

### Batch Size Optimization

**Small Batches (1-5 events):**

* Real-time tracking
* Low traffic sites
* Critical events

**Medium Batches (10-20 events):**

* Default for most sites
* Balanced latency/performance

**Large Batches (50-100 events):**

* High traffic applications
* Bulk imports
* Non-time-sensitive tracking

## Offline Support

### How Offline Queue Works

SDKs queue events when offline and send when connection restored.

**Features:**

* Automatic network detection
* Persistent queue (survives app restart)
* Automatic retry with backoff
* Max queue size limit

### Configuration

**Web SDK:**

```javascript theme={null}
datalyr.init({
  workspaceId: 'abc123',
  maxOfflineQueueSize: 100,  // Max queued events
  maxRetries: 5,              // Retry attempts
  retryDelay: 1000            // Initial retry delay (ms)
});
```

**Server SDK:**

```javascript theme={null}
const datalyr = new Datalyr({
  apiKey: 'dk_your_api_key',
  maxQueueSize: 1000,
  retryLimit: 3
});
```

**Mobile SDKs:**

```javascript theme={null}
await Datalyr.initialize({
  apiKey: 'dk_your_api_key',
  maxQueueSize: 100,
  maxRetries: 3
});
```

### Handling Offline State

**Check Network Status:**

```javascript theme={null}
// Web SDK
const status = datalyr.getNetworkStatus();
console.log('Online:', status.online);
console.log('Pending events:', status.queueSize);

// Mobile SDKs
const status = Datalyr.getStatus();
console.log('Queue size:', status.queueStats.queueSize);
```

**Queue Overflow:**
When queue exceeds `maxQueueSize`, oldest events dropped first.

## Performance Optimization

### Lazy Loading (Web SDK)

**Defer Script Loading:**

```html theme={null}
<script defer src="https://track.datalyr.com/dl.js"
  data-workspace-id="abc123">
</script>
```

Uses `defer` attribute to load script without blocking page render.

### Reduce Event Volume

**Track Selectively:**

```javascript theme={null}
// Bad: Track every mousemove
document.addEventListener('mousemove', () => {
  datalyr.track('mouse_move');  // Thousands of events
});

// Good: Track meaningful interactions
button.addEventListener('click', () => {
  datalyr.track('button_click');  // Few events
});
```

### Debounce Frequent Events

```javascript theme={null}
import { debounce } from 'lodash';

const trackScroll = debounce(() => {
  datalyr.track('scroll', {
    depth: window.scrollY
  });
}, 1000);

window.addEventListener('scroll', trackScroll);
```

### Use Super Properties

**Instead of Repeating Properties:**

```javascript theme={null}
// Bad
datalyr.track('page_view', { version: '2.0', env: 'prod' });
datalyr.track('button_click', { version: '2.0', env: 'prod' });
datalyr.track('form_submit', { version: '2.0', env: 'prod' });

// Good
datalyr.setSuperProperties({
  version: '2.0',
  env: 'prod'
});

datalyr.track('page_view');
datalyr.track('button_click');
datalyr.track('form_submit');
```

### Increase Batch Size

```javascript theme={null}
// For high-volume tracking
datalyr.init({
  workspaceId: 'abc123',
  flushAt: 50,           // Larger batches
  flushInterval: 30000   // Less frequent flushes
});
```

## Error Handling

### Automatic Retries

All SDKs retry failed requests automatically.

**Retry Logic:**

* Exponential backoff (1s, 2s, 4s, 8s...)
* Max retry attempts configurable
* Client errors (4xx) not retried
* Server errors (5xx) retried

**Configuration:**

```javascript theme={null}
datalyr.init({
  workspaceId: 'abc123',
  maxRetries: 5,
  retryDelay: 1000
});
```

### Error Handling

**Web SDK:**

```javascript theme={null}
try {
  await datalyr.track('event_name');
} catch (error) {
  console.error('Tracking failed:', error);
}

// View recent errors
const errors = datalyr.getErrors();
```

**Server SDK:**

```javascript theme={null}
try {
  await datalyr.track({
    userId: 'user_123',
    event: 'purchase'
  });
} catch (error) {
  console.error('Tracking failed:', error.message);
  // Handle error (log, alert, etc.)
}
```

**Mobile SDKs:**

```swift theme={null}
do {
  try await DatalyrSDK.shared.track("event_name")
} catch {
  print("Tracking error: \(error)")
}
```

### Graceful Degradation

SDKs designed to fail silently without breaking your application.

```javascript theme={null}
// Even if SDK fails, app continues
datalyr.track('button_click');
handleButtonClick();  // Always executes
```

## Plugin Architecture (Web SDK)

### Custom Plugins

**Create Plugin:**

```javascript theme={null}
const myPlugin = {
  name: 'MyPlugin',

  initialize: (datalyr) => {
    console.log('Plugin initialized');
  },

  track: (eventName, properties) => {
    console.log('Event tracked:', eventName);
  },

  identify: (userId, traits) => {
    console.log('User identified:', userId);
  },

  page: (properties) => {
    console.log('Page viewed:', properties.url);
  }
};

// Use plugin
datalyr.init({
  workspaceId: 'abc123',
  plugins: [myPlugin]
});
```

### Plugin Use Cases

**Google Analytics Integration:**

```javascript theme={null}
const googleAnalyticsPlugin = {
  name: 'GoogleAnalytics',

  initialize: (datalyr) => {
    // Initialize GA
    gtag('config', 'GA_MEASUREMENT_ID');
  },

  track: (eventName, properties) => {
    // Send to GA
    gtag('event', eventName, properties);
  }
};
```

**Console Logger:**

```javascript theme={null}
const consoleLoggerPlugin = {
  name: 'ConsoleLogger',

  track: (eventName, properties) => {
    console.log(`[Event] ${eventName}`, properties);
  },

  identify: (userId, traits) => {
    console.log(`[Identify] ${userId}`, traits);
  }
};
```

**Custom Destination:**

```javascript theme={null}
const customDestinationPlugin = {
  name: 'CustomDestination',

  track: async (eventName, properties) => {
    await fetch('https://my-api.com/track', {
      method: 'POST',
      body: JSON.stringify({ eventName, properties })
    });
  }
};
```

## Advanced Patterns

### Conditional Tracking

```javascript theme={null}
// Only track in production
if (process.env.NODE_ENV === 'production') {
  datalyr.track('event_name');
}

// Track for specific users
if (user.plan === 'enterprise') {
  datalyr.track('feature_usage');
}
```

### Event Validation

```javascript theme={null}
function trackValidated(eventName, properties) {
  // Validate event name
  if (!/^[a-z_]+$/.test(eventName)) {
    console.error('Invalid event name:', eventName);
    return;
  }

  // Validate properties
  if (properties && typeof properties !== 'object') {
    console.error('Properties must be object');
    return;
  }

  datalyr.track(eventName, properties);
}
```

### Rate Limiting

```javascript theme={null}
import { throttle } from 'lodash';

const trackThrottled = throttle((eventName, properties) => {
  datalyr.track(eventName, properties);
}, 1000);

// Max 1 event per second
trackThrottled('rapid_event');
```

### Context Enrichment

```javascript theme={null}
// Add context to all events
datalyr.setSuperProperties({
  app_version: '2.1.0',
  environment: 'production',
  user_role: currentUser.role,
  experiment_variant: getExperimentVariant()
});
```

## Testing SDKs

### Debug Mode

**Enable Debug Logs:**

```javascript theme={null}
datalyr.init({
  workspaceId: 'abc123',
  debug: true
});
```

**Console Output:**

```
[Datalyr] SDK initialized
[Datalyr] Event tracked: button_click
[Datalyr] Flushing 5 events
[Datalyr] Events sent successfully
```

### Testing Environment

**Use Test Workspace:**

```javascript theme={null}
const workspaceId = process.env.NODE_ENV === 'production'
  ? 'prod_workspace_id'
  : 'test_workspace_id';

datalyr.init({ workspaceId });
```

### Mock SDK for Tests

```javascript theme={null}
// __mocks__/@datalyr/web.js
export default {
  init: jest.fn(),
  track: jest.fn(),
  identify: jest.fn(),
  flush: jest.fn()
};

// test.js
import datalyr from '@datalyr/web';

test('tracks button click', () => {
  handleClick();
  expect(datalyr.track).toHaveBeenCalledWith('button_click');
});
```

## Best Practices

**Initialize Once:**
Create single SDK instance and reuse throughout application.

**Flush Before Exit:**
Call `flush()` before page navigation, app close, or function termination.

**Use Super Properties:**
Set common properties once instead of repeating in every event.

**Batch Appropriately:**
Balance real-time needs with performance (larger batches = better performance).

**Handle Errors:**
Wrap tracking in try/catch for critical paths.

**Respect Privacy:**
Enable Do Not Track, respect user consent, anonymize sensitive data.

**Test Thoroughly:**
Use debug mode and test workspace during development.

**Monitor Queue Size:**
Check queue size in high-traffic scenarios to prevent memory issues.

## Next Steps

<CardGroup cols={2}>
  <Card title="Web SDK" icon="globe" href="/sdks/web">
    Browser tracking guide
  </Card>

  <Card title="Server SDK" icon="server" href="/sdks/server">
    Backend tracking guide
  </Card>

  <Card title="Mobile SDKs" icon="mobile" href="/sdks/mobile">
    iOS & React Native guide
  </Card>

  <Card title="Event Stream" icon="water" href="/features/event-stream">
    Verify tracked events
  </Card>
</CardGroup>
