Implement Appizer securely to protect your data and users.
API Key Management
Never Expose Secret Keys
Secret keys (sk_) must never be exposed in client-side code:
// ❌ DANGER: Secret key in browser
const appizer = new Appizer({
apiKey: 'sk_live_abc123...' // Exposed to users!
})
// ✅ SAFE: Use public key in browser
const appizer = new AppizerClient({
publicKey: 'pk_live_xyz789...' // Safe for client-side
})
Use Environment Variables
Store API keys in environment variables:
# .env
APPIZER_API_KEY=sk_live_your_secret_key
APPIZER_PUBLIC_KEY=pk_live_your_public_key
// Server-side
const appizer = new Appizer({
apiKey: process.env.APPIZER_API_KEY
})
// Client-side
const appizer = new AppizerClient({
publicKey: process.env.NEXT_PUBLIC_APPIZER_PUBLIC_KEY
})
Critical
Add .env to your .gitignore to prevent committing secrets to version control.
Rotate Keys Regularly
Rotate API keys periodically:
Generate New Key
Create a new API key in your Appizer dashboard
Update Applications
Deploy the new key to all applications
Revoke Old Key
Delete the old key after confirming the new one works
Use Different Keys Per Environment
Separate keys for development, staging, and production:
# Development
APPIZER_API_KEY=sk_test_dev_abc123
# Staging
APPIZER_API_KEY=sk_test_staging_def456
# Production
APPIZER_API_KEY=sk_live_prod_ghi789
Data Privacy
PII Handling
Be careful with Personally Identifiable Information (PII):
// ❌ Avoid sending sensitive PII
appizer.identify({
userId: 'user_123',
traits: {
ssn: '123-45-6789', // Don't send
creditCard: '4111...', // Don't send
password: 'secret123' // Never send
}
})
// ✅ Hash or omit sensitive data
appizer.identify({
userId: 'user_123',
traits: {
email: 'user@example.com', // OK if needed
plan: 'enterprise', // Non-sensitive
hashedId: sha256(userId) // Hashed if needed
}
})
Data Minimization
Only track data you actually need:
// ❌ Over-collection
appizer.track({
event: 'page_view',
properties: {
fullUrl: window.location.href,
allCookies: document.cookie,
localStorage: JSON.stringify(localStorage),
userAgent: navigator.userAgent
}
})
// ✅ Minimal collection
appizer.track({
event: 'page_view',
properties: {
page: '/products',
referrer: document.referrer
}
})
User Consent
Respect user privacy preferences:
// Check consent before tracking
if (userHasConsented()) {
appizer.track({ event: 'page_view' })
}
// Provide opt-out mechanism
function optOutOfTracking() {
appizer.optOut()
localStorage.setItem('tracking_opted_out', 'true')
}
Network Security
Use HTTPS Only
Always use HTTPS for API requests:
const appizer = new Appizer({
apiKey: process.env.APPIZER_API_KEY,
baseUrl: 'https://api.appizer.com' // Always HTTPS
})
HTTP Blocked
Appizer blocks all HTTP requests. Only HTTPS is supported.
Validate SSL Certificates
Ensure SSL certificate validation is enabled:
const appizer = new Appizer({
apiKey: process.env.APPIZER_API_KEY,
validateSSL: true // Default: true
})
Set Request Timeouts
Prevent hanging connections:
const appizer = new Appizer({
apiKey: process.env.APPIZER_API_KEY,
timeout: 5000, // 5 seconds
retries: 3
})
Input Validation
Sanitize User Input
Validate and sanitize data before tracking:
function sanitizeEventName(name: string): string {
return name
.toLowerCase()
.replace(/[^a-z0-9_]/g, '_')
.substring(0, 100)
}
function trackUserAction(action: string) {
const sanitized = sanitizeEventName(action)
appizer.track({ event: sanitized })
}
Validate Property Types
Ensure properties match expected types:
interface PurchaseProperties {
amount: number
currency: string
productId: string
}
function trackPurchase(props: PurchaseProperties) {
if (typeof props.amount !== 'number' || props.amount <= 0) {
throw new Error('Invalid amount')
}
if (!/^[A-Z]{3}$/.test(props.currency)) {
throw new Error('Invalid currency code')
}
appizer.track({
event: 'purchase_completed',
properties: props
})
}
Limit Property Size
Prevent large payloads:
const MAX_PROPERTY_SIZE = 10000 // 10KB
function trackWithSizeLimit(event: string, properties: any) {
const size = JSON.stringify(properties).length
if (size > MAX_PROPERTY_SIZE) {
console.error('Properties too large:', size)
return
}
appizer.track({ event, properties })
}
Authentication
Server-Side Authentication
Perform sensitive operations server-side:
// ❌ Client-side (exposed)
appizer.identify({
userId: 'user_123',
traits: {
internalScore: 95, // Sensitive
accountBalance: 1000 // Sensitive
}
})
// ✅ Server-side (protected)
// In your API endpoint
app.post('/api/identify-user', async (req, res) => {
const { userId } = req.body
await appizer.identify({
userId,
traits: {
internalScore: calculateScore(userId),
accountBalance: getBalance(userId)
}
})
res.json({ success: true })
})
Verify Webhook Signatures
Validate webhook authenticity:
import crypto from 'crypto'
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
)
}
app.post('/webhooks/appizer', (req, res) => {
const signature = req.headers['x-appizer-signature']
const payload = JSON.stringify(req.body)
if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
// Process webhook
res.status(200).send('OK')
})
Rate Limiting
Implement Client-Side Rate Limiting
Prevent excessive API calls:
class RateLimiter {
private requests: number[] = []
private limit = 100 // requests
private window = 60000 // 1 minute
canMakeRequest(): boolean {
const now = Date.now()
this.requests = this.requests.filter(t => t > now - this.window)
if (this.requests.length >= this.limit) {
return false
}
this.requests.push(now)
return true
}
}
const limiter = new RateLimiter()
function trackEvent(event: Event) {
if (!limiter.canMakeRequest()) {
console.warn('Rate limit exceeded')
return
}
appizer.track(event)
}
Handle Rate Limit Errors
Gracefully handle 429 responses:
async function trackWithRetry(event: Event) {
try {
await appizer.track(event)
} catch (error) {
if (error.status === 429) {
const retryAfter = error.headers['retry-after'] || 60
console.log(`Rate limited. Retry after ${retryAfter}s`)
setTimeout(() => trackWithRetry(event), retryAfter * 1000)
}
}
}
Error Handling
Don't Expose Internal Errors
Sanitize error messages:
try {
await appizer.track(event)
} catch (error) {
// ❌ Exposes internal details
console.error('Track failed:', error)
// ✅ Generic message
console.error('Failed to track event')
// Log detailed error server-side only
if (process.env.NODE_ENV === 'development') {
console.error('Details:', error)
}
}
Implement Circuit Breaker
Prevent cascading failures:
class CircuitBreaker {
private failures = 0
private threshold = 5
private timeout = 60000
private state: 'closed' | 'open' | 'half-open' = 'closed'
async execute<T>(fn: () => Promise<T>): Promise<T> {
if (this.state === 'open') {
throw new Error('Circuit breaker is open')
}
try {
const result = await fn()
this.onSuccess()
return result
} catch (error) {
this.onFailure()
throw error
}
}
private onSuccess() {
this.failures = 0
this.state = 'closed'
}
private onFailure() {
this.failures++
if (this.failures >= this.threshold) {
this.state = 'open'
setTimeout(() => {
this.state = 'half-open'
}, this.timeout)
}
}
}
Compliance
GDPR Compliance
Implement data subject rights:
// Right to access
async function exportUserData(userId: string) {
return await appizer.users.export(userId)
}
// Right to deletion
async function deleteUserData(userId: string) {
await appizer.users.delete(userId)
}
// Right to rectification
async function updateUserData(userId: string, traits: any) {
await appizer.identify({ userId, traits })
}
Data Retention
Set appropriate retention policies:
// Configure retention in dashboard or API
await appizer.settings.update({
dataRetention: {
events: 90, // days
users: 365 // days
}
})
Security Checklist
API Keys
✓ Use environment variables
✓ Never commit to version control
✓ Separate keys per environment
✓ Rotate regularly
Data Privacy
✓ Minimize PII collection
✓ Hash sensitive data
✓ Obtain user consent
✓ Implement opt-out
Network
✓ Use HTTPS only
✓ Validate SSL certificates
✓ Set timeouts
✓ Implement rate limiting
Code
✓ Validate input
✓ Sanitize data
✓ Handle errors gracefully
✓ Use server-side for sensitive ops