Files
obsidian-vault/work/wiki/apple-browsers/analytics-patterns.md
T

4.4 KiB

source, confidence, namespace, last_synced, alwaysApply
source confidence namespace last_synced alwaysApply
~/DuckDuckGo/apple-browsers.git/main/.cursor/rules/analytics-patterns.mdc 0.9 work 2026-04-28 false

Analytics and Pixel Patterns

Structured Pixel Events

Use the existing Pixel.fire pattern with structured event definitions:

// ✅ CORRECT - Use existing Pixel.fire with proper parameters
extension PixelEvent {
    static let featureUsed = "feature_used"
    static let performanceMetric = "performance_metric"
    static let errorOccurred = "error_occurred"
    static let userAction = "user_action"
}

// Usage examples from codebase
Pixel.fire(pixel: .webKitTerminationDidReloadCurrentTab)

Pixel.fire(pixel: .cachedTabPreviewsExceedsTabCount, withAdditionalParameters: [
    PixelParameters.tabPreviewCountDelta: "\(storedPreviews - totalTabs)"
])

Pixel.fire(pixel: .autofillLoginsSavePromptDisplayed, withAdditionalParameters: [
    PixelParameters.autofillPromptTrigger: "manual"
])

Pixel Parameters

Use the established PixelParameters constants:

// ✅ CORRECT - Use existing PixelParameters
extension PixelParameters {
    static let featureName = "fn"
    static let errorType = "et"
    static let performanceValue = "pv"
    static let userActionSource = "uas"
}

// Usage
Pixel.fire(pixel: .newFeatureUsed, withAdditionalParameters: [
    PixelParameters.featureName: "voice_search",
    PixelParameters.userActionSource: "keyboard_shortcut"
])

Performance Metrics

Track performance metrics consistently:

// ✅ CORRECT - Performance tracking pattern
final class PerformanceTracker {
    static func trackPageLoad(duration: TimeInterval, url: URL) {
        let parameters = [
            PixelParameters.duration: String(format: "%.3f", duration),
            PixelParameters.domain: url.host ?? "unknown"
        ]
        
        Pixel.fire(pixel: .pageLoadTime, withAdditionalParameters: parameters)
    }
    
    static func trackMemoryUsage(bytes: Int, context: String) {
        let parameters = [
            PixelParameters.memoryUsage: "\(bytes)",
            PixelParameters.context: context
        ]
        
        Pixel.fire(pixel: .memoryUsage, withAdditionalParameters: parameters)
    }
}

Error Tracking

Track errors with context:

// ✅ CORRECT - Error tracking
extension Pixel {
    static func fireError(_ error: Error, context: String = "") {
        let parameters = [
            PixelParameters.errorType: String(describing: type(of: error)),
            PixelParameters.context: context
        ]
        
        Pixel.fire(pixel: .errorOccurred, withAdditionalParameters: parameters)
    }
}

// Usage
do {
    try await networkService.fetchData()
} catch {
    Pixel.fireError(error, context: "data_fetch")
    throw error
}

Feature Usage Tracking

Track feature adoption and usage:

// ✅ CORRECT - Feature usage tracking
final class FeatureTracker {
    static func trackFeatureUsage(_ feature: String, source: String = "") {
        let parameters = [
            PixelParameters.featureName: feature,
            PixelParameters.userActionSource: source
        ]
        
        Pixel.fire(pixel: .featureUsed, withAdditionalParameters: parameters)
    }
    
    static func trackFeatureEnabled(_ feature: String, enabled: Bool) {
        let parameters = [
            PixelParameters.featureName: feature,
            PixelParameters.enabled: enabled ? "true" : "false"
        ]
        
        Pixel.fire(pixel: .featureToggled, withAdditionalParameters: parameters)
    }
}

Privacy-Safe Analytics

Ensure all analytics respect privacy:

// ✅ CORRECT - Privacy-safe analytics
final class PrivacyAnalytics {
    static func trackWithPrivacy(event: String, value: String) {
        // Hash sensitive values
        let hashedValue = value.sha256Hash
        
        let parameters = [
            PixelParameters.hashedValue: hashedValue
        ]
        
        Pixel.fire(pixel: event, withAdditionalParameters: parameters)
    }
    
    static func trackAggregateMetric(metric: String, count: Int) {
        // Only send aggregate data, never individual events
        let parameters = [
            PixelParameters.metric: metric,
            PixelParameters.count: "\(count)"
        ]
        
        Pixel.fire(pixel: .aggregateMetric, withAdditionalParameters: parameters)
    }
}

See feature-flags.md for A/B test analytics and privacy-security.md for privacy requirements.