Skip to contentSkip to navigationSkip to topbar
On this page
Looking for more inspiration?Visit the
(information)
You're in the right place! Segment documentation is now part of Twilio Docs. The content you are used to is still here—just in a new home with a refreshed look.

Analytics for Node.js


Community x
Maintenance x
Flagship

Segment's Analytics Node.js library lets you record analytics data from your node code. The requests hit Segment's servers, and then Segment routes your data to any destinations you have enabled.

The Segment Analytics Node.js Next library is open-source(link takes you to an external page) on GitHub.

All of Segment's server-side libraries are built for high-performance, so you can use them in your web server controller code. This library uses an internal queue to make Identify and Track calls non-blocking and fast. It also batches messages and flushes asynchronously to Segment's servers.


Getting started

getting-started page anchor
(warning)

Warning

Make sure you're using a version of Node that's 18 or higher.

  1. Run the relevant command to add Segment's Node library module to your package.json.

    1
    # npm
    2
    npm install @segment/analytics-node
    3
    # yarn
    4
    yarn add @segment/analytics-node
    5
    # pnpm
    6
    pnpm add @segment/analytics-node
  2. Initialize the Analytics constructor the module exposes with your Segment source Write Key:

    1
    import { Analytics } from '@segment/analytics-node'
    2
    // or, if you use require:
    3
    const { Analytics } = require('@segment/analytics-node')
    4
    5
    // instantiation
    6
    const analytics = new Analytics({ writeKey: '<YOUR_WRITE_KEY>' })

Replace YOUR_WRITE_KEY with your actual Write Key which you can find in Segment by navigating to: Connections > Sources, selecting your source, and going to the Settings tab.

This creates an instance of Analytics that you can use to send data to Segment for your project. The default initialization settings are production-ready and queue 20 messages before sending any requests.


The basic tracking methods below serve as the building blocks of your Segment tracking. They include Identify, Track, Page, Group, and Alias.

These methods correspond with those used in the Segment Spec. The documentation on this page explains how to use these methods in Analytics for Node.js.

Identify

identify page anchor
(information)

Info

For any of the different methods described on this page, you can replace the properties and traits in the code samples with variables that represent the data collected.

Identify lets you tie a user to their actions and record traits about them. It includes a unique User ID and/or anonymous ID, and any optional traits you know about them.

You should call Identify once when the user's account is first created, and then again any time their traits change.

Example of an anonymous Identify call:

1
analytics.identify({
2
anonymousId: '48d213bb-95c3-4f8d-af97-86b2b404dcfe',
3
traits: {
4
friends: 42
5
}
6
});

This call identifies the user and records their unique anonymous ID, and labels them with the friends trait.

Example of an Identify call for an identified user:

1
analytics.identify({
2
userId: '019mr8mf4r',
3
traits: {
4
name: 'Michael Bolton',
5
email: 'mbolton@example.com',
6
plan: 'Enterprise',
7
friends: 42
8
}
9
});

The call above identifies Michael by his unique User ID (the one you know him by in your database), and labels him with the name, email, plan, and friends traits.

An Identify call has the following fields:

FieldData typeDetails
userIdString, optionalThe ID for this user in your database. Note: at least one of userId or anonymousId must be included in any Identify call.
anonymousIdString, optionalAn ID associated with the user when you don't know who they are (for example, the anonymousId generated by analytics.js). Note: You must include at least one of userId or anonymousId in all Identify calls.
traitsObject, optionalA dictionary of traits you know about the user. Things like: email, name, or friends.
timestampDate, optionalA JavaScript date object representing when the identify took place. If the identify just happened, leave it out as Segment uses the server's time. If you're importing data from the past make sure to send a timestamp.
contextObject, optionalA dictionary of extra context to attach to the call. Note: context differs from traits because it is not attributes of the user itself.

Find details on the Identify method payload in Segment's Spec.

