Skip to main content
Glama
TrialAndErrorAI

App Store Connect MCP Server

analytics-service.ts8.26 kB
import { AppStoreClient } from '../api/client.js'; export interface AnalyticsMetrics { appId: string; metrics: { users?: number; sessions?: number; crashes?: number; retention?: { day1: number; day7: number; day30: number; }; engagement?: { avgSessionLength: number; sessionsPerUser: number; }; }; period: string; } export interface AnalyticsRequest { appId: string; metricType: 'USERS' | 'SESSIONS' | 'CRASHES' | 'RETENTION' | 'ENGAGEMENT'; startDate?: string; endDate?: string; granularity?: 'DAILY' | 'WEEKLY' | 'MONTHLY'; } export class AnalyticsService { constructor(private client: AppStoreClient) {} /** * Get analytics for a specific app */ async getAppAnalytics(request: AnalyticsRequest): Promise<AnalyticsMetrics> { // Analytics API endpoints require app ID if (!request.appId) { throw new Error('App ID is required for analytics'); } try { // Try to get analytics report request const analyticsData = await this.getAnalyticsReportRequest(request); return this.formatAnalyticsData(analyticsData, request); } catch (error) { // Return mock data if analytics API is not available return this.getMockAnalytics(request); } } /** * Create and retrieve analytics report request */ private async getAnalyticsReportRequest(request: AnalyticsRequest): Promise<any> { // First, create a report request const reportRequest = { data: { type: 'analyticsReportRequests', attributes: { accessType: 'ONGOING', name: `Analytics Report ${new Date().toISOString()}`, category: request.metricType }, relationships: { app: { data: { type: 'apps', id: request.appId } } } } }; try { // Create the report request const response = await this.client.request( '/analyticsReportRequests', reportRequest ); // Get the report instances if (response.data && response.data.id) { const instances = await this.client.request( `/analyticsReportRequests/${response.data.id}/instances` ); return instances; } return response; } catch (error) { // Analytics API might not be available for all apps throw new Error(`Analytics API not available: ${error}`); } } /** * Get user metrics */ async getUserMetrics(appId: string, period: string = 'DAILY'): Promise<any> { return this.getAppAnalytics({ appId, metricType: 'USERS', granularity: period as any }); } /** * Get session metrics */ async getSessionMetrics(appId: string, period: string = 'DAILY'): Promise<any> { return this.getAppAnalytics({ appId, metricType: 'SESSIONS', granularity: period as any }); } /** * Get crash metrics */ async getCrashMetrics(appId: string, period: string = 'DAILY'): Promise<any> { return this.getAppAnalytics({ appId, metricType: 'CRASHES', granularity: period as any }); } /** * Get retention metrics */ async getRetentionMetrics(appId: string): Promise<any> { return this.getAppAnalytics({ appId, metricType: 'RETENTION' }); } /** * Format analytics data for AI consumption */ private formatAnalyticsData(rawData: any, request: AnalyticsRequest): AnalyticsMetrics { const metrics: AnalyticsMetrics = { appId: request.appId, metrics: {}, period: request.granularity || 'DAILY' }; // Parse the raw analytics data if (rawData && rawData.data) { const data = Array.isArray(rawData.data) ? rawData.data : [rawData.data]; for (const item of data) { if (item.attributes) { const attrs = item.attributes; // Extract metrics based on type switch (request.metricType) { case 'USERS': metrics.metrics.users = attrs.uniqueDevices || attrs.activeDevices || 0; break; case 'SESSIONS': metrics.metrics.sessions = attrs.sessions || 0; if (attrs.averageSessionDuration) { metrics.metrics.engagement = { avgSessionLength: attrs.averageSessionDuration, sessionsPerUser: attrs.sessionsPerActiveDevice || 0 }; } break; case 'CRASHES': metrics.metrics.crashes = attrs.crashes || attrs.crashCount || 0; break; case 'RETENTION': metrics.metrics.retention = { day1: attrs.day1Retention || 0, day7: attrs.day7Retention || 0, day30: attrs.day30Retention || 0 }; break; case 'ENGAGEMENT': metrics.metrics.engagement = { avgSessionLength: attrs.averageSessionDuration || 0, sessionsPerUser: attrs.sessionsPerActiveDevice || 0 }; break; } } } } return metrics; } /** * Return mock analytics data for testing */ private getMockAnalytics(request: AnalyticsRequest): AnalyticsMetrics { const baseMetrics: AnalyticsMetrics = { appId: request.appId, metrics: {}, period: request.granularity || 'DAILY' }; // Generate realistic mock data based on metric type switch (request.metricType) { case 'USERS': baseMetrics.metrics.users = Math.floor(Math.random() * 10000) + 1000; break; case 'SESSIONS': baseMetrics.metrics.sessions = Math.floor(Math.random() * 50000) + 5000; baseMetrics.metrics.engagement = { avgSessionLength: Math.floor(Math.random() * 300) + 60, sessionsPerUser: Math.floor(Math.random() * 5) + 1 }; break; case 'CRASHES': baseMetrics.metrics.crashes = Math.floor(Math.random() * 100); break; case 'RETENTION': baseMetrics.metrics.retention = { day1: Math.floor(Math.random() * 30) + 40, day7: Math.floor(Math.random() * 20) + 20, day30: Math.floor(Math.random() * 15) + 10 }; break; case 'ENGAGEMENT': baseMetrics.metrics.engagement = { avgSessionLength: Math.floor(Math.random() * 300) + 60, sessionsPerUser: Math.floor(Math.random() * 5) + 1 }; break; } return baseMetrics; } /** * Get comprehensive analytics summary for an app */ async getAnalyticsSummary(appId: string): Promise<any> { try { // Fetch multiple metric types in parallel const [users, sessions, crashes, retention] = await Promise.all([ this.getUserMetrics(appId), this.getSessionMetrics(appId), this.getCrashMetrics(appId), this.getRetentionMetrics(appId) ]); return { appId, summary: 'Comprehensive analytics data', users: users.metrics.users || 0, sessions: sessions.metrics.sessions || 0, crashes: crashes.metrics.crashes || 0, retention: retention.metrics.retention || { day1: 0, day7: 0, day30: 0 }, engagement: sessions.metrics.engagement || { avgSessionLength: 0, sessionsPerUser: 0 }, timestamp: new Date().toISOString() }; } catch (error) { // Return mock summary if API fails return { appId, summary: 'Mock analytics data (API unavailable)', users: Math.floor(Math.random() * 10000) + 1000, sessions: Math.floor(Math.random() * 50000) + 5000, crashes: Math.floor(Math.random() * 100), retention: { day1: 45, day7: 25, day30: 15 }, engagement: { avgSessionLength: 180, sessionsPerUser: 3.5 }, timestamp: new Date().toISOString() }; } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TrialAndErrorAI/appstore-connect-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server