Overview
Kissmetrics is a behavior analytics and engagement platform focused on tracking individual user journeys across devices and sessions. Unlike pageview-centric analytics, Kissmetrics emphasizes person-based tracking, allowing you to analyze cohorts, funnels, and revenue attribution at the user level.
Key Capabilities:
- Person-Based Tracking: Track individual users across devices and sessions
- Behavioral Cohorts: Group users by actions taken or properties
- Funnel Analysis: Measure conversion at each step of user flows
- A/B Test Analysis: Compare behavior between experiment variants
- Revenue Tracking: Attribute revenue to specific users and campaigns
- Customer Journey Mapping: Visualize complete user paths
Architecture:
- JavaScript Library: Client-side tracking via
_kmqqueue - API: Server-side event and people API
- People & Events: Dual data model tracking both identity and actions
- Properties: Custom attributes attached to people and events
Prerequisites
1. Kissmetrics Account Setup
Before implementation:
- Active Kissmetrics Account: Sign up at kissmetrics.io
- API Key: Found in Settings → Account (format: alphanumeric string)
- Product Configuration: Define which product/site you're tracking
- Separate Projects: Use different API keys for staging vs production
2. Implementation Planning
Define your tracking strategy:
- Identity Strategy: How users will be identified (email, user ID, anonymous)
- Core Events: Critical actions to track (signup, purchase, subscription)
- User Properties: Attributes to store (plan type, signup date, LTV)
- Funnel Definitions: Key conversion flows to measure
- Revenue Attribution: How to track monetary value
3. Data Layer Design
Plan your event structure:
// Example event structure
_kmq.push(['record', 'Signed Up', {
'Plan Type': 'Premium',
'Signup Method': 'Google OAuth',
'Trial Period': 14
}]);
- Event Names: Descriptive, past-tense (e.g., "Viewed Product," "Completed Purchase")
- Property Names: Human-readable with spaces and capitals
- Property Values: Strings, numbers, or booleans
- Reserved Properties: Avoid Kissmetrics reserved names
4. Privacy & Compliance
Consider data governance:
- PII Handling: Decide which personal identifiers to collect
- Consent Management: Integrate with CMP if required by jurisdiction
- Data Retention: Configure how long Kissmetrics stores data
- GDPR Compliance: Enable data deletion capabilities for user requests
Quick Start
1. Get API Key
- Log in to Kissmetrics at kissmetrics.io
- Navigate to Settings → Account
- Copy your API key (alphanumeric string)
- Store securely in environment variables
Never commit API keys to version control.
2. Install Tracking Code
Add the Kissmetrics JavaScript snippet to your site's <head> section:
<!DOCTYPE html>
<html>
<head>
<title>Your Site</title>
<!-- Kissmetrics Tracking Code -->
<script type="text/javascript">
var _kmq = _kmq || [];
var _kmk = _kmk || 'YOUR_API_KEY';
function _kms(u){
setTimeout(function(){
var d = document, f = d.getElementsByTagName('script')[0],
s = d.createElement('script');
s.type = 'text/javascript'; s.async = true; s.src = u;
f.parentNode.insertBefore(s, f);
}, 1);
}
_kms('//scripts.kissmetrics.io/' + _kmk + '.js');
_kms('//doug1izaerwt3.cloudfront.net/' + _kmk + '.1.js');
</script>
<!-- End Kissmetrics Tracking Code -->
</head>
<body>
<!-- Your content -->
</body>
</html>
Replace YOUR_API_KEY with your actual Kissmetrics API key.
Script Explanation:
_kmq: Global queue for tracking commands_kmk: Your API key_kms(): Asynchronous script loader- Two script URLs: Primary and fallback CDN
3. Identify Users
Once a user logs in or signs up, identify them:
// Identify by email (recommended)
_kmq.push(['identify', 'user@example.com']);
// Identify by user ID
_kmq.push(['identify', 'user-12345']);
// Set user properties
_kmq.push(['set', {
'Name': 'Jane Doe',
'Email': 'jane@example.com',
'Plan': 'Premium',
'Signup Date': '2024-01-15',
'Monthly Spend': 99.99
}]);
Identity Best Practices:
- Use a persistent identifier (email or database user ID)
- Call
identifyas early as possible after login - Consistent identifier across all platforms (web, mobile, server)
- Don't identify with temporary/session IDs
4. Track Events
Record user actions:
// Simple event
_kmq.push(['record', 'Viewed Homepage']);
// Event with properties
_kmq.push(['record', 'Viewed Product', {
'Product ID': 'SKU-12345',
'Product Name': 'Premium Subscription',
'Product Price': 99.99,
'Product Category': 'Subscriptions'
}]);
// Conversion event
_kmq.push(['record', 'Completed Purchase', {
'Order ID': 'ORDER-789',
'Order Total': 149.99,
'Payment Method': 'Credit Card',
'Items Count': 2
}]);
Event Naming Conventions:
- Use past tense (Clicked, Viewed, Completed)
- Be specific and descriptive
- Use Title Case for readability
- Avoid technical jargon in event names
5. Track Revenue
Kissmetrics provides dedicated revenue tracking:
// Track billing event with revenue
_kmq.push(['record', 'Billed', {
'Billing Amount': 99.99,
'Billing Description': 'Monthly Premium Plan',
'Transaction ID': 'TXN-456'
}]);
// Track revenue without specific event name
_kmq.push(['trackSubmit', 'checkout-form', 'Completed Checkout']);
_kmq.push(['set', {
'Revenue': 99.99
}]);
Revenue Tracking Methods:
- Billing Events: Use "Billed" event with amount
- Revenue Property: Set "Revenue" property on conversion events
- Custom Events: Track specific revenue events (upgrade, renewal)
Installation Methods
Method 1: Direct JavaScript Embed (Recommended)
The standard implementation for most websites.
Basic Installation
<script type="text/javascript">
var _kmq = _kmq || [];
var _kmk = _kmk || 'YOUR_API_KEY';
function _kms(u){
setTimeout(function(){
var d = document, f = d.getElementsByTagName('script')[0],
s = d.createElement('script');
s.type = 'text/javascript'; s.async = true; s.src = u;
f.parentNode.insertBefore(s, f);
}, 1);
}
_kms('//scripts.kissmetrics.io/' + _kmk + '.js');
_kms('//doug1izaerwt3.cloudfront.net/' + _kmk + '.1.js');
</script>
Environment-Specific Configuration
Use server-side templating to inject the correct API key:
<!-- Node.js/Express -->
<script>
var _kmq = _kmq || [];
var _kmk = _kmk || '<%= process.env.KISSMETRICS_API_KEY %>';
// ... rest of script
</script>
<!-- Ruby on Rails -->
<script>
var _kmq = _kmq || [];
var _kmk = _kmk || '<%= ENV['KISSMETRICS_API_KEY'] %>';
// ... rest of script
</script>
<!-- PHP -->
<script>
var _kmq = _kmq || [];
var _kmk = _kmk || '<?php echo getenv('KISSMETRICS_API_KEY'); ?>';
// ... rest of script
</script>
With Consent Management
Delay Kissmetrics loading until consent granted:
<script>
var _kmq = _kmq || [];
// Only load Kissmetrics if user has consented
if (userHasConsented()) {
var _kmk = _kmk || 'YOUR_API_KEY';
function _kms(u){
setTimeout(function(){
var d = document, f = d.getElementsByTagName('script')[0],
s = d.createElement('script');
s.type = 'text/javascript'; s.async = true; s.src = u;
f.parentNode.insertBefore(s, f);
}, 1);
}
_kms('//scripts.kissmetrics.io/' + _kmk + '.js');
_kms('//doug1izaerwt3.cloudfront.net/' + _kmk + '.1.js');
}
function userHasConsented() {
// Check your consent management platform
return localStorage.getItem('analytics_consent') === 'granted';
}
</script>
Method 2: Google Tag Manager
Deploy Kissmetrics through GTM for centralized management.
Step 1: Create Custom HTML Tag
<script type="text/javascript">
var _kmq = _kmq || [];
var _kmk = _kmk || '{{Kissmetrics API Key}}';
function _kms(u){
setTimeout(function(){
var d = document, f = d.getElementsByTagName('script')[0],
s = d.createElement('script');
s.type = 'text/javascript'; s.async = true; s.src = u;
f.parentNode.insertBefore(s, f);
}, 1);
}
_kms('//scripts.kissmetrics.io/' + _kmk + '.js');
_kms('//doug1izaerwt3.cloudfront.net/' + _kmk + '.1.js');
</script>
Step 2: Create API Key Variable
- Navigate to Variables → New
- Variable Type: Lookup Table
- Input:
{{Page Hostname}} - Map hostnames to API keys:
localhost→DEV_API_KEYstaging.yourdomain.com→STAGING_API_KEYyourdomain.com→PRODUCTION_API_KEY
Step 3: Configure Trigger
- Trigger Type: Page View - DOM Ready
- Fires On: All Pages
- Priority: 100 (load early)
Step 4: Track Events via GTM
Create additional Custom HTML tags for events:
<script>
if (typeof _kmq !== 'undefined') {
_kmq.push(['record', '{{Event Name}}', {
'Event Category': '{{Event Category}}',
'Event Label': '{{Event Label}}',
'Event Value': {{Event Value}}
}]);
}
</script>
Trigger: Custom Event matching your data layer
Step 5: Identify Users via GTM
<script>
if (typeof _kmq !== 'undefined' && '{{User Email}}') {
_kmq.push(['identify', '{{User Email}}']);
_kmq.push(['set', {
'Name': '{{User Name}}',
'Plan': '{{User Plan}}',
'Signup Date': '{{User Signup Date}}'
}]);
}
</script>
Trigger: Custom Event on login/page load when user is authenticated
Method 3: Server-Side API
For backend event tracking and sensitive data.
HTTP API Endpoint
POST https://trk.kissmetrics.io/e
Required Parameters:
_k: API key_p: Person identifier_n: Event name
Optional Parameters:
_t: Timestamp (Unix epoch)_d: Event property (can be repeated)
Node.js Implementation
const axios = require('axios');
async function trackKissmetricsEvent(personId, eventName, properties = {}) {
const apiKey = process.env.KISSMETRICS_API_KEY;
const baseUrl = 'https://trk.kissmetrics.io/e';
const params = {
_k: apiKey,
_p: personId,
_n: eventName,
_t: Math.floor(Date.now() / 1000)
};
// Add properties
Object.keys(properties).forEach(key => {
params[key] = properties[key];
});
try {
await axios.get(baseUrl, { params });
return true;
} catch (error) {
console.error('Kissmetrics tracking error:', error);
return false;
}
}
// Usage
await trackKissmetricsEvent('user@example.com', 'Server Signup', {
'Plan': 'Premium',
'Method': 'API',
'Revenue': 99.99
});
Python Implementation
import requests
import time
def track_kissmetrics_event(person_id, event_name, properties=None):
api_key = os.environ.get('KISSMETRICS_API_KEY')
base_url = 'https://trk.kissmetrics.io/e'
params = {
'_k': api_key,
'_p': person_id,
'_n': event_name,
'_t': int(time.time())
}
if properties:
params.update(properties)
try:
response = requests.get(base_url, params=params)
return response.status_code == 200
except Exception as e:
print(f'Kissmetrics error: {e}')
return False
# Usage
track_kissmetrics_event('user@example.com', 'Server Signup', {
'Plan': 'Premium',
'Method': 'API',
'Revenue': 99.99
})
Ruby Implementation
require 'net/http'
require 'uri'
def track_kissmetrics_event(person_id, event_name, properties = {})
api_key = ENV['KISSMETRICS_API_KEY']
base_url = 'https://trk.kissmetrics.io/e'
params = {
'_k' => api_key,
'_p' => person_id,
'_n' => event_name,
'_t' => Time.now.to_i
}.merge(properties)
uri = URI(base_url)
uri.query = URI.encode_www_form(params)
begin
Net::HTTP.get_response(uri)
true
rescue => e
puts "Kissmetrics error: #{e.message}"
false
end
end
# Usage
track_kissmetrics_event('user@example.com', 'Server Signup', {
'Plan' => 'Premium',
'Method' => 'API',
'Revenue' => 99.99
})
Set People Properties via API
async function setKissmetricsProperties(personId, properties) {
const apiKey = process.env.KISSMETRICS_API_KEY;
const baseUrl = 'https://trk.kissmetrics.io/s';
const params = {
_k: apiKey,
_p: personId,
_t: Math.floor(Date.now() / 1000)
};
Object.keys(properties).forEach(key => {
params[key] = properties[key];
});
await axios.get(baseUrl, { params });
}
// Usage
await setKissmetricsProperties('user@example.com', {
'Name': 'Jane Doe',
'Plan': 'Premium',
'LTV': 1299.99,
'Last Login': '2024-12-26'
});
Framework Integrations
React
Custom Hook
// hooks/useKissmetrics.js
import { useEffect } from 'react';
export function useKissmetricsPageview() {
useEffect(() => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['record', 'Viewed Page', {
'Page Path': window.location.pathname,
'Page Title': document.title
}]);
}
}, []);
}
export function useKissmetrics() {
const identify = (userId, traits = {}) => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['identify', userId]);
if (Object.keys(traits).length > 0) {
window._kmq.push(['set', traits]);
}
}
};
const track = (eventName, properties = {}) => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['record', eventName, properties]);
}
};
const set = (properties) => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['set', properties]);
}
};
return { identify, track, set };
}
// Usage in component
import { useKissmetrics, useKissmetricsPageview } from './hooks/useKissmetrics';
function ProductPage() {
useKissmetricsPageview();
const { track } = useKissmetrics();
const handleAddToCart = () => {
track('Added to Cart', {
'Product ID': 'SKU-123',
'Product Price': 99.99
});
};
return <button onClick={handleAddToCart}>Add to Cart</button>;
}
React Router Integration
// App.js
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function App() {
const location = useLocation();
useEffect(() => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['record', 'Viewed Page', {
'Page Path': location.pathname,
'Page Title': document.title
}]);
}
}, [location]);
return <Routes />;
}
Next.js
Pages Router
// pages/_app.js
import { useEffect } from 'react';
import { useRouter } from 'next/router';
function MyApp({ Component, pageProps }) {
const router = useRouter();
useEffect(() => {
const handleRouteChange = (url) => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['record', 'Viewed Page', {
'Page Path': url,
'Page Title': document.title
}]);
}
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router.events]);
return <Component {...pageProps} />;
}
App Router
// app/providers.js
'use client';
import { usePathname } from 'next/navigation';
import { useEffect } from 'react';
export function AnalyticsProvider({ children }) {
const pathname = usePathname();
useEffect(() => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['record', 'Viewed Page', {
'Page Path': pathname,
'Page Title': document.title
}]);
}
}, [pathname]);
return <>{children}</>;
}
Vue.js
// plugins/kissmetrics.js
export default {
install: (app) => {
app.config.globalProperties.$km = {
identify: (userId, traits = {}) => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['identify', userId]);
if (Object.keys(traits).length > 0) {
window._kmq.push(['set', traits]);
}
}
},
track: (eventName, properties = {}) => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['record', eventName, properties]);
}
},
set: (properties) => {
if (typeof window !== 'undefined' && window._kmq) {
window._kmq.push(['set', properties]);
}
}
};
}
};
// main.js
import kissmetricsPlugin from './plugins/kissmetrics';
app.use(kissmetricsPlugin);
// Component usage
this.$km.track('Button Clicked', {
'Button ID': 'signup-cta'
});
Advanced Features
Automatic Event Tracking
Form Submissions
// Track all form submissions
_kmq.push(function() {
document.querySelectorAll('form').forEach(form => {
form.addEventListener('submit', function(e) {
_kmq.push(['record', 'Submitted Form', {
'Form ID': this.id || 'unknown',
'Form Action': this.action,
'Form Method': this.method
}]);
});
});
});
Link Clicks
// Track outbound link clicks
_kmq.push(['trackClick', 'outbound-link', 'Clicked Outbound Link']);
// Track specific button clicks
_kmq.push(['trackClick', 'signup-button', 'Clicked Signup Button']);
Form Submit Tracking
// Track form submission
_kmq.push(['trackSubmit', 'signup-form', 'Submitted Signup Form']);
Aliasing Identities
When a user transitions from anonymous to known:
// Before signup: tracked as anonymous (automatic)
// After signup: identify with email
_kmq.push(['identify', 'user@example.com']);
// Alias connects previous anonymous activity
_kmq.push(['alias', 'user@example.com', 'anonymous-visitor-id']);
Best Practice: Kissmetrics automatically handles most aliasing, but use explicitly when:
- Merging duplicate profiles
- Consolidating pre/post signup activity
- Linking accounts across platforms
Custom Properties
// Set user-level properties
_kmq.push(['set', {
'Account Type': 'Business',
'Employee Count': '50-100',
'Industry': 'SaaS',
'Signup Source': 'Google Ads',
'Trial End Date': '2024-02-01'
}]);
// Properties persist across sessions
// Update properties as they change
_kmq.push(['set', {
'Last Login': new Date().toISOString(),
'Login Count': 47,
'Last Feature Used': 'Reports'
}]);
Verification & Testing
1. Live Event Stream
View events in real-time:
- Log in to Kissmetrics
- Navigate to Live tab
- Trigger events on your site
- Verify events appear with correct properties
2. Browser Console Testing
// Check if Kissmetrics loaded
typeof _kmq !== 'undefined'
// Should return: true
// Manually fire test event
_kmq.push(['record', 'Test Event', {
'Test Property': 'Test Value',
'Timestamp': new Date().toISOString()
}]);
// Check queue
console.log(_kmq);
3. Network Inspector
Monitor network requests:
- Open DevTools (F12)
- Navigate to Network tab
- Filter for "kissmetrics" or "trk.kissmetrics"
- Trigger events
- Verify requests to
https://trk.kissmetrics.io/
Successful request format:
https://trk.kissmetrics.io/e?_k=API_KEY&_p=user@example.com&_n=Event+Name&Property=Value&_t=timestamp
4. People Profiles
Verify user data:
- Navigate to People in Kissmetrics
- Search for test user identifier
- Review events timeline
- Confirm properties are set correctly
Troubleshooting
Events Not Appearing
Problem: Events don't show in Kissmetrics
Solutions:
- Verify API key is correct for environment
- Check browser console for JavaScript errors
- Ensure
_kmqvariable exists before pushing - Check ad blockers aren't blocking Kissmetrics scripts
- Verify network requests reaching kissmetrics.io
Duplicate Identities
Problem: Same user appears as multiple profiles
Solutions:
- Ensure consistent identifier across sessions
- Call
identifywith same ID every session - Use aliasing to merge profiles
- Avoid identifying with session IDs or cookies
Missing Properties
Problem: Event properties don't appear
Solutions:
- Verify property names don't have typos
- Check property values aren't undefined/null
- Ensure
setcalled before event recording - Properties must be strings, numbers, or booleans
Cross-Domain Tracking Issues
Problem: Users tracked separately across domains
Solutions:
- Use same API key across all domains
- Implement consistent identification strategy
- Pass user ID via URL parameters if needed
- Call
identifyon each domain
Security Best Practices
1. API Key Protection
// Good - Server-side injection
var _kmk = _kmk || '<%= ENV['KISSMETRICS_API_KEY'] %>';
// Bad - Hardcoded in client code
var _kmk = _kmk || 'abc123def456'; // Don't do this
2. PII Handling
// Acceptable - Email as identifier
_kmq.push(['identify', 'user@example.com']);
// Bad - Sending sensitive PII in properties
_kmq.push(['set', {
'SSN': '123-45-6789', // Never do this
'Credit Card': '4111...', // Never do this
'Password': 'password123' // Never do this
}]);
// Good - Non-sensitive properties
_kmq.push(['set', {
'Plan Type': 'Premium',
'Account Age Days': 365,
'Feature Usage': 'High'
}]);
3. Server-Side for Sensitive Events
// Client-side: Track initiation only
_kmq.push(['record', 'Started Checkout']);
// Server-side: Track completion with revenue
await trackKissmetricsEvent('user@example.com', 'Completed Purchase', {
'Order ID': 'ORDER-123',
'Revenue': 149.99,
'Items': 3
});
Validation Checklist
Before going live:
- Correct API key configured per environment
- Kissmetrics script loads successfully
- Test events appear in Live stream
- User identification working correctly
- Event properties structured correctly
- Revenue tracking implemented for purchases
- Funnel events firing in correct sequence
- No PII exposed in event properties
- Cross-domain tracking works if needed
- Server-side tracking verified
- Team has access to Kissmetrics account
- Critical funnels defined in Kissmetrics
- Cohorts configured for analysis
Guides
Continue with detailed implementation guides:
- Install Tracking Code - Comprehensive installation instructions
- Event Tracking - Track custom user actions
- Data Layer Setup - Structure your tracking data
- Cross-Domain Tracking - Track users across domains
- Server-Side vs Client-Side - Choose the right approach
Open Decisions & Follow-Ups
Document these for your implementation:
Identity Strategy
- What identifier to use (email vs user ID)?
- How to handle pre-login activity?
- Cross-platform identity resolution?
-
- Which events are critical to track?
- Naming conventions to standardize?
- Event property requirements?
Revenue Attribution
- How to track different revenue types?
- Attribution model (first-touch, last-touch, multi-touch)?
- Subscription vs one-time purchase tracking?
Privacy & Compliance
- Consent management requirements?
- Data retention policies?
- User data deletion process?
Reporting & Analysis
- Key funnels to monitor?
- Cohort definitions?
- A/B test tracking requirements?