Track lets you record the actions your users perform. Every action triggers an event, which can also have associated properties.

You'll want to track events that are indicators of success for your site, like Signed Up, Item Purchased, or Article Bookmarked.

To get started, Segment recommends tracking just a few important events. You can always add more later.

Example anonymous Track call:

1
analytics.track({
2
anonymousId: '48d213bb-95c3-4f8d-af97-86b2b404dcfe',
3
event: 'Item Purchased',
4
properties: {
5
revenue: 39.95,
6
shippingMethod: '2-day'
7
}
8
});

Example identified Track call:

1
analytics.track({
2
userId: '019mr8mf4r',
3
event: 'Item Purchased',
4
properties: {
5
revenue: 39.95,
6
shippingMethod: '2-day'
7
}
8
});

This example Track call tells you that your user just triggered the Item Purchased event with a revenue of $39.95 and chose your hypothetical '2-day' shipping.

Track event properties can be anything you want to record. In this case, revenue and shipping method.

The Track call has the following fields:

FieldData typeDetails
userIdString, optionalThe ID for this user in your database. _Note: at least one of userId or anonymousId must be included in any Track call.
anonymousIdString, optionalAn ID associated with the user when you don't know who they are (for example, the anonymousId generated by analytics.js). Note: You must include at least one of userId or anonymousId in all Track calls.
eventStringThe name of the event you're tracking. We recommend human-readable names like Song Played or Status Updated.
propertiesObject, optionalA dictionary of properties for the event. If the event was Product Added, it might have properties like price or product.
timestampDate, optionalA JavaScript date object representing when the track took place. If the track just happened, leave it out and we'll use the server's time. If you're importing data from the past make sure you to send a timestamp.
contextObject, optionalA dictionary of extra context to attach to the call. Note: context differs from traits because it is not attributes of the user itself.

Find details on best practices in event naming and the Track method payload in the Segment Spec.

The Page method lets you record page views on your website, along with optional extra information about the page being viewed.

If you're using Segment's client-side set up in combination with the Node.js library, Page calls are already tracked for you by default. However, if you want to record your own page views manually and aren't using the client-side library, read on.

Example Page call:

1
analytics.page({
2
userId: '019mr8mf4r',
3
category: 'Docs',
4
name: 'Node.js Library',
5
properties: {
6
url: 'https://segment.com/docs/connections/sources/catalog/librariesnode',
7
path: '/docs/connections/sources/catalog/librariesnode/',
8
title: 'Node.js Library - Segment',
9
referrer: 'https://github.com/segmentio/analytics-node'
10
}
11
});

A Page call has the following fields:

FieldData typeDetails
userIdString, optionalThe ID for this user in your database. _Note: at least one of userId or anonymousId must be included in any Page call.
anonymousIdString, optionalAn ID associated with the user when you don't know who they are (for example, the anonymousId generated by analytics.js). Note: at least one of userId or anonymousId must be included in any Page call.
categoryString, optionalThe category of the page. Useful for industries, like ecommerce, where many pages often live under a larger category.
nameString, optionalThe name of the page, for example Signup or Home.
propertiesObject, optionalA dictionary of properties of the page. A few properties specially recognized and automatically translated: url, title, referrer, and path, but you can add your own too.
timestampDate, optionalA JavaScript date object representing when the Page took place. If the Page just happened, leave it out and Segment will use the server's time. If you're importing data from the past make sure you to send a timestamp.
contextObject, optionalA dictionary of extra context to attach to the call. Note: context differs from traits because it is not attributes of the user itself.

Find details on the Page payload in the Segment Spec.

Group lets you associate an identified user with a group. A group could be a company, organization, account, project or team. It also lets you record custom traits about the group, like industry or number of employees.

This is useful for tools like Intercom, Preact, and Totango, as it ties the user to a group of other users.

Example Group call:

