Skip to main content
Ask your AI

RudderStack

Server Source code Package Beta

Server-side event delivery to RudderStack via the official @rudderstack/rudder-sdk-node SDK. Implements the full Segment Spec surface (track, identify, group, page, screen, and alias) with automatic identity deduplication and graceful shutdown via flush().

Where this fits

RudderStack is a server destination in the walkerOS flow:

Receives events server-side from the collector, resolves identity, and forwards them to RudderStack's data plane for routing to downstream destinations.

Installation​

npm install @walkeros/server-destination-rudderstack
import { startFlow } from '@walkeros/collector';
import { destinationRudderStack } from '@walkeros/server-destination-rudderstack';

await startFlow({
  destinations: {
    rudderstack: {
      code: destinationRudderStack,
      config: {
        settings: {
          writeKey: 'YOUR_RUDDERSTACK_WRITE_KEY',
          dataPlaneUrl: 'https://your-data-plane.rudderstack.com',
        },
      },
    },
  },
});

Configuration​

This destination uses the standard destination config wrapper (consent, data, env, id, ...). For the shared fields see destination configuration. Package-specific fields live under config.settings and are listed below.

Settings​

PropertyTypeDescriptionMore
writeKey*stringRudderStack source write key. Find it in the RudderStack dashboard under Sources > Setup.
dataPlaneUrl*stringRudderStack data plane URL. Required. Example: https://your-data-plane.rudderstack.com
userIdstringwalkerOS mapping value path to resolve userId from each event (like user.id).
anonymousIdstringwalkerOS mapping value path to resolve anonymousId from each event (like user.session).
pathstringAPI path route (like /v1/batch).
flushAtintegerEvents the SDK sends in one request. Each push and each config.batch batch flushes the SDK and waits until its calls are sent. Default: 20.
flushIntervalintegerMax milliseconds before auto-flush. Default: 10000.
maxQueueSizeintegerMaximum batch payload size in bytes. Default: 460800 (~500KB).
maxInternalQueueSizeintegerMaximum in-memory queue length. Default: 20000.
logLevelstringSDK log level: 'info', 'debug', 'error', or 'silly'. Default: 'info'.
retryCountintegerRetries the SDK makes for a failed request, a tenth of config.timeout apart. Default: 2, which ends within config.timeout. A value set here wins.
timeoutintegerTime one request may take, in milliseconds. Default: a quarter of config.timeout (2500 at the 10 s default). A value set here wins.
enablebooleanSet to false to no-op all SDK calls. Default: true.
gzipbooleanEnable gzip compression for requests. Default: true.
identifyanyDestination-level identity mapping. Resolves to { traits } object. Fires identify() on the first push and re-fires when values change.
groupanyDestination-level group mapping. Resolves to { groupId, traits }. Fires group() on the first push and re-fires on change.
integrationsRecord<string, any>Enable/disable downstream RudderStack destinations. Example: { "All": true, "Mixpanel": false }.
* Required fields

Mapping​

Per-event rules under config.mapping. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.

PropertyTypeDescriptionMore
identifyanyPer-event identity mapping. Resolves to { userId?, traits? }. Use with rule-level silent: true on login/identify events.
groupanyPer-event group assignment. Resolves to { groupId, traits? }. Use with rule-level silent: true on company/team events.
pageanyPer-event page call. Resolves to { name, properties? } or true for minimal page(). RudderStack requires name (falls back to empty string). Use with silent: true.
screenanyPer-event screen call (mobile backends). Resolves to { name, properties? } or true for minimal screen(). RudderStack requires name (falls back to empty string). Use with silent: true.
aliasanyPer-event alias call. Resolves to { previousId }. Links anonymous user to identified user. Use with rule-level silent: true.

Examples

Alias user

An identity merge fires analytics.alias to link a previous anonymous id to the newly registered user id.

