Skip to main content

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 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:
// Automatically creates anonymousId on first visit
datalyr.init({ workspaceId: 'abc123' });

// Get anonymous ID
const anonId = datalyr.getAnonymousId();
// Returns: "anon_abc123xyz"
Server SDK:
// 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:
// 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)
// User visits site - Web SDK tracks anonymously
datalyr.track('product_view', {
  product_id: 'prod_123'
});
// anonymousId: "anon_abc123"
Step 2: User Signs Up
// User creates account
datalyr.identify('user_456', {
  email: '[email protected]',
  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:
// Client-side (Web SDK)
const anonymousId = datalyr.getAnonymousId();

// Send to server on signup
fetch('/api/signup', {
  method: 'POST',
  body: JSON.stringify({
    email: '[email protected]',
    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:
// 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).
// 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:
datalyr.init({
  workspaceId: 'abc123',
  batchSize: 10,           // Events per batch
  flushInterval: 5000,     // Flush every 5 seconds
  flushAt: 10              // Auto-flush at 10 events
});
Server SDK:
const datalyr = new Datalyr({
  apiKey: 'dk_your_api_key',
  flushAt: 20,             // Larger batches for server
  flushInterval: 10000
});
Mobile SDKs:
await Datalyr.initialize({
  apiKey: 'dk_your_api_key',
  batchSize: 10,
  flushInterval: 30000
});

Manual Flushing

Force Immediate Send:
// 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:
datalyr.init({
  workspaceId: 'abc123',
  maxOfflineQueueSize: 100,  // Max queued events
  maxRetries: 5,              // Retry attempts
  retryDelay: 1000            // Initial retry delay (ms)
});
Server SDK:
const datalyr = new Datalyr({
  apiKey: 'dk_your_api_key',
  maxQueueSize: 1000,
  retryLimit: 3
});
Mobile SDKs:
await Datalyr.initialize({
  apiKey: 'dk_your_api_key',
  maxQueueSize: 100,
  maxRetries: 3
});

Handling Offline State

Check Network Status:
// 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:
<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:
// 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

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:
// 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

// 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:
datalyr.init({
  workspaceId: 'abc123',
  maxRetries: 5,
  retryDelay: 1000
});

Error Handling

Web SDK:
try {
  await datalyr.track('event_name');
} catch (error) {
  console.error('Tracking failed:', error);
}

// View recent errors
const errors = datalyr.getErrors();
Server SDK:
try {
  await datalyr.track({
    userId: 'user_123',
    event: 'purchase'
  });
} catch (error) {
  console.error('Tracking failed:', error.message);
  // Handle error (log, alert, etc.)
}
Mobile SDKs:
do {
  try await DatalyrSDK.shared.track("event_name")
} catch {
  print("Tracking error: \(error)")
}

Graceful Degradation

SDKs designed to fail silently without breaking your application.
// Even if SDK fails, app continues
datalyr.track('button_click');
handleButtonClick();  // Always executes

Plugin Architecture (Web SDK)

Custom Plugins

Create Plugin:
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:
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:
const consoleLoggerPlugin = {
  name: 'ConsoleLogger',

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

  identify: (userId, traits) => {
    console.log(`[Identify] ${userId}`, traits);
  }
};
Custom Destination:
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

// 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

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

import { throttle } from 'lodash';

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

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

Context Enrichment

// 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:
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:
const workspaceId = process.env.NODE_ENV === 'production'
  ? 'prod_workspace_id'
  : 'test_workspace_id';

datalyr.init({ workspaceId });

Mock SDK for Tests

// __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

Web SDK

Browser tracking guide

Server SDK

Backend tracking guide

Mobile SDKs

iOS & React Native guide

Event Stream

Verify tracked events