1
analytics.group({
2
userId: '019mr8mf4r',
3
groupId: '56',
4
traits: {
5
name: 'Initech',
6
description: 'Accounting Software'
7
}
8
});

The Group call has the following fields:

FieldData typeDetails
userIdString, optionalThe ID for this user in your database. _Note: at least one of userId or anonymousId must be included in any Group call.
anonymousIdString, optionalAn ID associated with the user when you don't know who they are. For example, the anonymousId generated by analytics.js. Note: at least one of userId or anonymousId must be included in any Group call.
groupId_stringThe ID of the group.
traitsdict, optionalA dict of traits you know about the group. For a company, they might be things like name, address, or phone. Learn more about traits.
contextdict, optionalA dict containing any context about the request. To see the full reference of supported keys, check them out in the context reference.
timestampdatetime, optionalA datetime object representing when the Group call took place. If the Group call just happened, leave it out and Segment will use the server's time. If you're importing data from the past make sure you send timestamp.
integrationsdict, optionalA dictionary of destinations to enable or disable.

Find more details about Group, including the Group payload, in the Segment Spec.

The Alias call allows you to associate one identity with another. This is an advanced method and should not be widely used, but is required to manage user identities in some destinations. Other destinations do not support the Alias call.

In Mixpanel it's used to associate an anonymous user with an identified user once they sign up. For Kissmetrics, if your user switches IDs, you can use the Alias call to rename the userId.

Example Alias call:

1
analytics.alias({
2
previousId: 'old_id',
3
userId: 'new_id'
4
});

The Alias call has the following fields:

FieldData typeDetails
userIdStringThe ID for this user in your database.
previousIdStringThe previous ID to alias from.

Here's a full example of how Segment might use the Alias call:

1
// the anonymous user does actions ...
2
analytics.track({ userId: 'anonymous_user', event: 'Anonymous Event' })
3
// the anonymous user signs up and is aliased
4
analytics.alias({ previousId: 'anonymous_user', userId: 'identified@example.com' })
5
// the identified user is identified
6
analytics.identify({ userId: 'identified@example.com', traits: { plan: 'Free' } })
7
// the identified user does actions ...
8
analytics.track({ userId: 'identified@example.com', event: 'Identified Action' })

For more details about Alias, including the Alias call payload, check out the Segment Spec.


The second argument to the Analytics constructor is an optional list of settings to configure the module.

1
const analytics = new Analytics({
2
writeKey: '<MY_WRITE_KEY>',
3
host: 'https://api.segment.io',
4
path: '/v1/batch',
5
maxRetries: 3,
6
flushAt: 15,
7
flushInterval: 10000,
8
// ... and more!
9
})
SettingData typeDetails
writeKeystringThe key that corresponds to your Segment.io project
hoststringThe base URL of the API. The default is https://api.segment.io
pathstringThe API path route. The default is: "/v1/batch"
maxRetriesnumberThe number of times to retry flushing a batch. The default is: 3
flushAtnumberThe number of messages to enqueue before flushing. The default is: 15
flushIntervalnumberThe number of milliseconds to wait before flushing the queue automatically. The default is: 10000
httpRequestTimeoutnumberThe maximum number of milliseconds to wait for an http request. The default is: 10000
disablebooleanDisable the analytics library for testing. The default is: false
httpClientHTTPClient or HTTPClientFnA custom HTTP Client implementation to support alternate libraries or proxies. Defaults to global fetch or node-fetch for older versions of node. See the Overriding the default HTTP Client section for more details.

See the complete AnalyticsSettings interface in the analytics-next repository(link takes you to an external page).


Usage in serverless environments and non-node runtimes

usage-in-serverless-environments-and-non-node-runtimes page anchor

Segment supports a variety of runtimes, including, but not limited to:

  • AWS Lambda
  • Cloudflare Workers
  • Vercel Edge Functions
  • Web Workers / Browser (no device mode destination support)

