Verify Node.js SDK events
이 페이지는 아직 귀하의 언어로 번역되지 않았습니다. 현재 작업 중이므로 곧 다시 확인해 주십시오.
An event moves through four stages between your track() call and Amplitude's servers. Verify each stage in order. The first stage where the event looks wrong is where the problem is.
| Stage | Question | Where to look |
|---|---|---|
| Captured | Did the SDK accept the call? | Debug logs on standard output |
| Transformed | What did plugins add, change, or drop? | Verbose logs, or an inspection plugin |
| Sent | Did the request leave the process, and with what? | A local capture server |
| Received | Did Amplitude accept and store the event? | The upload result, then User Lookup in Amplitude |
For problems common to every Amplitude SDK, go to SDK troubleshooting and debugging. If behavior changed after an SDK upgrade, check the Node.js SDK release notes.
Turn on debug logging
Set logLevel to Debug while you verify. Debug logs include every public method call, the SDK's state before and after it, each event as plugins change it, and the upload result.
import { init, track, Types } from "@amplitude/analytics-node";
init("AMPLITUDE_API_KEY", {
logLevel: Types.LogLevel.Debug,
});
track("Sign Up Completed", { plan: "starter" }, { user_id: "user-12345" });
The levels are 0 None, 1 Error, 2 Warn (default), 3 Verbose, and 4 Debug. Each message starts with Amplitude Logger. The default logger writes errors with console.error, warnings with console.warn, and Verbose and Debug messages with console.log. Filter both standard output and standard error on that prefix.
Debug logs contain your API key
At the Debug level, the SDK logs its configuration, including the API key, and every event payload. Return logLevel to Warn before you deploy, and don't ship Debug logs to a shared log store.
Check what the SDK captured
With debug logging on, each public call prints a block like this:
Amplitude Logger [Debug]: {
"type": "invoke public method",
"name": "track",
"args": ["Sign Up Completed", { "plan": "starter" }, { "user_id": "user-12345" }],
"stacktrace": ["at file:///srv/app/signup.mjs:6:7", "..."],
"time": { "start": "2026-11-10T19:47:54.361Z", "end": "2026-11-10T19:48:04.383Z" },
"states": {
"before": { "config.apiKey": "...", "timeline.queue.length": 0 },
"after": { "config.apiKey": "...", "timeline.queue.length": 0 }
}
}
For methods that return a promise, such as track(), identify(), and flush(), the SDK prints the block after the promise resolves. A track block therefore appears after the upload attempt, about 10 seconds after the call.
Check the block for these problems:
| What you see | What it means |
|---|---|
No track block | The call never ran, or the upload never finished. Check that the code path runs, and that the process stays alive until the next upload. |
No user_id or device_id in args | Amplitude rejects the event. Pass one of them in the third argument. |
Event skipped due to optOut config before it | Opt-out is on for this instance. Go to Opt out of tracking. |
Event skipped due to empty event type before it | The event name is empty or not a string. |
Check how plugins transformed the event
At Verbose or Debug level, the SDK logs the event after each before and enrichment plugin, then the final event it hands to destinations:
Amplitude Logger [Log]: Timeline.apply: Event after before plugin 'context', event: {"time":1794340064240,"insert_id":"9dfa11d7-...","event_type":"Sign Up Completed","user_id":"user-12345",...}
Amplitude Logger [Log]: Timeline.apply: Final event before destinations, event: {...}
A plugin that returns null drops the event, and the log shows Event filtered out by with the plugin's name. The built-in context plugin adds time, insert_id, event_id, and library to every event.
To inspect events in code, add an enrichment plugin after init(). Enrichment plugins run after the built-in context plugin, so your plugin sees the fields the SDK added:
import { init, add, track } from "@amplitude/analytics-node";
await init("AMPLITUDE_API_KEY").promise;
add({
name: "inspect-events",
type: "enrichment",
execute: async (event) => {
console.log("Amplitude event:", JSON.stringify(event));
return event;
},
});
track("Sign Up Completed", { plan: "starter" }, { user_id: "user-12345" });
The plugin prints the event as the SDK sends it:
{
"event_type": "Sign Up Completed",
"user_id": "user-12345",
"event_properties": { "plan": "starter" },
"time": 1794340064240,
"insert_id": "9dfa11d7-2592-47b5-ba83-a599db8f8536",
"event_id": 0,
"library": "amplitude-node-ts/1.5.83"
}
event_id is a counter that starts at 0 for each SDK instance. The SDK overwrites any event_id or library value you pass. Remove the inspection plugin when you finish, so event payloads don't reach your production logs.
Check what the SDK sent
A server process has no Network tab. To see the exact request body, point serverUrl at a local server that prints each request and answers like Amplitude:
// capture-server.mjs: run with node capture-server.mjs
import http from "node:http";
http
.createServer((req, res) => {
let body = "";
req.on("data", (chunk) => (body += chunk));
req.on("end", () => {
console.log(req.method, req.url, body);
const events = JSON.parse(body).events ?? [];
res.writeHead(200, { "Content-Type": "application/json" });
res.end(
JSON.stringify({
code: 200,
events_ingested: events.length,
payload_size_bytes: body.length,
server_upload_time: Date.now(),
}),
);
});
})
.listen(8080);
Then send events to it:
import { init, track } from "@amplitude/analytics-node";
init("AMPLITUDE_API_KEY", {
serverUrl: "http://localhost:8080/2/httpapi",
});
track("Sign Up Completed", { plan: "starter" }, { user_id: "user-12345" });
The server prints one POST /2/httpapi request per upload, with a body like this:
{
"api_key": "AMPLITUDE_API_KEY",
"events": [
{
"time": 1794340064240,
"insert_id": "9dfa11d7-2592-47b5-ba83-a599db8f8536",
"event_type": "Sign Up Completed",
"user_id": "user-12345",
"event_properties": { "plan": "starter" },
"event_id": 0,
"library": "amplitude-node-ts/1.5.83"
}
],
"options": {},
"client_upload_time": "2026-11-10T19:48:04.374Z"
}
The SDK sends plain JSON. It doesn't compress request bodies. options.min_id_length appears only when you set minIdLength. Remove serverUrl when you finish, so events go to Amplitude again.
Check what Amplitude received
Read the upload result
track(), identify(), groupIdentify(), setGroup(), and revenue() return an object whose promise resolves to a result with event, code, and message:
import { init, track } from "@amplitude/analytics-node";
init("AMPLITUDE_API_KEY");
const result = await track(
"Sign Up Completed",
{ plan: "starter" },
{ user_id: "user-12345" },
).promise;
console.log(result.code, result.message);
code | message | Meaning |
|---|---|---|
200 | Event tracked successfully | Amplitude accepted the event on a scheduled upload. |
200 | success: {...}, with the server's JSON response | Amplitude accepted the event on an upload that flush() started. |
0 | Event skipped due to optOut config | Opt-out is on. The SDK sent nothing. |
0 | Event skipped due to empty event type | The event name is empty. The SDK sent nothing. Requires 1.5.70 or later. |
0 | Empty string | A before or enrichment plugin returned null and dropped the event. |
0 | Unexpected error occurred | The request never reached a server. The SDK doesn't retry these. |
100 | Event not tracked, no destination plugins on the instance | No destination ran. Usually flush() ran before init() finished. |
400 | Event rejected due to missing API key | init() received an empty key. |
400 | The server's error, such as Request missing required field | Amplitude rejected this event. The SDK retries other events in the request. |
413 | The server's error | A single event is larger than Amplitude accepts. |
429 | The server's error | The user or device exceeded Amplitude's daily event quota. |
500 | Event rejected due to exceeded retry count | Every attempt failed. The SDK made flushMaxRetries attempts. |
For how the SDK retries each status, go to How the SDK uploads events.
Find the event in Amplitude
- In Amplitude, open User Lookup and search for the
user_idordevice_idyou sent. - Open the Activity tab and turn on Live event updates.
- Find the event by name, and confirm its properties.
If the upload result is 200 but the event doesn't appear, check these settings:
- The API key belongs to the project you're viewing.
- The project's data center matches
serverZone.
이 내용이 도움이 되었나요?
For AI agents: a documentation index is available at /docs/llms.txt. Append .md to any page URL for markdown, or send Accept: text/markdown.