Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
ahmed3elshaer avatar

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)
At a glance

analytics-patterns capabilities & compatibility

Capabilities
analytics integration · event tracking · screen tracking
Works with
gcp
Use cases
data analysis
Pricing
Free
From the docs

What analytics-patterns says it does

Analytics integration patterns - event tracking, screen tracking, user properties, Firebase Analytics, custom analytics providers, and privacy compliance.
SKILL.md
if (!consentManager.hasAnalyticsConsent()) return
SKILL.md
npx skills add https://github.com/ahmed3elshaer/everything-claude-code-mobile --skill analytics-patterns

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs18
repo stars60
Last updatedJune 14, 2026
Repositoryahmed3elshaer/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

SKILL.mdMarkdownGitHub ↗

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

PatternExampleNotes
noun_verbproduct_viewedPast tense for completed actions
noun_verbcart_item_addedInclude context noun
feature_actionsearch_performedFeature-scoped
screen_actionsettings_openedScreen-scoped

Rules:

  • Use snake_case consistently
  • 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.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.