AWS lambda execution environment(link takes you to an external page) is challenging for typically non-response-blocking async activities like tracking or logging, since the runtime terminates or freezes after a response is emitted.

Here is an example of using analytics.js within a handler:

1
const { Analytics } = require('@segment/analytics-node');
2
3
// Preferable to create a new analytics instance per-invocation. Otherwise, we may get a warning about overlapping flush calls. Also, custom plugins have the potential to be stateful, so we prevent those kind of race conditions.
4
const createAnalytics = () => new Analytics({
5
writeKey: '<MY_WRITE_KEY>',
6
}).on('error', console.error);
7
8
module.exports.handler = async (event) => {
9
const analytics = createAnalytics()
10
11
analytics.identify({ ... })
12
analytics.track({ ... })
13
14
// ensure analytics events get sent before program exits
15
await analytics.flush()
16
17
return {
18
statusCode: 200,
19
};
20
....
21
};

Usage in Vercel Edge Functions

usage-in-vercel-edge-functions page anchor
1
import { Analytics } from '@segment/analytics-node';
2
import { NextRequest, NextResponse } from 'next/server';
3
4
const createAnalytics = () => new Analytics({
5
writeKey: '<MY_WRITE_KEY>',
6
}).on('error', console.error)
7
8
export const config = {
9
runtime: 'edge',
10
};
11
12
export default async (req: NextRequest) => {
13
const analytics = createAnalytics()
14
15
analytics.identify({ ... })
16
analytics.track({ ... })
17
18
// ensure analytics events get sent before program exits
19
await analytics.flush()
20
21
return NextResponse.json({ ... })
22
};

Usage in Cloudflare Workers

usage-in-cloudflare-workers page anchor
1
import { Analytics, Context } from '@segment/analytics-node';
2
3
4
const createAnalytics = () => new Analytics({
5
writeKey: '<MY_WRITE_KEY>',
6
}).on('error', console.error);
7
8
export default {
9
async fetch(
10
request: Request,
11
env: Env,
12
ctx: ExecutionContext
13
): Promise<Response> {
14
const analytics = createAnalytics()
15
16
analytics.identify({ ... })
17
analytics.track({ ... })
18
19
// ensure analytics events get sent before program exits
20
await analytics.flush()
21
22
return new Response(...)
23
},
24
};
25

Avoid losing events after shutting down your console. Call .flush({ close: true }) to stop collecting new events and flush all existing events. If a callback on an event call is included, this also waits for all callbacks to be called, and any of their subsequent promises to be resolved.

1
await analytics.flush({ close: true })
2
// or
3
await analytics.flush({ close: true, timeout: 5000 }) // force resolve after 5000ms

Here's an example of how to use graceful shutdown:

1
const app = express()
2
const server = app.listen(3000)
3
4
const onExit = async () => {
5
await analytics.flush({ close: true })
6
server.close(() => {
7
console.log("Gracefully closing server...")
8
process.exit()
9
})
10
}
11
['SIGINT', 'SIGTERM'].forEach((code) => process.on(code, onExit))

Collect unflushed events

collect-unflushed-events page anchor

If you need to preserve all of your events in the instance of a forced timeout, even ones that came in after analytics.flush({ close: true }) was called, you can still collect those events by using:

1
const unflushedEvents = []
2
3
analytics.on('call_after_close', (event) => unflushedEvents.push(events))
4
await analytics.flush({ close: true })
5
6
console.log(unflushedEvents) // all events that came in after flush was called

For Business plans with access to Regional Segment, you can use the host configuration parameter to send data to the desired region:

  1. Oregon (Default) — api.segment.io/v1
  2. Dublin — eu1.api.segmentapis.com

An example of setting the host to the EU endpoint using the Node library is:

1
const analytics = new Analytics({
2
...
3
host: "https://eu1.api.segmentapis.com"
4
});

To keep track of errors, subscribe and log all event delivery errors by running:

