
Analytics Patterns
- 18 installs
- 60 repo stars
- Updated June 14, 2026
- ahmed3elshaer/everything-claude-code-mobile
analytics-patterns is a Claude Code skill for integrating consent-gated event, screen, and user-property analytics into Android and iOS apps.
About
analytics-patterns is a Claude Code skill for integrating analytics into mobile apps on Android and iOS. It defines an AnalyticsProvider interface, a consent-gated multi-provider manager, and typed event data classes for e-commerce and engagement events. It shows Firebase Analytics setup, screen tracking with lifecycle observers, and user properties, so developers can instrument a mobile app while respecting analytics consent.
- Analytics integration patterns for Android and iOS with a provider abstraction
- Firebase Analytics setup, event/screen tracking, and user properties
- Consent-gated multi-provider manager for privacy compliance
Analytics Patterns by the numbers
- 18 all-time installs (skills.sh)
- Ranked #767 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
analytics-patterns capabilities & compatibility
- Capabilities
- analytics integration · event tracking · screen tracking
- Works with
- gcp
- Use cases
- data analysis
- Pricing
- Free
What analytics-patterns says it does
Analytics integration patterns - event tracking, screen tracking, user properties, Firebase Analytics, custom analytics providers, and privacy compliance.
if (!consentManager.hasAnalyticsConsent()) return
npx skills add https://github.com/ahmed3elshaer/everything-claude-code-mobile --skill analytics-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 18 |
|---|---|
| repo stars | ★ 60 |
| Last updated | June 14, 2026 |
| Repository | ahmed3elshaer/everything-claude-code-mobile ↗ |
What it does
Instrument a mobile app with consent-gated event, screen, and user-property tracking across Firebase and custom analytics providers.
Who is it for?
Wiring Firebase and custom analytics into a mobile app behind a provider abstraction with consent checks.
Skip if: Web analytics or backend event pipelines; it targets Android and iOS clients.
When should I use this skill?
Adding event tracking, screen tracking, or user properties to a mobile app with privacy consent.
What you get
A provider-abstracted, consent-gated analytics layer tracking events, screens, and user properties.
- A provider-abstracted analytics layer
- Typed analytics events
- Consent-gated tracking code
Files
Analytics Integration Patterns
Architecture
AnalyticsProvider Interface (Kotlin)
interface AnalyticsProvider {
fun logEvent(name: String, params: Map<String, Any> = emptyMap())
fun setUserProperty(name: String, value: String)
fun setUserId(userId: String?)
fun logScreenView(screenName: String, screenClass: String? = null)
}AnalyticsProvider Protocol (Swift)
protocol AnalyticsProvider {
func logEvent(_ name: String, parameters: [String: Any])
func setUserProperty(_ value: String?, forName name: String)
func setUserId(_ userId: String?)
func logScreenView(screenName: String, screenClass: String?)
}Multi-Provider Analytics Manager
class AnalyticsManager(
private val providers: List<AnalyticsProvider>,
private val consentManager: ConsentManager
) {
fun logEvent(name: String, params: Map<String, Any> = emptyMap()) {
if (!consentManager.hasAnalyticsConsent()) return
providers.forEach { it.logEvent(name, params) }
}
fun setUserProperty(name: String, value: String) {
if (!consentManager.hasAnalyticsConsent()) return
providers.forEach { it.setUserProperty(name, value) }
}
fun setUserId(userId: String?) {
providers.forEach { it.setUserId(userId) }
}
fun logScreenView(screenName: String, screenClass: String? = null) {
if (!consentManager.hasAnalyticsConsent()) return
providers.forEach { it.logScreenView(screenName, screenClass) }
}
}Event Data Classes
sealed class AnalyticsEvent(
val name: String,
val params: Map<String, Any> = emptyMap()
) {
// E-commerce
class ViewProduct(productId: String, category: String) : AnalyticsEvent(
name = "view_product",
params = mapOf("product_id" to productId, "category" to category)
)
class AddToCart(productId: String, price: Double, quantity: Int) : AnalyticsEvent(
name = "add_to_cart",
params = mapOf("product_id" to productId, "price" to price, "quantity" to quantity)
)
class Purchase(orderId: String, total: Double, currency: String) : AnalyticsEvent(
name = "purchase",
params = mapOf("order_id" to orderId, "total" to total, "currency" to currency)
)
// Engagement
class Search(query: String, resultCount: Int) : AnalyticsEvent(
name = "search",
params = mapOf("query" to query, "result_count" to resultCount)
)
class ShareContent(contentType: String, itemId: String) : AnalyticsEvent(
name = "share_content",
params = mapOf("content_type" to contentType, "item_id" to itemId)
)
}
// Usage
analytics.logEvent(AnalyticsEvent.ViewProduct("sku-123", "electronics"))---
Android / Firebase Analytics
Setup and Initialization
class FirebaseAnalyticsProvider(context: Context) : AnalyticsProvider {
private val firebaseAnalytics = FirebaseAnalytics.getInstance(context)
override fun logEvent(name: String, params: Map<String, Any>) {
val bundle = Bundle().apply {
params.forEach { (key, value) ->
when (value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Double -> putDouble(key, value)
is Boolean -> putBoolean(key, value)
}
}
}
firebaseAnalytics.logEvent(name, bundle)
}
override fun setUserProperty(name: String, value: String) {
firebaseAnalytics.setUserProperty(name, value)
}
override fun setUserId(userId: String?) {
firebaseAnalytics.setUserId(userId)
}
override fun logScreenView(screenName: String, screenClass: String?) {
val bundle = Bundle().apply {
putString(FirebaseAnalytics.Param.SCREEN_NAME, screenName)
screenClass?.let { putString(FirebaseAnalytics.Param.SCREEN_CLASS, it) }
}
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, bundle)
}
}Screen Tracking with Lifecycle Observer
@Composable
fun TrackScreen(screenName: String, analytics: AnalyticsManager) {
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME) {
analytics.logScreenView(screenName)
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
}
}
// Usage in a screen composable
@Composable
fun ProductListScreen(analytics: AnalyticsManager) {
TrackScreen("product_list", analytics)
// Screen content...
}---
iOS Analytics
Firebase Analytics Provider
final class FirebaseAnalyticsProvider: AnalyticsProvider {
func logEvent(_ name: String, parameters: [String: Any]) {
Analytics.logEvent(name, parameters: parameters)
}
func setUserProperty(_ value: String?, forName name: String) {
Analytics.setUserProperty(value, forName: name)
}
func setUserId(_ userId: String?) {
Analytics.setUserID(userId)
}
func logScreenView(screenName: String, screenClass: String?) {
Analytics.logEvent(AnalyticsEventScreenView, parameters: [
AnalyticsParameterScreenName: screenName,
AnalyticsParameterScreenClass: screenClass ?? ""
])
}
}Screen Tracking with SwiftUI
struct AnalyticsScreenModifier: ViewModifier {
let screenName: String
@EnvironmentObject var analytics: AnalyticsManager
func body(content: Content) -> some View {
content.onAppear {
analytics.logScreenView(screenName: screenName)
}
}
}
extension View {
func trackScreen(_ name: String) -> some View {
modifier(AnalyticsScreenModifier(screenName: name))
}
}
// Usage
struct ProductListView: View {
var body: some View {
List { /* ... */ }
.trackScreen("product_list")
}
}App Tracking Transparency (ATT)
import AppTrackingTransparency
func requestTrackingPermission() async -> ATTrackingManager.AuthorizationStatus {
await ATTrackingManager.requestTrackingAuthorization()
}
// Call after app launch delay (Apple requirement)
func onAppBecomeActive() {
Task {
let status = await requestTrackingPermission()
switch status {
case .authorized:
analytics.enableFullTracking()
case .denied, .restricted:
analytics.enableLimitedTracking()
case .notDetermined:
break
@unknown default:
break
}
}
}---
Event Naming Conventions
| Pattern | Example | Notes |
|---|---|---|
noun_verb | product_viewed | Past tense for completed actions |
noun_verb | cart_item_added | Include context noun |
feature_action | search_performed | Feature-scoped |
screen_action | settings_opened | Screen-scoped |
Rules:
- Use
snake_caseconsistently - Max 40 characters per event name
- Max 25 custom parameters per event
- Prefix custom events to avoid Firebase reserved names
User Property Design
// Set on login
analytics.setUserProperty("subscription_tier", "premium")
analytics.setUserProperty("account_age_days", "365")
analytics.setUserProperty("preferred_language", "en")Properties should be low-cardinality (not unique per user). Use for segmentation, not identification.
---
Privacy: Consent Management
class ConsentManager(private val prefs: SharedPreferences) {
fun hasAnalyticsConsent(): Boolean = prefs.getBoolean("analytics_consent", false)
fun hasAdConsent(): Boolean = prefs.getBoolean("ad_consent", false)
fun updateConsent(analytics: Boolean, ads: Boolean) {
prefs.edit()
.putBoolean("analytics_consent", analytics)
.putBoolean("ad_consent", ads)
.apply()
// Disable Firebase collection if consent revoked
FirebaseAnalytics.getInstance(context).setAnalyticsCollectionEnabled(analytics)
}
}GDPR/CCPA checklist:
- Show consent dialog before any tracking
- Allow granular opt-in/opt-out
- Provide data deletion request mechanism
- Do not track until consent is given
- Log consent timestamps for audit
- Respect platform-level tracking preferences (ATT on iOS)
Related skills
FAQ
How does analytics-patterns handle privacy?
A consent-gated AnalyticsManager skips event, property, and screen logging unless analytics consent is present.
Does it support multiple analytics backends?
Yes, it uses an AnalyticsProvider interface so multiple providers, including Firebase, receive the same events.