Skip to main content
The DATALYR Server SDK (Node.js) enables backend event tracking for server-side applications, webhooks, APIs, and data processing pipelines.

What It Does

Server-Side Tracking:
  • Track events from backend services
  • Process webhook conversions
  • Import historical data
  • Track authenticated users
  • Server-to-server attribution
  • Secure API key authentication
  • Event batching and retry logic

Installation

npm install @datalyr/api
Requirements:
  • Node.js 14+
  • npm or yarn

Basic Usage

Initialize SDK

const Datalyr = require('@datalyr/api');

// Simple initialization
const datalyr = new Datalyr('dk_your_api_key');

// With configuration
const datalyr = new Datalyr({
  apiKey: 'dk_your_api_key',
  host: 'https://api.datalyr.com',
  debug: true,
  flushAt: 20,               // Flush after 20 events
  flushInterval: 10000,      // Or every 10 seconds
  timeout: 10000,            // Request timeout (ms)
  retryLimit: 3,             // Max retry attempts
  maxQueueSize: 1000         // Max queued events
});

Track Events

// Track event with user ID
await datalyr.track({
  userId: 'user_123',
  event: 'purchase',
  properties: {
    revenue: 99.99,
    currency: 'USD',
    product_id: 'prod_456'
  }
});

// Track with anonymous ID
await datalyr.track({
  anonymousId: 'anon_abc123',
  event: 'signup',
  properties: {
    plan: 'pro'
  }
});

// Track with both (identity resolution)
await datalyr.track({
  userId: 'user_123',
  anonymousId: 'anon_abc123',  // Link anonymous to known user
  event: 'login',
  properties: {
    method: 'email'
  }
});

Identify Users

// Identify user with traits
await datalyr.identify('user_123', {
  email: '[email protected]',
  name: 'John Doe',
  plan: 'enterprise',
  created_at: '2025-01-15T10:30:00Z'
});

Group Users

// Associate user with account/organization
await datalyr.group('user_123', 'company_456', {
  name: 'Acme Corp',
  plan: 'enterprise',
  employees: 500
});

Page Tracking

// Track server-rendered page view
await datalyr.page('user_123', 'Landing Page', {
  url: 'https://example.com',
  referrer: 'https://google.com'
});

Configuration Options

Initialization Config

const config = {
  apiKey: 'dk_your_api_key',     // Required: API key from Settings
  host: 'https://api.datalyr.com', // API endpoint
  debug: false,                   // Enable debug logs
  flushAt: 20,                    // Flush after N events
  flushInterval: 10000,           // Flush every N ms
  timeout: 10000,                 // Request timeout
  retryLimit: 3,                  // Max retries for failed events
  maxQueueSize: 1000              // Max queued events before dropping oldest
};

Event Options

await datalyr.track({
  userId: 'user_123',          // User identifier (optional)
  anonymousId: 'anon_abc',     // Anonymous identifier (optional)
  event: 'purchase',           // Event name (required)
  properties: {                // Event properties (optional)
    revenue: 99.99,
    currency: 'USD'
  }
});
Note: Must provide userId or anonymousId (or both for identity linking).

Advanced Features

Manual Flush

// Flush events immediately (before closing app)
await datalyr.flush();

Close SDK

// Flush and cleanup before shutdown
await datalyr.close();
Automatically called on process exit, but manually call in serverless functions or short-lived scripts.

Get Anonymous ID

// Get SDK's anonymous ID for linking
const anonId = datalyr.getAnonymousId();

Event Batching

Events automatically batched for efficiency:
// All these events batched together
for (let i = 0; i < 100; i++) {
  await datalyr.track({
    userId: `user_${i}`,
    event: 'batch_event',
    properties: { index: i }
  });
}

// Batch sent when flushAt reached or flushInterval elapsed

TypeScript Support

Full TypeScript definitions included:
import Datalyr, { DatalyrConfig, TrackOptions } from '@datalyr/api';

const config: DatalyrConfig = {
  apiKey: 'dk_your_api_key',
  debug: true
};

const datalyr = new Datalyr(config);

const options: TrackOptions = {
  userId: 'user_123',
  event: 'purchase',
  properties: {
    revenue: 99.99,
    currency: 'USD'
  }
};

await datalyr.track(options);

Common Use Cases

Stripe Webhook

const express = require('express');
const Datalyr = require('@datalyr/api');

const app = express();
const datalyr = new Datalyr('dk_your_api_key');

app.post('/webhook/stripe', express.json(), async (req, res) => {
  const event = req.body;

  if (event.type === 'checkout.session.completed') {
    const session = event.data.object;

    await datalyr.track({
      userId: session.client_reference_id,
      event: 'purchase',
      properties: {
        revenue: session.amount_total / 100,
        currency: session.currency,
        order_id: session.id,
        payment_method: 'stripe'
      }
    });
  }

  res.json({ received: true });
});

app.listen(3000);

Background Job Processing

const Datalyr = require('@datalyr/api');
const datalyr = new Datalyr('dk_your_api_key');

async function processOrderQueue() {
  const orders = await fetchOrders();

  for (const order of orders) {
    await datalyr.track({
      userId: order.userId,
      event: 'order_processed',
      properties: {
        order_id: order.id,
        status: order.status,
        total: order.total
      }
    });
  }

  // Ensure all events sent before job completes
  await datalyr.flush();
}

Shopify Webhook

const Datalyr = require('@datalyr/api');
const datalyr = new Datalyr('dk_your_api_key');

