Skip to content

사용자 분석 도구

앱을 배포한 후에는 사용자들이 앱을 어떻게 사용하는지 분석하는 것이 중요합니다. 이를 통해 UX를 개선하고, 사용자 행동 패턴을 파악하며, 비즈니스 결정을 내리는 데 도움이 됩니다. 이 문서에서는 Flutter 앱에서 사용할 수 있는 주요 분석 도구인 Firebase Analytics와 PostHog를 살펴보겠습니다.

분석 도구를 사용하면 다음과 같은 이점이 있습니다:

  1. 사용자 행동 이해: 어떤 기능을 많이 사용하는지, 어디서 이탈하는지 파악
  2. 앱 성능 모니터링: 오류 발생률, 응답 시간 등 측정
  3. 비즈니스 목표 추적: 전환율, 사용자 유지율 등 측정
  4. A/B 테스트: 여러 변형을 테스트하여 최적의 UX 결정
  5. 마케팅 효과 측정: 다양한 마케팅 채널의 효과 분석

Firebase Analytics는 Google의 모바일 앱 분석 도구로, 무료이면서도 강력한 기능을 제공합니다.

먼저 Firebase Console에서 프로젝트를 생성하고 Flutter 앱을 등록해야 합니다:

  1. Firebase Console에 로그인하고 프로젝트 생성
  2. Flutter 앱 등록 (Android 및 iOS 패키지 이름 입력)
  3. 설정 파일 다운로드(google-services.jsonGoogleService-Info.plist)
  4. 각 파일을 프로젝트의 적절한 위치에 배치:
    • Android: android/app/google-services.json
    • iOS: ios/Runner/GoogleService-Info.plist

pubspec.yaml에 다음 패키지를 추가합니다:

dependencies:
firebase_core: ^2.15.0
firebase_analytics: ^10.4.4

그리고 패키지를 설치합니다:

Terminal window
flutter pub get

앱의 메인 파일에서 Firebase를 초기화합니다:

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// Firebase Analytics 인스턴스 생성
static FirebaseAnalytics analytics = FirebaseAnalytics.instance;
static FirebaseAnalyticsObserver observer =
FirebaseAnalyticsObserver(analytics: analytics);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Firebase Analytics Demo',
navigatorObservers: [observer], // 화면 전환 추적을 위한 설정
home: MyHomePage(),
);
}
}

Firebase Analytics에서 사용자 행동을 추적하려면 이벤트를 기록해야 합니다:

class AnalyticsService {
final FirebaseAnalytics _analytics = FirebaseAnalytics.instance;
// 화면 보기 이벤트 로깅
Future<void> logScreenView({
required String screenName,
String screenClass = 'Flutter',
}) async {
await _analytics.logScreenView(
screenName: screenName,
screenClass: screenClass,
);
}
// 로그인 이벤트 로깅
Future<void> logLogin({String? loginMethod}) async {
await _analytics.logLogin(loginMethod: loginMethod);
}
// 구매 이벤트 로깅
Future<void> logPurchase({
required double price,
required String currency,
required String itemId,
required String itemName,
}) async {
await _analytics.logPurchase(
currency: currency,
value: price,
items: [
AnalyticsEventItem(
itemId: itemId,
itemName: itemName,
price: price,
),
],
);
}
// 사용자 속성 설정
Future<void> setUserProperty({
required String name,
required String value,
}) async {
await _analytics.setUserProperty(name: name, value: value);
}
// 사용자 ID 설정 (식별 가능한 정보는 피해야 함)
Future<void> setUserId(String? id) async {
await _analytics.setUserId(id: id);
}
// 커스텀 이벤트 로깅
Future<void> logCustomEvent({
required String name,
Map<String, dynamic>? parameters,
}) async {
await _analytics.logEvent(
name: name,
parameters: parameters,
);
}
}

위의 서비스를 사용하여 앱 내에서 이벤트를 추적하는 방법:

class ProductDetailPage extends StatelessWidget {
final Product product;
final AnalyticsService _analyticsService = AnalyticsService();
ProductDetailPage({required this.product});
@override
Widget build(BuildContext context) {
// 화면이 표시될 때 화면 보기 이벤트 로깅
_analyticsService.logScreenView(
screenName: 'product_detail',
screenClass: 'ProductDetailPage',
);
return Scaffold(
appBar: AppBar(title: Text(product.name)),
body: Column(
children: [
// 제품 상세 정보...
ElevatedButton(
onPressed: () {
// 구매 버튼 클릭 시 이벤트 로깅
_analyticsService.logCustomEvent(
name: 'add_to_cart',
parameters: {
'item_id': product.id,
'item_name': product.name,
'item_price': product.price,
},
);
// 장바구니에 추가 로직...
},
child: Text('장바구니에 추가'),
),
],
),
);
}
}

Riverpod을 사용하는 경우 다음과 같이 분석 서비스를 제공할 수 있습니다:

