Skip to content

Repository files navigation

XiAnalytics

A privacy-focused iOS analytics SDK for Swift 6.2+ and iOS 17+. Track user flows, interactions, and app performance while minimizing App Store privacy declarations.

Features

✅ Privacy-First Design

  • No personally identifiable information (PII) collection
  • Uses Apple's privacy-preserving frameworks (MetricKit)
  • Minimizes App Store privacy impact
  • All data stored locally with optional backend sync

✅ Comprehensive Tracking

  • User interactions and flows
  • Screen views and navigation
  • App lifecycle events
  • Performance metrics (via MetricKit)
  • Custom events
  • Error tracking

✅ Modern Swift

  • Swift 6.2 with strict concurrency
  • Actor-based thread safety
  • Async/await throughout
  • Type-safe property values

✅ Flexible Storage

  • In-memory or file system storage
  • Automatic cleanup and limits
  • Optional backend synchronization

Installation

Swift Package Manager

Add XiAnalytics to your project in Xcode:

  1. File → Add Package Dependencies
  2. Enter the repository URL
  3. Select the version you want to use

Or add it to your Package.swift:

dependencies: [
    .package(url: "https://github.com/alirezarzg/xiAnalytics.git", from: "1.0.0")
]

Quick Start

1. Configure the SDK

In your AppDelegate or App struct:

import XiAnalytics

@main
struct MyApp: App {
    init() {
        // Configure with default settings
        XiAnalytics.shared.configure(with: .default)

        // Or customize the configuration
        let config = AnalyticsConfiguration(
            maxStoredEvents: 10_000,
            autoTrackLifecycle: true,
            collectPerformanceMetrics: true,
            backendURL: URL(string: "https://api.example.com/analytics"),
            globalProperties: [
                "app_name": .string("MyApp"),
                "environment": .string("production")
            ],
            logLevel: .warning
        )
        XiAnalytics.shared.configure(with: config)
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

2. Track Events

import XiAnalytics

// Track a screen view
await XiAnalytics.shared.trackScreen("HomeScreen")

// Track a button tap
await XiAnalytics.shared.trackButtonTap("login_button")

// Track a custom interaction
await XiAnalytics.shared.trackInteraction(
    action: "swipe",
    target: "card_stack",
    properties: [
        "direction": .string("left"),
        "card_index": .int(3)
    ]
)

// Track a custom event
await XiAnalytics.shared.track(
    name: "purchase_completed",
    category: .custom,
    properties: [
        "product_id": .string("premium_subscription"),
        "price": .double(9.99),
        "currency": .string("USD")
    ]
)

// Track performance
await XiAnalytics.shared.trackPerformance(
    metric: "api_response_time",
    value: 1.234,
    properties: [
        "endpoint": .string("/api/users")
    ]
)

// Track errors
await XiAnalytics.shared.trackError(
    errorType: "network",
    message: "Failed to load user data",
    properties: [
        "status_code": .int(500)
    ]
)

3. SwiftUI Integration

Create a ViewModifier for automatic screen tracking:

import SwiftUI
import XiAnalytics

struct AnalyticsScreenModifier: ViewModifier {
    let screenName: String

    func body(content: Content) -> some View {
        content
            .task {
                await XiAnalytics.shared.trackScreen(screenName)
            }
    }
}

extension View {
    func trackScreen(_ name: String) -> some View {
        modifier(AnalyticsScreenModifier(screenName: name))
    }
}

// Usage
struct HomeView: View {
    var body: some View {
        VStack {
            Text("Home")
        }
        .trackScreen("HomeScreen")
    }
}

4. UIKit Integration

import UIKit
import XiAnalytics

class HomeViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        Task {
            await XiAnalytics.shared.trackScreen("HomeScreen")
        }
    }

    @IBAction func loginButtonTapped(_ sender: UIButton) {
        Task {
            await XiAnalytics.shared.trackButtonTap("login_button")
        }
    }
}

Configuration Options

let config = AnalyticsConfiguration(
    // Maximum events to store locally (default: 10,000)
    maxStoredEvents: 10_000,

    // Auto-track app lifecycle events (default: true)
    autoTrackLifecycle: true,

    // Collect MetricKit performance data (default: true)
    collectPerformanceMetrics: true,

    // Batch size for network sync (default: 100)
    syncBatchSize: 100,

    // Session timeout in seconds (default: 1800 = 30 minutes)
    sessionTimeoutSeconds: 1800,

    // Optional backend URL for syncing
    backendURL: URL(string: "https://api.example.com/analytics"),

    // Global properties attached to all events
    globalProperties: [
        "app_version": .string("1.0.0"),
        "environment": .string("production")
    ],

    // Storage type (default: .fileSystem)
    storageType: .fileSystem, // or .memory

    // Log level (default: .warning)
    logLevel: .debug // .none, .error, .warning, .info, .debug
)