1
const analytics = new Analytics({ writeKey: '<MY_WRITE_KEY>' })
2
3
analytics.on('error', (err) => console.error(err))

The event emitter interface allows you to pass a callback which will be invoked whenever a specific emitter event occurs in your app, such as when a certain method call is made.

For example:

1
analytics.on('track', (ctx) => console.log(ctx))
2
analytics.on('error', (err) => console.error(err))
3
4
5
// when triggered, emits an event of the shape:
6
analytics.on('http_request', (event) => console.log(event))
7
{
8
url: 'https://api.segment.io/v1/batch',
9
method: 'POST',
10
headers: {
11
'Content-Type': 'application/json',
12
...
13
},
14
body: '...',
15
}

The following table documents all the emitter types available in the Analytics Node.js library:

Emitter typeDescription
errorEmitted when there is an error after SDK initialization.
identifyEmitted when an Identify call is made.
trackEmitted when a Track call is made.
pageEmitted when a Page call is made.
groupEmitted when a Group call is made.
aliasEmitted when an Alias call is made.
flushEmitted after a batch is flushed.
http_requestEmitted when an HTTP request is made.
registerEmitted when a plugin is registered
call_after_closeEmitted when an event is received after the flush with { close: true }.

These emitters allow you to hook into various stages of the event lifecycle and handle them accordingly.


The plugins you write can improve functionality, enrich data, and control the flow and delivery of events. From modifying event payloads to changing analytics functionality, plugins help to speed up the process of getting things done.

Segment has these five entry types of plugins:

TypeDetails
beforeExecutes before event processing begins. These are plugins that run before any other plugins run. Thrown errors here can block the event pipeline. Source middleware added using addSourceMiddleware is treated as a before plugin. No events send to destinations until .load() method is resolved.
enrichmentExecutes as the first level of event processing. These plugins modify an event. Thrown errors here can block the event pipeline. No events send to destinations until .load() method is resolved.
destinationExecutes as events begin to pass off to destinations. Segment.io is implemented as a destination plugin. Thrown errors here will not block the event pipeline.
afterExecutes after all event processing completes. You can use this to perform cleanup operations.
utilityExecutes only once during the bootstrap. Gives you access to the analytics instance using the plugin's load() method. This doesn't allow you to modify events.

Here's an example of a plugin that converts all Track event names to lowercase before the event goes through the rest of the pipeline:

1
export const lowercase: Plugin = {
2
name: 'Lowercase events',
3
type: 'enrichment',
4
version: '1.0.0',
5
6
isLoaded: () => true,
7
load: () => Promise.resolve(),
8
9
track: (ctx) => {
10
ctx.updateEvent('event', ctx.event.event.toLowerCase())
11
return ctx
12
}
13
}

Registering plugins enable you to modify your analytics implementation to best fit your needs. You can register a plugin using this snippet:

1
// A promise will resolve once the plugins have been successfully loaded into Analytics.js
2
// Register multiple plugins at once by using the variable args interface in Analytics.js
3
await analytics.register(pluginA, pluginB, pluginC)

To deregister a plugin:

await analytics.deregister("pluginNameA", "pluginNameB") // takes strings

The Alias, Group, Identify, Page, and Track calls can all be passed an object of integrations that lets you turn certain destinations on or off. By default all destinations are enabled.

Here's an example with the integrations object shown:

1
analytics.track({
2
event: 'Membership Upgraded',
3
userId: '97234974',
4
integrations: {
5
'All': false,
6
'Vero': true,
7
'Google Analytics': false
8
}
9
})

In this case, Segment specifies that they want this Track event to only go to Vero. All: false says that no destination should be enabled unless otherwise specified. Vero: true turns on Vero.

Destination flags are case sensitive and match the destination's name in the docs (for example, "AdLearn Open Platform", "awe.sm", or "MailChimp"). In some cases, there may be several names for a destination; if that happens you'll see a "Adding (destination name) to the Integrations Object" section in the destination's doc page with a list of valid names.

