161 lines
4.4 KiB
Markdown
Executable File
161 lines
4.4 KiB
Markdown
Executable File
---
|
|
source: ~/DuckDuckGo/apple-browsers.git/main/.cursor/rules/analytics-patterns.mdc
|
|
confidence: 0.9
|
|
namespace: work
|
|
last_synced: 2026-04-28
|
|
alwaysApply: false
|
|
---
|
|
|
|
# Analytics and Pixel Patterns
|
|
|
|
## Structured Pixel Events
|
|
Use the existing Pixel.fire pattern with structured event definitions:
|
|
|
|
```swift
|
|
// ✅ 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:
|
|
|
|
```swift
|
|
// ✅ 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:
|
|
|
|
```swift
|
|
// ✅ 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:
|
|
|
|
```swift
|
|
// ✅ 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:
|
|
|
|
```swift
|
|
// ✅ 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:
|
|
|
|
```swift
|
|
// ✅ 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.
|