Overview
Amplitude is a product analytics platform that helps teams understand user behavior through event tracking and analysis. The Amplitude SDK ecosystem supports web, mobile, and server-side implementations with automatic session tracking, user identification, and attribution capture. This comprehensive guide covers all deployment methods to help you instrument Amplitude across your entire digital ecosystem.
Amplitude offers multiple SDKs optimized for different platforms: Browser SDK for web applications, iOS/Android SDKs for native mobile apps, and HTTP API for server-side tracking. Each SDK provides automatic event tracking capabilities alongside manual instrumentation for custom events.
Prerequisites
Before installing Amplitude, ensure you have:
- Amplitude Account: Active account with appropriate plan (Free, Growth, or Enterprise)
- API Key: Found in Settings > Projects > [Your Project] (format: 32-character alphanumeric string)
- Project Selection: Separate projects for dev, staging, and production recommended
- Data Taxonomy: Documented event names and property schemas (naming conventions)
- User ID Strategy: Plan for how users will be identified (user_id vs device_id)
- Consent Management: Cookie consent implementation if required by privacy regulations
Finding Your API Key
- Log into Amplitude at https://analytics.amplitude.com
- Navigate to Settings (gear icon) > Projects
- Select your project
- Copy the API Key from the project details
- For EU data residency, note the EU endpoint requirement
API Key Security: While Amplitude API keys are used client-side, avoid exposing them in public repositories. Use environment variables for different deployment environments.
Installation Methods
Method 1: NPM Package Installation (Recommended for Modern Web Apps)
The npm package provides the best developer experience with TypeScript support and tree-shaking capabilities.
Installation
npm install @amplitude/analytics-browser
# or
yarn add @amplitude/analytics-browser
# or
pnpm add @amplitude/analytics-browser
Basic Implementation
// src/analytics/amplitude.js
import * as amplitude from '@amplitude/analytics-browser';
// Initialize Amplitude
amplitude.init('YOUR_API_KEY', {
defaultTracking: {
sessions: true,
pageViews: true,
formInteractions: false,
fileDownloads: true
},
serverUrl: 'https://api2.amplitude.com/2/httpapi', // Use EU endpoint if required
minIdLength: 5,
partnerId: 'your-partner-id', // Optional
sessionTimeout: 30 * 60 * 1000, // 30 minutes
trackingOptions: {
ipAddress: true,
language: true,
platform: true
}
});
// Track page view
amplitude.track('Page Viewed', {
page: window.location.pathname,
title: document.title,
referrer: document.referrer
});
export default amplitude;
Environment-Specific Configuration
// src/config/amplitude.config.js
const getAmplitudeConfig = () => {
const environment = process.env.NODE_ENV;
const apiKeys = {
development: process.env.REACT_APP_AMPLITUDE_API_KEY_DEV,
staging: process.env.REACT_APP_AMPLITUDE_API_KEY_STAGING,
production: process.env.REACT_APP_AMPLITUDE_API_KEY_PROD
};
return {
apiKey: apiKeys[environment],
defaultTracking: {
sessions: true,
pageViews: true,
formInteractions: environment === 'production',
fileDownloads: true
},
logLevel: environment === 'production' ? amplitude.Types.LogLevel.Warn : amplitude.Types.LogLevel.Verbose,
serverZone: 'US', // or 'EU'
useBatch: true,
flushIntervalMillis: 10000,
flushQueueSize: 30
};
};
export default getAmplitudeConfig;
Usage Example
import * as amplitude from '@amplitude/analytics-browser';
import getAmplitudeConfig from './config/amplitude.config';
// Initialize
const config = getAmplitudeConfig();
amplitude.init(config.apiKey, config);
// Track event
amplitude.track('Button Clicked', {
buttonName: 'Sign Up',
location: 'Header',
timestamp: Date.now()
});
// Identify user
amplitude.setUserId('user-123');
// Set user properties
const identifyEvent = new amplitude.Identify();
identifyEvent.set('plan', 'premium');
identifyEvent.set('age', 25);
identifyEvent.add('loginCount', 1);
amplitude.identify(identifyEvent);
Method 2: Direct Script Tag (CDN)
For simpler implementations or non-bundled websites:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Your Website</title>
<!-- Amplitude SDK -->
<script type="text/javascript">
!function(){"use strict";!function(e,t){var r=e.amplitude||{_q:[],_iq:{}};if(r.invoked)e.console&&console.error&&console.error("Amplitude snippet has been loaded.");else{r.invoked=!0;var n=t.createElement("script");n.type="text/javascript",n.integrity="sha384-x0ik2D45ZDEEEpYpEuDpmj05YY2jEvsdG+FLOw8LkJI4LI/Djj1+qMqAr/AqWXpS",n.crossOrigin="anonymous",n.async=!0,n.src="https://cdn.amplitude.com/libs/analytics-browser-2.0.1-min.js.gz",n.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var s=t.getElementsByTagName("script")[0];s.parentNode.insertBefore(n,s);for(var o=function(){return this._q=[],this},i=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],a=0;a<i.length;a++)o.prototype[i[a]]=function(e){return function(){return this._q.push({name:e,args:Array.prototype.slice.call(arguments,0)}),this}}(i[a]);r.Identify=o;for(var c=function(){this._q=[];return this},u=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],l=0;l<u.length;l++)c.prototype[u[l]]=function(e){return function(){return this._q.push({name:e,args:Array.prototype.slice.call(arguments,0)}),this}}(u[l]);r.Revenue=c;var p=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset","extendSession"],d=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];function v(e){function t(t,r){e[t]=function(){var n={promise:new Promise((r=>{e._q.push({name:t,args:Array.prototype.slice.call(arguments,0),resolve:r})}))};if(r)return n}}for(var r=0;r<p.length;r++)t(p[r],!1);for(var n=0;n<d.length;n++)t(d[n],!0)}v(r),r.createInstance=function(){var e=r._iq[++r._iqc]={_q:[]};return v(e),e},r._iqc=0,e.amplitude=r}}(window,document)}();
// Initialize Amplitude
amplitude.init('YOUR_API_KEY', {
defaultTracking: {
sessions: true,
pageViews: true,
formInteractions: false,
fileDownloads: true
}
});
// Track page view
amplitude.track('Page Viewed', {
page: window.location.pathname,
title: document.title
});
</script>
</head>
<body>
<h1>Your Content</h1>
<button Me</button>
<script>
function trackButtonClick() {
amplitude.track('Button Clicked', {
buttonName: 'CTA Button',
location: 'Hero Section'
});
}
</script>
</body>
</html>
EU Data Residency
amplitude.init('YOUR_API_KEY', {
serverZone: 'EU', // Routes data to EU servers
serverUrl: 'https://api.eu.amplitude.com/2/httpapi'
});
Method 3: Google Tag Manager Integration
Deploy Amplitude through GTM for centralized tag management:
Step 1: Create Custom HTML Tag
<!-- GTM Tag: Amplitude - Initialize -->
<script>
(function() {
// Load Amplitude SDK if not already loaded
if (typeof amplitude === 'undefined') {
!function(){"use strict";!function(e,t){var r=e.amplitude||{_q:[],_iq:{}};if(r.invoked)e.console&&console.error&&console.error("Amplitude snippet has been loaded.");else{r.invoked=!0;var n=t.createElement("script");n.type="text/javascript",n.integrity="sha384-x0ik2D45ZDEEEpYpEuDpmj05YY2jEvsdG+FLOw8LkJI4LI/Djj1+qMqAr/AqWXpS",n.crossOrigin="anonymous",n.async=!0,n.src="https://cdn.amplitude.com/libs/analytics-browser-2.0.1-min.js.gz",n.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var s=t.getElementsByTagName("script")[0];s.parentNode.insertBefore(n,s);for(var o=function(){return this._q=[],this},i=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],a=0;a<i.length;a++)o.prototype[i[a]]=function(e){return function(){return this._q.push({name:e,args:Array.prototype.slice.call(arguments,0)}),this}}(i[a]);r.Identify=o;for(var c=function(){this._q=[];return this},u=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],l=0;l<u.length;l++)c.prototype[u[l]]=function(e){return function(){return this._q.push({name:e,args:Array.prototype.slice.call(arguments,0)}),this}}(u[l]);r.Revenue=c;var p=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset","extendSession"],d=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];function v(e){function t(t,r){e[t]=function(){var n={promise:new Promise((r=>{e._q.push({name:t,args:Array.prototype.slice.call(arguments,0),resolve:r})}))};if(r)return n}}for(var r=0;r<p.length;r++)t(p[r],!1);for(var n=0;n<d.length;n++)t(d[n],!0)}v(r),r.createInstance=function(){var e=r._iq[++r._iqc]={_q:[]};return v(e),e},r._iqc=0,e.amplitude=r}}(window,document)}();
}
// Initialize with API key from GTM variable
amplitude.init({{Amplitude API Key}}, {
defaultTracking: {
sessions: true,
pageViews: false, // Handle manually for better control
formInteractions: false,
fileDownloads: true
},
logLevel: {{Environment}} === 'production' ? 2 : 1
});
})();
</script>
Trigger: All Pages (pageview) - Fire once per page
Step 2: Create Variables
Create the following GTM Variables:
Amplitude API Key (Constant)
- Type: Constant String
- Value: Your API key
Environment (Custom JavaScript)
function() { return {{Page Hostname}}.includes('localhost') ? 'development' : {{Page Hostname}}.includes('staging') ? 'staging' : 'production'; }
Step 3: Create Event Tracking Tag
<!-- GTM Tag: Amplitude - Track Event -->
<script>
amplitude.track({{Event Name}}, {
category: {{Event Category}},
label: {{Event Label}},
value: {{Event Value}},
page: {{Page Path}},
timestamp: Date.now()
});
</script>
Trigger: Custom Event (e.g., button_click, form_submit)
Step 4: Create User Identification Tag
<!-- GTM Tag: Amplitude - Identify User -->
<script>
(function() {
var userId = {{User ID}};
if (userId) {
amplitude.setUserId(userId);
var identifyEvent = new amplitude.Identify();
identifyEvent.set('email', {{User Email}});
identifyEvent.set('plan', {{User Plan}});
identifyEvent.set('signupDate', {{User Signup Date}});
amplitude.identify(identifyEvent);
}
})();
</script>
Trigger: User Login (custom event)
Method 4: Tag Management System (Tealium/Segment)
If you're using another TMS, you can wrap Amplitude similarly:
// Tealium Custom Container Tag
(function() {
if (typeof amplitude === 'undefined') {
// Load SDK...
}
amplitude.init(utag_data.amplitude_api_key, {
defaultTracking: true
});
// Track from utag_data
if (utag_data.event_name) {
amplitude.track(utag_data.event_name, utag_data.event_properties || {});
}
})();
Framework-Specific Implementations
React Implementation
Installation
npm install @amplitude/analytics-browser
Create Analytics Context
// src/context/AmplitudeContext.jsx
import React, { createContext, useContext, useEffect } from 'react';
import * as amplitude from '@amplitude/analytics-browser';
const AmplitudeContext = createContext(null);
export const AmplitudeProvider = ({ children, config }) => {
useEffect(() => {
// Initialize Amplitude
amplitude.init(config.apiKey, {
defaultTracking: config.defaultTracking || {
sessions: true,
pageViews: true,
formInteractions: false,
fileDownloads: true
},
logLevel: config.logLevel || amplitude.Types.LogLevel.Warn,
serverZone: config.serverZone || 'US'
});
return () => {
// Flush events on unmount
amplitude.flush();
};
}, [config]);
return (
<AmplitudeContext.Provider value={amplitude}>
{children}
</AmplitudeContext.Provider>
);
};
export const useAmplitude = () => {
const context = useContext(AmplitudeContext);
if (!context) {
throw new Error('useAmplitude must be used within AmplitudeProvider');
}
return context;
};
App Integration
// src/App.js
import React from 'react';
import { AmplitudeProvider } from './context/AmplitudeContext';
const amplitudeConfig = {
apiKey: process.env.REACT_APP_AMPLITUDE_API_KEY,
defaultTracking: {
sessions: true,
pageViews: true
},
logLevel: process.env.NODE_ENV === 'production' ? 2 : 1
};
function App() {
return (
<AmplitudeProvider config={amplitudeConfig}>
<div className="App">
{/* Your app components */}
</div>
</AmplitudeProvider>
);
}
export default App;
Custom Hook for Tracking
// src/hooks/useAmplitudeTrack.js
import { useCallback } from 'react';
import { useAmplitude } from '../context/AmplitudeContext';
export const useAmplitudeTrack = () => {
const amplitude = useAmplitude();
const trackEvent = useCallback((eventName, eventProperties = {}) => {
amplitude.track(eventName, {
...eventProperties,
timestamp: Date.now(),
page: window.location.pathname
});
}, [amplitude]);
const identifyUser = useCallback((userId, userProperties = {}) => {
amplitude.setUserId(userId);
const identify = new amplitude.Identify();
Object.entries(userProperties).forEach(([key, value]) => {
identify.set(key, value);
});
amplitude.identify(identify);
}, [amplitude]);
const setUserProperty = useCallback((property, value) => {
const identify = new amplitude.Identify();
identify.set(property, value);
amplitude.identify(identify);
}, [amplitude]);
const incrementUserProperty = useCallback((property, value = 1) => {
const identify = new amplitude.Identify();
identify.add(property, value);
amplitude.identify(identify);
}, [amplitude]);
return {
trackEvent,
identifyUser,
setUserProperty,
incrementUserProperty
};
};
Component Usage
// src/components/SignupButton.jsx
import React from 'react';
import { useAmplitudeTrack } from '../hooks/useAmplitudeTrack';
function SignupButton() {
const { trackEvent } = useAmplitudeTrack();
const handleClick = () => {
trackEvent('Signup Button Clicked', {
buttonLocation: 'Header',
buttonColor: 'blue',
userType: 'new_visitor'
});
// Proceed with signup logic
};
return (
<button className="signup-btn">
Sign Up
</button>
);
}
export default SignupButton;
React Router Integration
// src/App.js
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { useAmplitudeTrack } from './hooks/useAmplitudeTrack';
function App() {
const location = useLocation();
const { trackEvent } = useAmplitudeTrack();
useEffect(() => {
// Track page view on route change
trackEvent('Page Viewed', {
page: location.pathname,
search: location.search,
hash: location.hash,
title: document.title
});
}, [location, trackEvent]);
return (
<Routes>
{/* Your routes */}
</Routes>
);
}
Next.js Implementation
// pages/_app.js
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import * as amplitude from '@amplitude/analytics-browser';
function MyApp({ Component, pageProps }) {
const router = useRouter();
useEffect(() => {
// Initialize Amplitude (client-side only)
if (typeof window !== 'undefined') {
amplitude.init(process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY, {
defaultTracking: {
sessions: true,
pageViews: false, // Handle manually
formInteractions: false,
fileDownloads: true
}
});
}
}, []);
useEffect(() => {
const handleRouteChange = (url) => {
amplitude.track('Page Viewed', {
page: url,
title: document.title,
referrer: document.referrer
});
};
// Track initial page view
handleRouteChange(router.pathname);
// Track route changes
router.events.on('routeChangeComplete', handleRouteChange);
return () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}, [router]);
return <Component {...pageProps} />;
}
export default MyApp;
// Create utility file: lib/amplitude.js
import * as amplitude from '@amplitude/analytics-browser';
export const trackEvent = (eventName, eventProperties = {}) => {
if (typeof window !== 'undefined') {
amplitude.track(eventName, eventProperties);
}
};
export const identifyUser = (userId, userProperties = {}) => {
if (typeof window !== 'undefined') {
amplitude.setUserId(userId);
const identify = new amplitude.Identify();
Object.entries(userProperties).forEach(([key, value]) => {
identify.set(key, value);
});
amplitude.identify(identify);
}
};
// Usage in page or component
import { trackEvent } from '../lib/amplitude';
export default function Home() {
const handleButtonClick = () => {
trackEvent('CTA Clicked', {
location: 'Homepage Hero',
buttonText: 'Get Started'
});
};
return <button Started</button>;
}
Vue.js Implementation
// src/plugins/amplitude.js
import * as amplitude from '@amplitude/analytics-browser';
export default {
install: (app, options) => {
// Initialize Amplitude
amplitude.init(options.apiKey, {
defaultTracking: options.defaultTracking || {
sessions: true,
pageViews: true
},
logLevel: options.logLevel || amplitude.Types.LogLevel.Warn
});
// Add global properties
app.config.globalProperties.$amplitude = {
track: (eventName, eventProperties = {}) => {
amplitude.track(eventName, eventProperties);
},
identify: (userId, userProperties = {}) => {
amplitude.setUserId(userId);
const identify = new amplitude.Identify();
Object.entries(userProperties).forEach(([key, value]) => {
identify.set(key, value);
});
amplitude.identify(identify);
},
setUserProperty: (property, value) => {
const identify = new amplitude.Identify();
identify.set(property, value);
amplitude.identify(identify);
}
};
// Provide for Composition API
app.provide('amplitude', app.config.globalProperties.$amplitude);
}
};
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import amplitudePlugin from './plugins/amplitude';
const app = createApp(App);
app.use(router);
app.use(amplitudePlugin, {
apiKey: import.meta.env.VITE_AMPLITUDE_API_KEY,
defaultTracking: {
sessions: true,
pageViews: false // Handle manually via router
}
});
// Track page views on route change
router.afterEach((to) => {
app.config.globalProperties.$amplitude.track('Page Viewed', {
page: to.path,
title: to.meta.title || document.title,
params: to.params
});
});
app.mount('#app');
// Usage in component (Options API)
export default {
methods: {
handleClick() {
this.$amplitude.track('Button Clicked', {
buttonName: 'Submit',
page: this.$route.path
});
}
}
};
// Usage in component (Composition API)
import { inject } from 'vue';
export default {
setup() {
const amplitude = inject('amplitude');
const handleClick = () => {
amplitude.track('Button Clicked', {
buttonName: 'Submit'
});
};
return { handleClick };
}
};
Angular Implementation
// src/app/services/amplitude.service.ts
import { Injectable } from '@angular/core';
import * as amplitude from '@amplitude/analytics-browser';
import { environment } from '../../environments/environment';
@Injectable({
providedIn: 'root'
})
export class AmplitudeService {
private initialized = false;
constructor() {
this.init();
}
private init(): void {
if (this.initialized) return;
amplitude.init(environment.amplitudeApiKey, {
defaultTracking: {
sessions: true,
pageViews: false, // Handle manually via router
formInteractions: false,
fileDownloads: true
},
logLevel: environment.production
? amplitude.Types.LogLevel.Warn
: amplitude.Types.LogLevel.Verbose
});
this.initialized = true;
}
trackEvent(eventName: string, eventProperties?: Record<string, any>): void {
amplitude.track(eventName, {
...eventProperties,
timestamp: Date.now()
});
}
identifyUser(userId: string, userProperties?: Record<string, any>): void {
amplitude.setUserId(userId);
if (userProperties) {
const identify = new amplitude.Identify();
Object.entries(userProperties).forEach(([key, value]) => {
identify.set(key, value);
});
amplitude.identify(identify);
}
}
setUserProperty(property: string, value: any): void {
const identify = new amplitude.Identify();
identify.set(property, value);
amplitude.identify(identify);
}
incrementProperty(property: string, value: number = 1): void {
const identify = new amplitude.Identify();
identify.add(property, value);
amplitude.identify(identify);
}
reset(): void {
amplitude.reset();
}
}
// src/app/app.component.ts
import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
import { AmplitudeService } from './services/amplitude.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
constructor(
private router: Router,
private amplitude: AmplitudeService
) {}
ngOnInit(): void {
// Track page views on navigation
this.router.events
.pipe(filter(event => event instanceof NavigationEnd))
.subscribe((event: NavigationEnd) => {
this.amplitude.trackEvent('Page Viewed', {
page: event.url,
title: document.title
});
});
}
}
// Usage in component
import { Component } from '@angular/core';
import { AmplitudeService } from '../services/amplitude.service';
@Component({
selector: 'app-signup',
template: `<button (click)="handleSignup()">Sign Up</button>`
})
export class SignupComponent {
constructor(private amplitude: AmplitudeService) {}
handleSignup(): void {
this.amplitude.trackEvent('Signup Initiated', {
source: 'landing_page',
buttonLocation: 'hero'
});
// Signup logic...
}
}
// environment.ts
export const environment = {
production: false,
amplitudeApiKey: 'your-dev-api-key'
};
// environment.prod.ts
export const environment = {
production: true,
amplitudeApiKey: 'your-prod-api-key'
};
Mobile & OTT SDKs
iOS Implementation (Swift)
// Install via CocoaPods
// Podfile
platform :ios, '13.0'
use_frameworks!
target 'YourApp' do
pod 'AmplitudeSwift', '~> 1.0'
end
// Install via Swift Package Manager
// Add package: https://github.com/amplitude/Amplitude-Swift
// AppDelegate.swift
import UIKit
import AmplitudeSwift
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var amplitude: Amplitude!
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Initialize Amplitude
amplitude = Amplitude(
configuration: Configuration(
apiKey: "YOUR_API_KEY",
defaultTracking: DefaultTrackingOptions(
sessions: true,
appLifecycles: true,
screenViews: true
),
logLevel: .LOG,
minIdLength: 5,
partnerId: nil,
flushQueueSize: 30,
flushIntervalMillis: 30000,
instanceName: nil,
optOut: false,
storageProvider: nil,
identifyBatchIntervalMillis: 30000,
flushMaxRetries: 5,
serverZone: .US, // or .EU
serverUrl: nil,
useBatch: false,
trackingOptions: TrackingOptions()
)
)
return true
}
}
// Track event
import AmplitudeSwift
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Get Amplitude instance
let amplitude = (UIApplication.shared.delegate as! AppDelegate).amplitude
// Track event
amplitude.track(
eventType: "Screen Viewed",
eventProperties: [
"screenName": "Home",
"category": "main"
]
)
}
@IBAction func buttonTapped(_ sender: UIButton) {
let amplitude = (UIApplication.shared.delegate as! AppDelegate).amplitude
amplitude.track(
eventType: "Button Clicked",
eventProperties: [
"buttonName": sender.titleLabel?.text ?? "Unknown",
"screenName": "Home"
]
)
}
}
// Identify user
func identifyUser(userId: String, email: String, plan: String) {
let amplitude = (UIApplication.shared.delegate as! AppDelegate).amplitude
amplitude.setUserId(userId: userId)
let identify = Identify()
identify.set(property: "email", value: email)
identify.set(property: "plan", value: plan)
identify.set(property: "signupDate", value: ISO8601DateFormatter().string(from: Date()))
amplitude.identify(identify: identify)
}
// Track revenue
func trackPurchase(productId: String, price: Double, quantity: Int) {
let amplitude = (UIApplication.shared.delegate as! AppDelegate).amplitude
let revenue = Revenue()
revenue.productId = productId
revenue.price = price
revenue.quantity = quantity
amplitude.revenue(revenue: revenue)
}
// Group identification
func setUserGroup(groupType: String, groupName: String) {
let amplitude = (UIApplication.shared.delegate as! AppDelegate).amplitude
amplitude.setGroup(groupType: groupType, groupName: groupName)
}
Android Implementation (Kotlin)
// build.gradle (project level)
allprojects {
repositories {
google()
mavenCentral()
}
}
// build.gradle (app level)
dependencies {
implementation 'com.amplitude:analytics-android:1.+'
}
// MainApplication.kt
import android.app.Application
import com.amplitude.android.Amplitude
import com.amplitude.android.Configuration
import com.amplitude.android.DefaultTrackingOptions
import com.amplitude.core.LogLevel
class MainApplication : Application() {
lateinit var amplitude: Amplitude
override fun onCreate() {
super.onCreate()
// Initialize Amplitude
amplitude = Amplitude(
Configuration(
apiKey = "YOUR_API_KEY",
context = applicationContext,
defaultTracking = DefaultTrackingOptions(
sessions = true,
appLifecycles = true,
screenViews = true
),
logLevel = LogLevel.DEBUG, // Use LogLevel.WARN in production
minIdLength = 5,
flushQueueSize = 30,
flushIntervalMillis = 30000,
optOut = false
)
)
}
}
// MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.amplitude.android.Amplitude
class MainActivity : AppCompatActivity() {
private lateinit var amplitude: Amplitude
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Get Amplitude instance
amplitude = (application as MainApplication).amplitude
// Track screen view
amplitude.track("Screen Viewed", mapOf(
"screenName" to "Home",
"category" to "main"
))
}
fun onButtonClick(view: android.view.View) {
amplitude.track("Button Clicked", mapOf(
"buttonName" to "Submit",
"screenName" to "Home"
))
}
}
// Identify user
fun identifyUser(userId: String, email: String, plan: String) {
val amplitude = (application as MainApplication).amplitude
amplitude.setUserId(userId)
amplitude.identify(
com.amplitude.android.Identify()
.set("email", email)
.set("plan", plan)
.set("signupDate", System.currentTimeMillis())
)
}
// Track revenue
fun trackPurchase(productId: String, price: Double, quantity: Int) {
val amplitude = (application as MainApplication).amplitude
amplitude.revenue(
com.amplitude.android.Revenue()
.setProductId(productId)
.setPrice(price)
.setQuantity(quantity)
)
}
// Set user properties
fun updateUserPlan(newPlan: String) {
val amplitude = (application as MainApplication).amplitude
amplitude.identify(
com.amplitude.android.Identify()
.set("plan", newPlan)
.add("planUpgrades", 1)
)
}
React Native Implementation
npm install @amplitude/analytics-react-native
# or
yarn add @amplitude/analytics-react-native
# iOS: Install pods
cd ios && pod install && cd ..
// App.js
import React, { useEffect } from 'react';
import { SafeAreaView, Button, Text } from 'react-native';
import { init, track, Identify, identify, setUserId } from '@amplitude/analytics-react-native';
const App = () => {
useEffect(() => {
// Initialize Amplitude
init('YOUR_API_KEY', {
defaultTracking: {
sessions: true,
appLifecycles: true,
screenViews: true
},
logLevel: __DEV__ ? 1 : 3 // Verbose in dev, Error in production
});
// Track app open
track('App Opened', {
source: 'direct',
platform: Platform.OS
});
}, []);
const handleLogin = (userId: string) => {
setUserId(userId);
const identifyObj = new Identify();
identifyObj.set('platform', Platform.OS);
identifyObj.set('appVersion', '1.0.0');
identify(identifyObj);
track('User Logged In', {
method: 'email'
});
};
const handleButtonPress = () => {
track('Button Pressed', {
buttonName: 'Submit',
screenName: 'Home'
});
};
return (
<SafeAreaView>
<Text>Amplitude React Native Example</Text>
<Button title="Track Event" />
</SafeAreaView>
);
};
export default App;
// Create utility hook
// hooks/useAmplitude.js
import { useCallback } from 'react';
import { track, Identify, identify } from '@amplitude/analytics-react-native';
export const useAmplitude = () => {
const trackEvent = useCallback((eventName, eventProperties = {}) => {
track(eventName, eventProperties);
}, []);
const identifyUser = useCallback((userId, userProperties = {}) => {
setUserId(userId);
const identifyObj = new Identify();
Object.entries(userProperties).forEach(([key, value]) => {
identifyObj.set(key, value);
});
identify(identifyObj);
}, []);
return { trackEvent, identifyUser };
};
Server-Side Collection
HTTP API V2
// Node.js Example
const https = require('https');
class AmplitudeServerSide {
constructor(apiKey) {
this.apiKey = apiKey;
this.endpoint = 'https://api2.amplitude.com/2/httpapi';
}
async track(events) {
const payload = {
api_key: this.apiKey,
events: Array.isArray(events) ? events : [events]
};
return new Promise((resolve, reject) => {
const data = JSON.stringify(payload);
const options = {
hostname: 'api2.amplitude.com',
path: '/2/httpapi',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = https.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
if (res.statusCode === 200) {
resolve(JSON.parse(responseData));
} else {
reject(new Error(`HTTP ${res.statusCode}: ${responseData}`));
}
});
});
req.on('error', reject);
req.write(data);
req.end();
});
}
createEvent(userId, eventType, eventProperties = {}, options = {}) {
return {
user_id: userId,
device_id: options.deviceId,
event_type: eventType,
event_properties: eventProperties,
user_properties: options.userProperties,
time: options.time || Date.now(),
insert_id: options.insertId || `${userId}-${eventType}-${Date.now()}`,
session_id: options.sessionId,
ip: options.ip || '$remote',
platform: options.platform || 'Web',
os_name: options.osName,
os_version: options.osVersion,
device_brand: options.deviceBrand,
device_model: options.deviceModel,
language: options.language,
country: options.country,
region: options.region,
city: options.city
};
}
}
// Usage
const amplitude = new AmplitudeServerSide(process.env.AMPLITUDE_API_KEY);
// Track single event
amplitude.track(
amplitude.createEvent(
'user-123',
'Purchase Completed',
{
product: 'Premium Plan',
price: 99.99,
currency: 'USD'
},
{
insertId: `purchase-${Date.now()}`,
ip: req.ip,
userProperties: {
plan: 'premium',
totalPurchases: 5
}
}
)
).then(response => {
console.log('Event tracked:', response);
}).catch(error => {
console.error('Tracking failed:', error);
});
// Batch track multiple events
const events = [
amplitude.createEvent('user-123', 'Page Viewed', { page: '/dashboard' }),
amplitude.createEvent('user-123', 'Button Clicked', { button: 'Export' }),
amplitude.createEvent('user-123', 'Export Completed', { format: 'CSV' })
];
amplitude.track(events);
Batch API
// For high-volume server-side tracking
class AmplitudeBatch {
constructor(apiKey, options = {}) {
this.apiKey = apiKey;
this.batchSize = options.batchSize || 100;
this.flushInterval = options.flushInterval || 10000; // 10 seconds
this.queue = [];
this.endpoint = 'https://api2.amplitude.com/batch';
// Auto-flush on interval
this.intervalId = setInterval(() => this.flush(), this.flushInterval);
}
enqueue(event) {
this.queue.push(event);
if (this.queue.length >= this.batchSize) {
this.flush();
}
}
async flush() {
if (this.queue.length === 0) return;
const events = this.queue.splice(0, this.batchSize);
const payload = {
api_key: this.apiKey,
events: events
};
try {
const response = await fetch(this.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!response.ok) {
console.error('Batch flush failed:', await response.text());
// Re-queue events on failure
this.queue.unshift(...events);
}
} catch (error) {
console.error('Batch flush error:', error);
this.queue.unshift(...events);
}
}
destroy() {
clearInterval(this.intervalId);
this.flush();
}
}
// Usage
const batch = new AmplitudeBatch(process.env.AMPLITUDE_API_KEY, {
batchSize: 50,
flushInterval: 5000
});
// Enqueue events
batch.enqueue({
user_id: 'user-123',
event_type: 'API Call',
event_properties: { endpoint: '/api/users', method: 'GET' }
});
// Graceful shutdown
process.on('SIGTERM', () => {
batch.destroy();
});
Configuration Options
Browser SDK Configuration
import * as amplitude from '@amplitude/analytics-browser';
amplitude.init('YOUR_API_KEY', {
// User/Device Identification
userId: 'user-123', // Optional: Set on init
deviceId: 'device-abc', // Optional: Custom device ID
// Tracking Options
defaultTracking: {
sessions: true, // Auto-track sessions
pageViews: true, // Auto-track page views
formInteractions: false, // Track form events
fileDownloads: true // Track download links
},
// Server Configuration
serverUrl: 'https://api2.amplitude.com/2/httpapi', // Default US
serverZone: 'US', // 'US' or 'EU'
useBatch: false, // Use batch endpoint
// Flush Configuration
flushIntervalMillis: 10000, // Flush every 10 seconds
flushQueueSize: 30, // Flush when queue reaches 30 events
flushMaxRetries: 5, // Retry failed requests up to 5 times
// Identity
minIdLength: 5, // Minimum user/device ID length
partnerId: 'your-partner-id', // Optional partner ID
// Session Configuration
sessionTimeout: 30 * 60 * 1000, // 30 minutes
// Tracking Options
trackingOptions: {
ipAddress: true,
language: true,
platform: true,
osName: true,
osVersion: true,
deviceManufacturer: true,
deviceModel: true
},
// Transport
transport: 'fetch', // 'fetch' or 'xhr' or 'beacon'
// Logging
logLevel: amplitude.Types.LogLevel.Warn, // None, Error, Warn, Verbose, Debug
// Opt Out
optOut: false,
// Callbacks
onBeforeEventSend: (event) => {
// Modify or drop events before sending
if (event.event_type === 'Internal Event') {
return null; // Drop event
}
return event;
}
});
Verifying Installation
Browser Console Checks
// Check if Amplitude is loaded
console.log(typeof amplitude !== 'undefined' ? 'Amplitude loaded' : 'Not loaded');
// Get current session ID
amplitude.getSessionId().promise.then(sessionId => {
console.log('Session ID:', sessionId);
});
// Get device ID
amplitude.getDeviceId().promise.then(deviceId => {
console.log('Device ID:', deviceId);
});
// Get user ID
amplitude.getUserId().promise.then(userId => {
console.log('User ID:', userId);
});
// Test track event
amplitude.track('Test Event', {
property1: 'value1',
property2: 'value2'
}).promise.then(result => {
console.log('Event tracked:', result);
});
Network Tab Verification
- Open DevTools (F12) > Network tab
- Filter by "amplitude" or "api2.amplitude.com"
- Look for POST requests to:
https://api2.amplitude.com/2/httpapi(standard)https://api2.amplitude.com/batch(batch mode)
- Check request payload:
- Contains
api_key - Contains
eventsarray - Events have
event_type,user_idordevice_id
- Contains
Amplitude Debugger
- Install Amplitude Instrumentation Explorer Chrome extension
- Navigate to your site
- Open extension
- Verify:
- Events appear in real-time
- Event properties are correct
- User properties are set
Live Events in Amplitude
- Log into Amplitude
- Navigate to User Look-Up
- Search for your test user ID or device ID
- Click on user > Event Stream
- Verify events appear within seconds
Common Installation Issues
| Issue | Symptoms | Solution |
|---|---|---|
| Events not sending | No network requests | Check API key is correct, verify SDK initialized, check console for errors |
| Wrong API key | Events don't appear in Amplitude | Verify environment-specific keys, check project selection in Amplitude |
| CORS errors | Console shows CORS blocked | Amplitude endpoints should allow CORS; check for proxy/firewall issues |
| Duplicate events | Same event tracked multiple times | Check for multiple init calls, use unique insert_id for deduplication |
| Missing user_id | Events tracked with device_id only | Call setUserId() after authentication, verify user ID not null/undefined |
| Session not starting | New session on every event | Check session timeout settings, verify cookies not blocked |
| EU data residency | Data not in EU | Set serverZone: 'EU' in configuration |
| Events delayed | Events appear after long delay | Check flushInterval and flushQueueSize settings, call flush() manually if needed |
| Type errors (TypeScript) | Import errors | Install @types or update to latest SDK version with built-in types |
| Mobile events missing | iOS/Android events don't appear | Verify SDK initialization, check API key, review app permissions |
Debug Mode
// Enable verbose logging
amplitude.init('YOUR_API_KEY', {
logLevel: amplitude.Types.LogLevel.Debug
});
// Manual flush for testing
amplitude.flush().promise.then(() => {
console.log('All events flushed');
});
// Set custom logger
amplitude.init('YOUR_API_KEY', {
loggerProvider: {
log: (message) => console.log('[Amplitude]', message),
error: (message) => console.error('[Amplitude Error]', message),
warn: (message) => console.warn('[Amplitude Warning]', message),
debug: (message) => console.debug('[Amplitude Debug]', message)
}
});
Security Best Practices
API Key Protection
// Use environment variables
const AMPLITUDE_API_KEY = process.env.REACT_APP_AMPLITUDE_API_KEY;
// Never commit API keys
// .env
REACT_APP_AMPLITUDE_API_KEY=your_api_key_here
// .gitignore
.env
.env.local
PII Handling
// DON'T: Track PII directly
amplitude.track('User Signup', {
email: 'user@example.com', // BAD
phone: '555-1234' // BAD
});
// DO: Hash or pseudonymize
import crypto from 'crypto';
const hashValue = (value) => {
return crypto.createHash('sha256').update(value).digest('hex');
};
amplitude.track('User Signup', {
emailHash: hashValue('user@example.com'), // GOOD
userIdHash: hashValue('user-123') // GOOD
});
Data Filtering
// Filter sensitive data before sending
amplitude.init('YOUR_API_KEY', {
onBeforeEventSend: (event) => {
// Remove sensitive properties
const sensitiveKeys = ['password', 'ssn', 'credit_card'];
if (event.event_properties) {
sensitiveKeys.forEach(key => {
delete event.event_properties[key];
});
}
return event;
}
});
Consent Management
// Wait for consent before initializing
let amplitudeInitialized = false;
window.addEventListener('cookieConsentGiven', (event) => {
if (event.detail.analytics && !amplitudeInitialized) {
amplitude.init('YOUR_API_KEY', {
defaultTracking: { sessions: true, pageViews: true }
});
amplitudeInitialized = true;
}
});
// Opt-out capability
function optOutOfTracking() {
amplitude.setOptOut(true);
}
function optInToTracking() {
amplitude.setOptOut(false);
}
Performance Considerations
Lazy Loading
// Load Amplitude only when needed
let amplitudeLoaded = false;
async function loadAmplitude() {
if (amplitudeLoaded) return;
const { default: amplitude } = await import('@amplitude/analytics-browser');
amplitude.init('YOUR_API_KEY');
amplitudeLoaded = true;
return amplitude;
}
// Use on user interaction
document.addEventListener('scroll', async () => {
const amplitude = await loadAmplitude();
amplitude.track('User Engaged');
}, { once: true });
Batching Events
// Configure batching for better performance
amplitude.init('YOUR_API_KEY', {
useBatch: true, // Use batch endpoint
flushQueueSize: 50, // Batch up to 50 events
flushIntervalMillis: 10000 // Flush every 10 seconds
});
Defer Non-Critical Tracking
// Use requestIdleCallback for low-priority events
function trackLowPriority(eventName, props) {
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
amplitude.track(eventName, props);
});
} else {
setTimeout(() => {
amplitude.track(eventName, props);
}, 1);
}
}
Deployment Strategy
- Load the Browser SDK with environment-specific API keys; disable automatic tracking you do not need (e.g., form interactions).
- Use a consent wrapper to delay init when required; set tracking options explicitly to avoid surprise events.
- Consider using a first-party proxy for ingestion to reduce blocking.
Tag Manager Deployment
- Store API keys and ingest endpoints as variables in the TMS; deploy init and event helpers through templates.
- Ensure the init tag fires early enough to capture attribution but after consent if needed.
- Create reusable TMS macros for common events (commerce, feature usage) to keep mappings consistent.
Direct Embed or Hard-Coded Scripts
- Embed the script in the head to establish device_id early and store attribution (utm, referrer) before SPA navigation.
- Register identify/setUserProperties after authentication to bind traits to the known user_id.
Validation Checklist
- Use Event Stream/Monitor to inspect payloads; ensure event volumes align with expectations after each release.
- Verify attribution fields (utm_*, referrer) and session_id values appear on key events.
Configuration Recommendations
Merged Users: Enable merged users (Project Settings → User Management) only if you need cross-device identity resolution. Once enabled, it retroactively merges historical anonymous profiles with identified users, which can alter historical funnel and retention reports. Test in a development project first.
Ingestion Filtering: If you track high-volume events (page scrolls, mouse movements), use Amplitude's ingestion filters (Settings → Project → Ingestion Filters) to drop or sample noisy events before they count against your event quota. Filter at ingestion rather than in queries to save quota.
Environment Separation: Use separate Amplitude projects for production and development. Never share API keys between environments. Use amplitude.init('API_KEY', { serverZone: 'US' }) for US data center or serverZone: 'EU' for EU data residency (available on Growth and Enterprise plans).
First-Party Proxy: Set up a first-party proxy (api.yourdomain.com/amplitude) to route events through your domain and bypass ad blockers. Amplitude provides proxy setup guides for Cloudflare, Nginx, and AWS CloudFront.