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.
Get started with Browser SDK 2
This guide helps you install Browser SDK 2 (@amplitude/analytics-browser), initialize it, and send one custom event to Amplitude. Each step lists the browser conditions that commonly break that step, so you can fix a problem where it happens. For the full option list, go to Configuration options.
Browser SDK 2 is the analytics-only package. If you also need Session Replay, Feature Experiment, or Guides and Surveys, install the Browser Unified SDK (@amplitude/unified) instead. It includes Browser SDK 2, so don't install both packages on the same page.
Prerequisites
- An Amplitude project and its API key. Find the key in Settings > Projects > your project > General.
- The data center your organization uses: US (default) or EU.
- The latest Browser SDK 2 release, or a pinned version you check against the Browser SDK 2 release notes for the features you use.
- A page served over
http://orhttps://. Pages opened fromfile://can't set cookies, so the SDK can't persist identity between loads.
Install the SDK
Choose one installation method. Use npm or yarn if you bundle your JavaScript. Use the script loader if you add tags to HTML directly or through a tag manager.
npm install @amplitude/analytics-browser
import * as amplitude from "@amplitude/analytics-browser";
To use the Unified SDK instead, install @amplitude/unified with npm install @amplitude/unified or yarn add @amplitude/unified, and import it the same way:
import * as amplitude from "@amplitude/unified";
The Unified package exports the same tracking and identity methods, such as track() and setUserId(), but not init(). Call initAll() instead, and pass the analytics options from this guide under analytics:
amplitude.initAll("YOUR_API_KEY", {
serverZone: "EU", // Omit for US projects.
analytics: { autocapture: true },
});
initAll() doesn't accept a user ID argument. Call setUserId() after it.
Fix installation problems
| Symptom | Cause | Fix |
|---|---|---|
amplitude is not defined in the console (script loader) | The snippet loads after your code runs, or a Content Security Policy blocks it. | Place the snippet before any code that calls amplitude. Add https://*.amplitude.com to script-src. |
net::ERR_BLOCKED_BY_CLIENT for the SDK script | An ad blocker or privacy extension blocks the CDN. | Install from npm and bundle the SDK with your code, or test in a profile without extensions. |
Two amplitude globals, or events sent twice | The page loads both this snippet and the Unified Script or @amplitude/unified. | Keep one Amplitude entry point per page. |
Initialize the SDK
Call init() once, as early as your app has the context it needs, such as a known user ID. Calls you make before init() finishes wait in a queue and run in order after it completes.
amplitude.init("YOUR_API_KEY", {
autocapture: true,
});
Pass a user ID as the second argument when you already know it:
amplitude.init("YOUR_API_KEY", "user-12345", {
autocapture: true,
});
If your project uses the EU data center, set serverZone:
amplitude.init("YOUR_API_KEY", {
serverZone: "EU",
autocapture: true,
});
autocapture: true turns on every autocapture feature that the SDK enables with a boolean, including element clicks, frustration interactions, failed network requests, and web vitals. To start with only the default set (page views, sessions, attribution, forms, and file downloads), omit autocapture or pass an object. For choices, go to Autocapture.
Fix initialization problems
| Symptom | Cause | Fix |
|---|---|---|
Console warning: `options.defaultTracking` is set to undefined | You didn't set autocapture (or the deprecated defaultTracking). | Not an error. Set autocapture explicitly to silence it. |
| Errors during server-side rendering, or no events from server-rendered pages | init() runs on the server (Next.js, Nuxt, SvelteKit, Remix). | Call init() only in browser code, for example in a client component or a useEffect. Go to the Next.js installation guide. |
Clicks or inputs stop working after init() in an Angular app | Zone.js wraps DOM APIs that autocapture also patches. | Call init() in main.ts before bootstrapApplication, or inside NgZone.runOutsideAngular(). |
| No page views, sessions, or attribution in a Chrome extension | In a Chrome extension, the SDK turns off default autocapture unless you enable each feature. This default changed in 2.42.1. | Set each feature explicitly, for example autocapture: { pageViews: true, sessions: true }. |
| Identity resets on every page load | The browser blocks cookies (private mode, strict tracking protection, or a sandboxed iframe), or the page runs on file://. | Serve the page over HTTP(S). If cookies stay blocked, set identityStorage: "localStorage". |
Events go to the wrong region, or ingestion returns Invalid API key | serverZone doesn't match the project's data center. | Set serverZone: "EU" for EU projects. Omit it for US projects. |
Send a first event
Track one custom event and wait for the upload result. track() returns an object whose promise resolves after the SDK finishes the upload attempt.
const result = await amplitude.track("Sign Up Clicked", {
plan: "starter",
}).promise;
console.log(result.code, result.message);
// 200 "Event tracked successfully"
The SDK uploads queued events about one second after the first one enters the queue, in requests of up to 30 events. The promise resolves after that upload, so expect about one second of delay.
Fix upload problems
result.code and result.message | Cause | Fix |
|---|---|---|
0, Event skipped due to optOut config | Opt-out is on for this browser. The SDK stores opt-out in its cookie, so it persists across loads. | Call amplitude.setOptOut(false), or clear the AMP_ cookies for your domain. |
0, Event skipped due to empty event type | The event name is empty or not a string. | Pass a non-empty string as the first argument. |
400, Event rejected due to missing API key | init() received an empty API key. | Check the variable that holds your key. Build tools often inline an empty value when an environment variable is missing. |
400, Invalid API key: ... | The key is wrong, or belongs to a project in the other data center. | Copy the key again and check serverZone. |
500, Event rejected due to exceeded retry count, after about 10 seconds | The request never reached Amplitude, and the SDK gave up after five attempts. Ad blockers, a Content Security Policy, CORS on a proxy, or a server error cause this. | Open the browser Network tab and check the request to api2.amplitude.com (or api.eu.amplitude.com). Add https://*.amplitude.com to connect-src. If an ad blocker blocks the request, route traffic through a proxy. |
| The promise never resolves | init() never ran on this instance, so the call is still queued. | Make sure init() runs before or after the call on the same instance, and that it isn't inside a branch that skips it. |
The event disappears when the page navigates right after track() | The browser canceled the request when the page unloaded. | Keep the default fetch transport, which sends with keepalive. For large payloads, go to Send events when the page unloads. |
Confirm the event in Amplitude
- In Amplitude, open User Lookup and search for the user ID you passed, or for the device ID from
amplitude.getDeviceId(). - Open the Activity tab and turn on Live event updates.
- Confirm that
Sign Up Clickedappears with theplanproperty.
If the event doesn't appear within a minute, follow Verify events. It walks through each stage between track() and Amplitude's servers.
Next steps
- Identify signed-in users with
setUserId(), and callreset()when they sign out. - Choose which Autocapture events to keep.
- Add the custom events and properties your tracking plan needs. Go to Track events.
Was this helpful?