Keep in mind:

  • Business Tier users can filter Track calls right from the Segment UI on your source schema page. We recommend using the UI if possible since it's a much simpler way of managing your filters and can be updated with no code changes on your side.
  • If you are on a grandfathered plan, events sent server-side that are filtered through the Segment dashboard still count towards your API usage.

You can import historical data by adding the timestamp argument to any of your method calls. This can be helpful if you've just switched to Segment.

Historical imports can only be done into destinations that can accept historical timestamped data. Most analytics tools like Mixpanel, Amplitude, and Kissmetrics can handle that type of data just fine. One common destination that does not accept historical data is Google Analytics since their API cannot accept historical data.

Note: If you're tracking things that are happening right now, leave out the timestamp and Segment's servers will timestamp the requests for you.


Segment's libraries are built to support high performance environments. That means it is safe to use Segment's Node library on a web server that's serving hundreds of requests per second.

Every method you call doesn't result in a HTTP request, but is queued in memory instead. Messages are then flushed in batch in the background, which allows for much faster operation.

By default, Segment's library will flush:

  • Every 15 messages (controlled by settings.flushAt).
  • If 10 seconds has passed since the last flush (controlled by settings.flushInterval)

There is a maximum of 500 KB per batch request and 32 KB per call.

If you don't want to batch messages, you can turn batching off by setting the flushAt setting to 1, like so:

1
const analytics = new Analytics({
2
...
3
flushAt: 1
4
});

Batching means that your message might not get sent right away. Every method call takes an optional callback, which you can use to know when a particular message is flushed from the queue, like so:

1
analytics.track({
2
userId: '019mr8mf4r',
3
event: 'Ultimate Played',
4
},
5
(err, ctx) => {
6
...
7
}
8
)

Different parts of your application may require different types of batching, or even sending to multiple Segment sources. In that case, you can initialize multiple instances of Analytics with different settings:

1
const marketingAnalytics = new Analytics({ writeKey: 'MARKETING_WRITE_KEY' });
2
const appAnalytics = new Analytics({ writeKey: 'APP_WRITE_KEY' });

Override the default HTTP Client

override-the-default-http-client page anchor

Segment attempts to use the global fetch implementation if available in order to support several diverse environments. Some special cases (for example, http proxy) may require a different implementation for http communication. You can provide a customized wrapper in the Analytics configuration to support this. Here are a few approaches:

Use a custom fetch-like implementation with proxy (Recommended)

1
import { HTTPFetchFn } from '../lib/http-client'
2
import axios from 'axios'
3
4
const httpClient: HTTPFetchFn = async (url, { body, ...options }) =>
5
axios({
6
url,
7
data: body,
8
proxy: {
9
protocol: 'http',
10
host: 'proxy.example.com',
11
port: 8886,
12
auth: {
13
username: 'user',
14
password: 'pass',
15
},
16
},
17
...options,
18
})
19
20
const analytics = new Analytics({
21
writeKey: '<YOUR_WRITE_KEY>',
22
httpClient,
23
})

Augment the default HTTP Client

1
import { FetchHTTPClient, HTTPClientRequest } from '@segment/analytics-node'
2
3
class MyClient extends FetchHTTPClient {
4
async makeRequest(options: HTTPClientRequest) {
5
return super.makeRequest({
6
...options,
7
headers: { ...options.headers, foo: 'bar' }
8
}})
9
}
10
}
11
12
const analytics = new Analytics({
13
writeKey: '<YOUR_WRITE_KEY>',
14
httpClient: new MyClient()
15
})