Event
{
  "name": "identity merge",
  "data": {
    "anonymous_id": "anonymous-123"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "lang": "elb"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "registered-456",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "ev1700000107",
  "trigger": "test",
  "entity": "identity",
  "action": "merge",
  "timestamp": 1700000107,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
Mapping
{
  "silent": true,
  "settings": {
    "alias": {
      "map": {
        "previousId": "data.anonymous_id"
      }
    }
  }
}
Out
analytics.alias({
  "messageId": "ev1700000107-alias",
  "userId": "registered-456",
  "previousId": "anonymous-123",
  "timestamp": {}
})

Anonymous only

When no userId is resolved RudderStack accepts the track call keyed solely by anonymousId.

Event
{
  "name": "product view",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "context": {
    "shopping": [
      "detail",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "session": "s3ss10n"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "ev1700000108",
  "trigger": "load",
  "entity": "product",
  "action": "view",
  "timestamp": 1700000108,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
Out
analytics.track({
  "messageId": "ev1700000108",
  "anonymousId": "s3ss10n",
  "event": "product view",
  "properties": {},
  "timestamp": {}
})

Group company

A company update fires analytics.group with the groupId and group traits for B2B account tracking.

Event
{
  "name": "company update",
  "data": {
    "company_id": "comp-456",
    "company_name": "Acme",
    "industry": "tech",
    "employees": 50
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "lang": "elb"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "ev1700000104",
  "trigger": "test",
  "entity": "company",
  "action": "update",
  "timestamp": 1700000104,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
Mapping
{
  "silent": true,
  "settings": {
    "group": {
      "map": {
        "groupId": "data.company_id",
        "traits": {
          "map": {
            "name": "data.company_name",
            "industry": "data.industry",
            "employees": "data.employees"
          }
        }
      }
    }
  }
}
Out
analytics.group({
  "messageId": "ev1700000104-group",
  "userId": "us3r",
  "anonymousId": "s3ss10n",
  "groupId": "comp-456",
  "traits": {
    "name": "Acme",
    "industry": "tech",
    "employees": 50
  },
  "timestamp": {}
})

Default track

A walker event becomes a RudderStack analytics.track call with userId and anonymousId resolved from the event.

Event
{
  "name": "product view",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "context": {
    "shopping": [
      "detail",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "session": "s3ss10n"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "ev1700000100",
  "trigger": "load",
  "entity": "product",
  "action": "view",
  "timestamp": 1700000100,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
Out
analytics.track({
  "messageId": "ev1700000100",
  "userId": "us3r",
  "anonymousId": "s3ss10n",
  "event": "product view",
  "properties": {},
  "timestamp": {}
})

Destination identify

Destination-level identify fires analytics.identify with traits on the first push only, then the track call follows.

Event
{
  "name": "page view",
  "data": {
    "domain": "www.example.com",
    "title": "walkerOS documentation",
    "referrer": "https://www.walkeros.io/",
    "search": "?foo=bar",
    "hash": "#hash",
    "id": "/docs/"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "pagegroup": "docs"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "session": "s3ss10n",
    "email": "user@example.com"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "ev1700000102",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000102,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
Out
analytics.identify({
  "messageId": "ev1700000102-identify",
  "userId": "us3r",
  "anonymousId": "s3ss10n",
  "traits": {
    "email": "user@example.com"
  },
  "timestamp": {}
});

analytics.track({
  "messageId": "ev1700000102",
  "userId": "us3r",
  "anonymousId": "s3ss10n",
  "event": "page view",
  "properties": {},
  "timestamp": {}
})

Renamed event

A mapping renames the event so the RudderStack track call uses a canonical name such as Order Completed.

Event
{
  "name": "order complete",
  "data": {
    "id": "0rd3r1d",
    "currency": "EUR",
    "shipping": 5.22,
    "taxes": 73.76,
    "value": 555
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "ev1700000101",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000101,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
Mapping
{
  "name": "Order Completed"
}
Out
analytics.track({
  "messageId": "ev1700000101",
  "userId": "us3r",
  "anonymousId": "s3ss10n",
  "event": "Order Completed",
  "properties": {},
  "timestamp": {}
})

Page view

A page view fires analytics.page with a resolved page name and properties instead of a generic track.

Event
{
  "name": "page view",
  "data": {
    "title": "Getting Started",
    "section": "tutorials"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "pagegroup": "docs"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "ev1700000105",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000105,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
Mapping
{
  "silent": true,
  "settings": {
    "page": {
      "map": {
        "name": "data.title",
        "properties": {
          "map": {
            "section": "data.section"
          }
        }
      }
    }
  }
}
Out
analytics.page({
  "messageId": "ev1700000105-page",
  "userId": "us3r",
  "anonymousId": "s3ss10n",
  "name": "Getting Started",
  "properties": {
    "section": "tutorials"
  },
  "timestamp": {}
})

Screen view

A screen view from a mobile app backend fires analytics.screen with a screen name and properties.

Event
{
  "name": "screen view",
  "data": {
    "screen_name": "Welcome",
    "section": "onboarding",
    "build": "1.2.3"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "lang": "elb"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "ev1700000106",
  "trigger": "test",
  "entity": "screen",
  "action": "view",
  "timestamp": 1700000106,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
Mapping
{
  "silent": true,
  "settings": {
    "screen": {
      "map": {
        "name": "data.screen_name",
        "properties": {
          "map": {
            "build": "data.build"
          }
        }
      }
    }
  }
}
Out
analytics.screen({
  "messageId": "ev1700000106-screen",
  "userId": "us3r",
  "anonymousId": "s3ss10n",
  "name": "Welcome",
  "properties": {
    "build": "1.2.3"
  },
  "timestamp": {}
})

User login identify

A user login fires only an analytics.identify call with the resolved userId and traits, skipping the track.

Event
{
  "name": "user login",
  "data": {
    "user_id": "new-user-123",
    "email": "user@acme.com",
    "name": "Jane Doe",
    "plan": "premium"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "lang": "elb"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "ev1700000103",
  "trigger": "test",
  "entity": "user",
  "action": "login",
  "timestamp": 1700000103,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
Mapping
{
  "silent": true,
  "settings": {
    "identify": {
      "map": {
        "userId": "data.user_id",
        "traits": {
          "map": {
            "email": "data.email",
            "name": "data.name",
            "plan": "data.plan"
          }
        }
      }
    }
  }
}
Out
analytics.identify({
  "messageId": "ev1700000103-identify",
  "userId": "new-user-123",
  "anonymousId": "s3ss10n",
  "traits": {
    "email": "user@acme.com",
    "name": "Jane Doe",
    "plan": "premium"
  },
  "timestamp": {}
})

Identity is resolved automatically from each event: userId defaults to user.id and anonymousId defaults to user.session. At least one must be present for a call to be sent. Override these paths in settings to match your event structure.

Batching and delivery​

This destination batches by default: config.batch sends after 20 events or 10 seconds, and each event keeps its own outcome. Set config.batch: { size: 1 } to send each event at once. How batching, retries, deduplication and acknowledgement work for the server SDK destinations is described in Server SDK destinations.

An event without userId or anonymousId fails with missing-input.

Alias support​

Unlike Segment, RudderStack also supports per-event alias() calls, useful for linking an anonymous identity to an identified user after signup or login. Configure via mapping.settings.alias with a previousId field.

💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)