import 'package:flutter_riverpod/flutter_riverpod.dart';
final analyticsServiceProvider = Provider<AnalyticsService>((ref) {
return AnalyticsService();
});
// 사용 예시
class ProductDetailPage extends ConsumerWidget {
final Product product;
ProductDetailPage({required this.product});
@override
Widget build(BuildContext context, WidgetRef ref) {
final analyticsService = ref.read(analyticsServiceProvider);
// 화면 로깅
analyticsService.logScreenView(
screenName: 'product_detail',
screenClass: 'ProductDetailPage',
);
// 나머지 UI 코드...
}
}

개발 중에는 이벤트가 올바르게 전송되는지 확인하는 것이 중요합니다. Firebase Analytics는 다음과 같은 디버그 기능을 제공합니다:

// 디버그 모드 활성화 (개발 중에만 사용)
await FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(true);
// iOS 디버그 모드 활성화
if (Platform.isIOS) {
await FirebaseAnalytics.instance.setIosAnalyticsCollectionEnabled(true);
}
// Android 디버그 모드 활성화
if (Platform.isAndroid) {
await FirebaseAnalytics.instance.setAndroidAnalyticsCollectionEnabled(true);
}

Firebase Console의 DebugView에서 실시간으로 전송되는 이벤트를 확인할 수 있습니다.

PostHog는 오픈소스 제품 분석 플랫폼으로, 자체 호스팅이 가능하고 고급 기능을 제공합니다.

  • 오픈소스: 자체 호스팅 가능
  • 제품 중심 분석: 사용자 행동 흐름 및 퍼널 분석
  • 세션 레코딩: 사용자 세션 녹화 및 재생
  • 히트맵: 클릭, 스크롤 등의 사용자 상호작용 시각화
  • 피처 플래그: A/B 테스트 및 기능 출시 제어
  • 개인정보 중심: EU GDPR 준수를 위한 기능 제공

pubspec.yaml에 다음 패키지를 추가합니다:

dependencies:
posthog_flutter: ^3.1.0

그리고 패키지를 설치합니다:

Terminal window
flutter pub get

앱의 메인 파일에서 PostHog를 초기화합니다:

import 'package:flutter/material.dart';
import 'package:posthog_flutter/posthog_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// PostHog 초기화
await Posthog.initAsync(
apiKey: 'YOUR_API_KEY',
options: PosthogOptions(
host: 'https://app.posthog.com', // 또는 자체 호스팅 URL
captureApplicationLifecycleEvents: true,
persistenceStrategy: PersistenceStrategy.memory,
flushAt: 20, // 이벤트가 20개 쌓이면 서버로 전송
flushInterval: 30, // 30초마다 서버로 전송
debug: true, // 개발 중에만 true로 설정
),
);
runApp(MyApp());
}

PostHog를 사용하여 이벤트를 추적하는 방법:

class PostHogAnalyticsService {
// 이벤트 캡처
void captureEvent(String eventName, {Map<String, dynamic>? properties}) {
Posthog.capture(
eventName: eventName,
properties: properties,
);
}
// 화면 보기 이벤트 캡처
void captureScreenView(String screenName, {Map<String, dynamic>? properties}) {
final screenProperties = {
'screen_name': screenName,
...?properties,
};
Posthog.capture(
eventName: 'Screen View',
properties: screenProperties,
);
}
// 사용자 식별
void identify(String userId, {Map<String, dynamic>? userProperties}) {
Posthog.identify(
userId: userId,
userProperties: userProperties,
);
}
// 사용자 속성 설정
void setUserProperties(Map<String, dynamic> properties) {
Posthog.identify(userProperties: properties);
}
// 그룹 설정 (팀, 조직 등)
void setGroup(String groupType, String groupKey) {
Posthog.group(
groupType: groupType,
groupKey: groupKey,
);
}
// 이벤트 플러시 (즉시 서버로 전송)
void flush() {
Posthog.flush();
}
// 추적 중지 (예: 로그아웃 시)
void reset() {
Posthog.reset();
}
}

PostHog의 주요 기능 중 하나는 피처 플래그(Feature Flags)로, 런타임에 특정 기능을 활성화하거나 비활성화할 수 있습니다:

class FeatureFlagService {
// 피처 플래그 값 가져오기
Future<bool> isFeatureEnabled(String flagKey) async {
return await Posthog.isFeatureEnabled(flagKey) ?? false;
}
// 모든 피처 플래그 가져오기
Future<Map<String, bool>> getAllFeatureFlags() async {
return await Posthog.getAllFeatureFlags() ?? {};
}
// 특정 피처 플래그와 연관된 페이로드 가져오기
Future<dynamic> getFeatureFlagPayload(String flagKey) async {
return await Posthog.getFeatureFlagPayload(flagKey);
}
// 새로운 피처 플래그 가져오기 (서버에서 새로고침)
Future<void> reloadFeatureFlags() async {
await Posthog.reloadFeatureFlags();
}
}
class NewFeatureWidget extends StatelessWidget {
final FeatureFlagService _featureFlagService = FeatureFlagService();
@override
Widget build(BuildContext context) {
return FutureBuilder<bool>(
future: _featureFlagService.isFeatureEnabled('new-ui-design'),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
final isNewDesignEnabled = snapshot.data ?? false;
return isNewDesignEnabled
? NewDesignWidget() // 새 디자인 위젯
: OldDesignWidget(); // 기존 디자인 위젯
},
);
}
}
import 'package:flutter_riverpod/flutter_riverpod.dart';
final posthogAnalyticsProvider = Provider<PostHogAnalyticsService>((ref) {
return PostHogAnalyticsService();
});
final featureFlagProvider = Provider<FeatureFlagService>((ref) {
return FeatureFlagService();
});
// 특정 기능 플래그 상태를 제공하는 provider
final newUiFeatureFlagProvider = FutureProvider<bool>((ref) async {
final featureFlagService = ref.read(featureFlagProvider);
return await featureFlagService.isFeatureEnabled('new-ui-design');
});
// 사용 예시
class NewFeatureScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// 분석 서비스 사용
final analyticsService = ref.read(posthogAnalyticsProvider);
analyticsService.captureScreenView('new_feature_screen');
// 피처 플래그 상태 확인
final isNewUiEnabled = ref.watch(newUiFeatureFlagProvider);
return isNewUiEnabled.when(
data: (isEnabled) => isEnabled ? NewUiWidget() : OldUiWidget(),
loading: () => CircularProgressIndicator(),
error: (_, __) => OldUiWidget(), // 오류 시 기본 UI 표시
);
}
}

수집한 분석 데이터를 실제로 활용하는 방법에 대해 알아보겠습니다.

일반적으로 추적해야 할 중요한 메트릭:

  1. 사용자 획득: 신규 사용자 수, 설치 수, 설치 출처
  2. 사용자 참여: 일/주/월간 활성 사용자(DAU/WAU/MAU), 세션 길이, 세션 빈도
  3. 사용자 유지: 리텐션 비율, 이탈률
  4. 전환: 가입 완료, 구매, 구독 등의 핵심 전환 이벤트
  5. 앱 성능: 크래시 비율, 응답 시간, ANR(App Not Responding) 발생 수

수집된 데이터를 기반으로 앱을 개선할 수 있는 예시:

  1. 사용자 여정 최적화:

    • 데이터: 결제 페이지에서 높은 이탈률 발견
    • 개선: 결제 프로세스 단순화, 오류 메시지 개선
  2. 핵심 기능 강화:

    • 데이터: 특정 기능의 사용 빈도가 매우 높음
    • 개선: 해당 기능을 더 쉽게 접근할 수 있도록 UI 개선
  3. 사용자 유지율 향상:

    • 데이터: 설치 후 3일 이내 이탈하는 사용자가 많음
    • 개선: 온보딩 개선, 초기 가치 제안 강화

분석 도구를 사용할 때 주의해야 할 사항:

  1. 개인정보 보호: GDPR, CCPA 등 데이터 보호 규정 준수
  2. 사용자 동의: 추적 전에 사용자 동의 획득
  3. 과도한 추적 방지: 필요한 데이터만 수집
  4. 식별 정보 제한: 개인 식별 정보는 최소화
  5. 데이터 보관 정책: 불필요한 데이터는 적절히 폐기

Firebase Analytics와 PostHog 중 어떤 것을 선택해야 할지 결정하는 기준:

  • 무료로 시작하고 싶을 때
  • Google 생태계의 다른 서비스와 통합이 필요할 때
  • 간단한 이벤트 추적과 기본적인 분석 기능이 필요할 때
  • 모바일 앱 성능에 민감한 경우 (경량화된 SDK)
  • 데이터 소유권과 개인정보 보호가 중요할 때 (자체 호스팅 가능)
  • 세션 레코딩, 히트맵 등 고급 분석 기능이 필요할 때
  • A/B 테스트와 피처 플래그가 필요할 때
  • 오픈소스 솔루션을 선호할 때

사용자 분석 도구는 앱의 개선과 사용자 경험 향상에 중요한 역할을 합니다. Firebase Analytics는 시작하기 쉽고 Google 생태계와의 통합이 뛰어나며, PostHog는 더 많은 고급 기능과 데이터 소유권을 제공합니다.

애플리케이션의 요구사항, 예산, 개인정보 보호 요구 등을 고려하여 적절한 도구를 선택하고, 사용자 행동을 체계적으로 추적하여 데이터 기반 의사 결정을 내리는 것이 중요합니다. 이러한 도구를 활용하면 사용자의 필요와 행동 패턴을 더 잘 이해하고, 더 나은 앱 경험을 제공할 수 있습니다.