async function handleShopifyOrder(orderData) {
  await datalyr.track({
    userId: orderData.customer.email,
    event: 'purchase',
    properties: {
      order_id: orderData.id,
      revenue: parseFloat(orderData.total_price),
      currency: orderData.currency,
      products: orderData.line_items.map(item => item.product_id),
      quantity: orderData.line_items.reduce((sum, item) => sum + item.quantity, 0)
    }
  });
}

Bulk Data Import

const Datalyr = require('@datalyr/api');
const datalyr = new Datalyr({
  apiKey: 'dk_your_api_key',
  flushAt: 50,  // Larger batch for imports
  flushInterval: 5000
});

async function importHistoricalData(events) {
  console.log(`Importing ${events.length} events...`);

  for (const event of events) {
    await datalyr.track({
      userId: event.userId,
      event: event.eventName,
      properties: event.properties
    });
  }

  // Ensure all events sent
  await datalyr.flush();
  await datalyr.close();

  console.log('Import complete');
}

Serverless Function (AWS Lambda)

const Datalyr = require('@datalyr/api');

// Initialize outside handler for connection reuse
const datalyr = new Datalyr('dk_your_api_key');

exports.handler = async (event) => {
  const body = JSON.parse(event.body);

  await datalyr.track({
    userId: body.userId,
    event: 'api_request',
    properties: {
      endpoint: event.path,
      method: event.httpMethod
    }
  });

  // Flush before function exits
  await datalyr.flush();

  return {
    statusCode: 200,
    body: JSON.stringify({ success: true })
  };
};

Identity Resolution

Link Anonymous to Known User:
// User visits site (Web SDK creates anonymous ID)
// Later, user signs up on backend

await datalyr.track({
  userId: 'user_123',
  anonymousId: 'anon_abc123',  // From Web SDK cookie/localStorage
  event: 'signup',
  properties: {
    email: '[email protected]'
  }
});
DATALYR links all anonymous activity to user_123 for complete attribution. Get Anonymous ID from Web SDK:
// Client-side (Web SDK)
const anonymousId = datalyr.getAnonymousId();

// Send to server
fetch('/api/signup', {
  method: 'POST',
  body: JSON.stringify({ anonymousId })
});

// Server-side (Server SDK)
app.post('/api/signup', async (req, res) => {
  await datalyr.track({
    userId: req.user.id,
    anonymousId: req.body.anonymousId,  // Link identities
    event: 'signup'
  });
});

Error Handling

try {
  await datalyr.track({
    userId: 'user_123',
    event: 'purchase',
    properties: { revenue: 99.99 }
  });
} catch (error) {
  console.error('Tracking failed:', error.message);
}
Automatic Retries: Failed events automatically retried up to retryLimit with exponential backoff. Client Errors (4xx): Not retried (invalid data, unauthorized). Server Errors (5xx): Retried automatically.

Best Practices

Initialize Once:
// Create single SDK instance
const datalyr = new Datalyr('dk_your_api_key');

// Reuse across application
module.exports = datalyr;
Flush Before Exit:
// Ensure events sent before process exits
process.on('SIGTERM', async () => {
  await datalyr.close();
  process.exit(0);
});
Handle Webhooks Efficiently:
// Don't block webhook response
app.post('/webhook', async (req, res) => {
  // Respond immediately
  res.json({ received: true });

  // Track asynchronously
  datalyr.track({
    userId: req.body.userId,
    event: 'webhook_received'
  }).catch(err => console.error('Tracking error:', err));
});
Batch Large Imports:
const datalyr = new Datalyr({
  apiKey: 'dk_your_api_key',
  flushAt: 100,           // Larger batches
  flushInterval: 30000,   // Less frequent flushes
  maxQueueSize: 10000     // More queue capacity
});

Debugging

Enable Debug Mode:
const datalyr = new Datalyr({
  apiKey: 'dk_your_api_key',
  debug: true  // Logs all events and API calls
});
Console Output:
[Datalyr] Event queued: purchase
[Datalyr] Flushing 10 events
[Datalyr] Event sent successfully

Rate Limits

API Limits:
  • 1,000 requests per second
  • 10,000 events per batch
Contact [email protected] for higher limits.

Troubleshooting

Events Not Appearing:
  • Verify API key from Settings → API Keys
  • Check debug: true for error messages
  • Ensure flush() called before app exits
  • Check Event Stream for events
  • Verify workspace ID matches (if using)
Identity Not Linking:
  • Pass both userId and anonymousId in track()
  • Ensure anonymousId matches Web SDK value
  • Check User Journeys for linked identities
High Memory Usage:
  • Reduce maxQueueSize
  • Increase flushAt frequency
  • Call flush() more often

API Reference

track(options)

Track an event. Parameters:
  • userId (string, optional): User identifier
  • anonymousId (string, optional): Anonymous identifier
  • event (string, required): Event name
  • properties (object, optional): Event properties
Returns: Promise<void>

identify(userId, traits)

Identify a user. Parameters:
  • userId (string, required): User identifier
  • traits (object, optional): User properties
Returns: Promise<void>

group(userId, groupId, traits)

Associate user with group. Parameters:
  • userId (string, required): User identifier
  • groupId (string, required): Group identifier
  • traits (object, optional): Group properties
Returns: Promise<void>

page(userId, name, properties)

Track page view. Parameters:
  • userId (string, required): User identifier
  • name (string, optional): Page name
  • properties (object, optional): Page properties
Returns: Promise<void>

flush()

Flush queued events immediately. Returns: Promise<void>

close()

Flush events and cleanup. Returns: Promise<void>

getAnonymousId()

Get SDK’s anonymous ID. Returns: string

Next Steps