Advanced Usage

Manual Session Management

// Start a new session manually
await XiAnalytics.shared.startNewSession()

// End the current session
await XiAnalytics.shared.endSession()

Syncing to Backend

// Sync a batch of events
try await XiAnalytics.shared.sync()

// Sync all stored events
try await XiAnalytics.shared.syncAll()

// Flush queued events to storage
await XiAnalytics.shared.flush()

Statistics

let stats = await XiAnalytics.shared.getStatistics()
print("Stored events: \(stats.storedEvents)")
print("Queued events: \(stats.queuedEvents)")
print("Total events: \(stats.totalEvents)")

Clear Data

// Clear all stored analytics data
try await XiAnalytics.shared.clearAllData()

MetricKit Integration

XiAnalytics automatically collects performance metrics using Apple's MetricKit framework when collectPerformanceMetrics is enabled. This includes:

  • CPU Usage: Cumulative CPU time
  • Memory: Peak and average memory usage
  • App Launch Time: Time to first draw
  • Battery: Energy consumption metrics
  • Scrolling Performance: Hitch time ratio
  • Crashes: Crash diagnostics
  • Hangs: App hang detection
  • Disk Writes: Excessive disk write warnings

All MetricKit data is collected in a privacy-preserving way and automatically converted to analytics events.

Privacy Considerations

What XiAnalytics Does NOT Collect

❌ User identifiers (no user IDs, email, names) ❌ Device identifiers (no IDFA, device UUID) ❌ Location data ❌ Contact information ❌ User content ❌ Browsing history

What XiAnalytics DOES Collect

✅ App version and build number ✅ iOS version ✅ Device type (iPhone, iPad - generic model) ✅ Locale/language ✅ Event timestamps ✅ Performance metrics (via MetricKit) ✅ Custom event properties you define

App Store Privacy Impact

With default settings, you should be able to declare:

Data Not Collected:

  • Contact Info
  • User Content
  • Browsing History
  • Search History
  • Identifiers
  • Location
  • Sensitive Info

Data Collected (Not Linked to User):

  • Product Interaction (analytics events)
  • Crash Data (from MetricKit)
  • Performance Data (from MetricKit)
  • Other Diagnostic Data

Note: Always review your specific implementation and consult Apple's privacy guidelines.

Backend API Format

If you provide a backendURL, events are sent as JSON POST requests:

[
  {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "name": "screen_view",
    "category": "screen_view",
    "timestamp": "2024-01-15T10:30:00Z",
    "sessionId": "987fcdeb-51a2-43d7-8f9e-123456789abc",
    "properties": {
      "screen_name": "HomeScreen"
    }
  }
]

Expected response: HTTP 200-299 status code.

Best Practices

1. Use Descriptive Event Names

// Good
await XiAnalytics.shared.track(name: "checkout_completed", category: .custom)

// Avoid
await XiAnalytics.shared.track(name: "event1", category: .custom)

2. Add Meaningful Properties

await XiAnalytics.shared.trackScreen(
    "ProductDetail",
    properties: [
        "product_category": .string("electronics"),
        "price_range": .string("high"),
        "in_stock": .bool(true)
    ]
)

3. Track User Flows

// User registration flow
await XiAnalytics.shared.trackScreen("RegistrationStart")
await XiAnalytics.shared.trackInteraction(action: "tap", target: "email_field")
await XiAnalytics.shared.trackInteraction(action: "tap", target: "password_field")
await XiAnalytics.shared.trackInteraction(action: "tap", target: "submit_button")
await XiAnalytics.shared.track(name: "registration_completed", category: .custom)

4. Flush Before App Termination

XiAnalytics automatically flushes on app backgrounding/termination if autoTrackLifecycle is enabled. For manual control:

await XiAnalytics.shared.flush()

5. Sync Periodically

// In your app, sync daily or when appropriate
Task {
    try? await XiAnalytics.shared.sync()
}

Requirements

  • iOS 17.0+
  • Swift 6.0+
  • Xcode 16.0+

License

MIT License - See LICENSE file for details

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues and feature requests, please use the GitHub issue tracker.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages