> ## 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.

# Server SDK (Node.js)

> Track server-side events and conversions with the DATALYR Node.js SDK

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

```bash theme={null}
npm install @datalyr/api
```

**Requirements:**

* Node.js 14+
* npm or yarn

## Basic Usage

### Initialize SDK

```javascript theme={null}
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://ingest.datalyr.com/track',
  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

```javascript theme={null}
// 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

```javascript theme={null}
// Identify user with traits
await datalyr.identify('user_123', {
  email: 'john@example.com',
  name: 'John Doe',
  plan: 'enterprise',
  created_at: '2025-01-15T10:30:00Z'
});
```

### Group Users

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

### Page Tracking

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

## Configuration Options

### Initialization Config

```javascript theme={null}
const config = {
  apiKey: 'dk_your_api_key',     // Required: API key from Settings
  host: 'https://ingest.datalyr.com/track', // 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

```javascript theme={null}
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

```javascript theme={null}
// Flush events immediately (before closing app)
await datalyr.flush();
```

### Close SDK

```javascript theme={null}
// 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

```javascript theme={null}
// Get SDK's anonymous ID for linking
const anonId = datalyr.getAnonymousId();
```

### Event Batching

Events automatically batched for efficiency:

```javascript theme={null}
// 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:

```typescript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
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)

```javascript theme={null}
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:**

```javascript theme={null}
// 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: 'user@example.com'
  }
});
```

DATALYR links all anonymous activity to `user_123` for complete attribution.

**Get Anonymous ID from Web SDK:**

```javascript theme={null}
// 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

```javascript theme={null}
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:**

```javascript theme={null}
// Create single SDK instance
const datalyr = new Datalyr('dk_your_api_key');

// Reuse across application
module.exports = datalyr;
```

**Flush Before Exit:**

```javascript theme={null}
// Ensure events sent before process exits
process.on('SIGTERM', async () => {
  await datalyr.close();
  process.exit(0);
});
```

**Handle Webhooks Efficiently:**

```javascript theme={null}
// 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:**

```javascript theme={null}
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:**

```javascript theme={null}
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 [hello@datalyr.com](mailto:hello@datalyr.com) 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

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

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

  <Card title="Advanced Topics" icon="code" href="/sdks/advanced">
    Identity, batching, plugins
  </Card>

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