Completely override the full HTTPClient (Advanced, you probably don't need to do this)

1
import { HTTPClient, HTTPClientRequest } from '@segment/analytics-node'
2
3
class CustomClient implements HTTPClient {
4
async makeRequest(options: HTTPClientRequest) {
5
return someRequestLibrary(options.url, {
6
method: options.method,
7
body: JSON.stringify(options.data) // serialize data
8
headers: options.headers,
9
})
10
}
11
}
12
const analytics = new Analytics({
13
writeKey: '<YOUR_WRITE_KEY>',
14
httpClient: new CustomClient()
15
})

1
analytics.track({
2
anonymousId: '48d213bb-95c3-4f8d-af97-86b2b404dcfe',
3
event: 'New Test',
4
properties: {
5
revenue: 39.95,
6
shippingMethod: '2-day'
7
},
8
context: {
9
traits: {
10
"email": "test@test.com"
11
}
12
}
13
});

Enable OAuth 2.0 in your Segment workspace to guarantee authorized communication between your server environment and Segment's Tracking API. To support the non-interactive server environment, the OAuth workflow used is a signed client assertion JWT.

You will need a public and private key pair where:

  • The public key is uploaded to the Segment dashboard.
  • The private key is kept in your server environment to be used by this SDK.

Your server will verify its identity by signing a token request and will receive a token that is used to to authorize all communication with the Segment Tracking API.

You'll need to provide the OAuth Application ID and the public key's ID, both of which are provided in the Segment dashboard. There are also options available to specify the authorization server, custom scope, maximum number of retries, or a custom HTTP client if your environment has special rules for separate Segment endpoints.

Be sure to implement handling for Analytics SDK errors. Good logging helps distinguish any configuration issues.

For more information, see the Segment OAuth 2.0 documentation.

1
import { Analytics, OAuthSettings } from '@segment/analytics-node';
2
import { readFileSync } from 'fs'
3
4
const privateKey = readFileSync('private.pem', 'utf8')
5
6
const settings: OAuthSettings = {
7
clientId: '<CLIENT_ID_FROM_DASHBOARD>',
8
clientKey: privateKey,
9
keyId: '<PUB_KEY_ID_FROM_DASHBOARD>',
10
}
11
12
const analytics = new Analytics({
13
writeKey: '<MY_WRITE_KEY>',
14
oauthSettings: settings,
15
})
16
17
analytics.on('error', (err) => { console.error(err) })
18
19
analytics.track({ userId: 'foo', event: 'bar' })

The following tips often help resolve common issues.

No events in my debugger

no-events-in-my-debugger page anchor
  1. Double check that you've followed all the steps in the Quickstart.
  2. Make sure that you're calling a Segment API method once the library is successfully installed—identify, track, etc.
  3. Make sure your application isn't shutting down before the Analytics.Client local queue events are pushed to Segment. You can manually call Analytics.Client.Flush() to ensure the queue is fully processed before shutdown.

If you are experiencing data loss from your source, you may be experiencing one or more of the following common errors:

  • Payload is too large: If you attempt to send events larger than 32KB per normal API request or batches of events larger than 500KB per request, Segment's tracking API responds with 400 Bad Request. Try sending smaller events (or smaller batches) to correct this error.
  • Identifier is not present: Segment's tracking API requires that each payload has a userId and/or anonymousId. If you send events without either the userId or anonymousId, Segment's tracking API responds with an no_user_anon_id error. Check the event payload and client instrumentation for more details.
  • Track event is missing name: All Track events to Segment must have a name in string format.
  • Event dropped during deduplication: Segment automatically adds a messageId field to all payloads and uses this value to deduplicate events. If you're manually setting a messageId value, ensure that each event has a unique value.
  • Incorrect credentials: Double check your credentials for your downstream destination(s).
  • Destination incompatibility: Make sure that the destination you are troubleshooting can accept server-side API calls. You can see compatibility information on the Destination comparison by category page and in the documentation for your specific destination.
  • Destination-specific requirements: Check out the destination's documentation to see if there are other requirements for using the method and destination that you're trying to get working.