Skip to main content
Deprecated: This is a beta service. Future versions may have changes to the telemetry API structure.

Overview

The BetaTelemetryServiceApi provides methods for reporting system information and resource usage to ZITADEL analytics. This helps with system monitoring, capacity planning, and feature usage tracking.

Initialization

require 'zitadel/client'

client = Zitadel::Client::ApiClient.new
client.config.access_token = 'your_access_token'

telemetry_service = Zitadel::Client::Api::BetaTelemetryServiceApi.new(client)
Telemetry reporting is typically used by system administrators and automated monitoring tools.

Key Methods

Base Information Reporting

beta_telemetry_service_report_base_information_request
object
required
System information to report
request = Zitadel::Client::Models::BetaTelemetryServiceReportBaseInformationRequest.new(
  system_id: 'system_unique_id',
  version: '2.x.x',
  instances: [
    {
      instance_id: 'instance_1',
      creation_date: '2024-01-15T10:00:00Z',
      domains: ['auth.example.com', 'login.example.com']
    },
    {
      instance_id: 'instance_2',
      creation_date: '2024-02-01T15:30:00Z',
      domains: ['auth.acme.com']
    }
  ]
)

response = telemetry_service.report_base_information(request)

puts "Report ID: #{response.report_id}"
puts "System ID: #{response.system_id}"
Returns: BetaTelemetryServiceReportBaseInformationResponse
The report ID can be used to link subsequent resource count reports.

Resource Count Reporting

beta_telemetry_service_report_resource_counts_request
object
required
Resource count information
request = Zitadel::Client::Models::BetaTelemetryServiceReportResourceCountsRequest.new(
  system_id: 'system_unique_id',
  report_id: response.report_id, # From base information report
  resource_counts: [
    {
      organization_id: 'org_1',
      user_count: 150,
      project_count: 5,
      application_count: 12,
      session_count: 45,
      action_count: 8
    },
    {
      organization_id: 'org_2',
      user_count: 320,
      project_count: 10,
      application_count: 25,
      session_count: 120,
      action_count: 15
    }
  ]
)

response = telemetry_service.report_resource_counts(request)

puts "Resource counts reported successfully"
puts "Report ID: #{response.report_id}"
Returns: BetaTelemetryServiceReportResourceCountsResponse
Resource counts can be reported in multiple batches using the same report ID.

Reporting Workflow

Complete Telemetry Report

def generate_telemetry_report
  # Step 1: Report base information
  puts "Collecting system information..."
  
  base_request = Zitadel::Client::Models::BetaTelemetryServiceReportBaseInformationRequest.new(
    system_id: ENV['ZITADEL_SYSTEM_ID'],
    version: get_zitadel_version,
    instances: collect_instances
  )
  
  base_response = telemetry_service.report_base_information(base_request)
  report_id = base_response.report_id
  
  puts "Base report created: #{report_id}"
  
  # Step 2: Collect resource counts
  puts "Collecting resource counts..."
  organizations = list_all_organizations
  
  # Report in batches (e.g., 100 orgs at a time)
  organizations.each_slice(100) do |org_batch|
    resource_counts = org_batch.map do |org|
      {
        organization_id: org.id,
        user_count: count_users(org.id),
        project_count: count_projects(org.id),
        application_count: count_applications(org.id),
        session_count: count_active_sessions(org.id),
        action_count: count_actions(org.id)
      }
    end
    
    count_request = Zitadel::Client::Models::BetaTelemetryServiceReportResourceCountsRequest.new(
      system_id: ENV['ZITADEL_SYSTEM_ID'],
      report_id: report_id,
      resource_counts: resource_counts
    )
    
    telemetry_service.report_resource_counts(count_request)
    puts "Reported counts for #{org_batch.size} organizations"
  end
  
  puts "Telemetry report complete!"
  report_id
end

Use Cases

Scheduled Daily Report

require 'rufus-scheduler'

scheduler = Rufus::Scheduler.new

# Report telemetry daily at 2 AM
scheduler.cron '0 2 * * *' do
  begin
    puts "Starting daily telemetry report..."
    report_id = generate_telemetry_report
    puts "Daily report completed: #{report_id}"
  rescue => e
    puts "Error generating report: #{e.message}"
  end
end

Monitor System Growth

def system_growth_metrics
  # Get all instances
  instances = instance_service.list_instances({}).result
  
  # Prepare base information
  base_request = Zitadel::Client::Models::BetaTelemetryServiceReportBaseInformationRequest.new(
    system_id: ENV['ZITADEL_SYSTEM_ID'],
    version: ZITADEL_VERSION,
    instances: instances.map { |i|
      {
        instance_id: i.id,
        creation_date: i.creation_date,
        domains: i.domains
      }
    }
  )
  
  base_response = telemetry_service.report_base_information(base_request)
  
  # Collect aggregate metrics
  total_users = 0
  total_projects = 0
  total_apps = 0
  
  resource_counts = organizations.map do |org|
    user_count = count_users(org.id)
    project_count = count_projects(org.id)
    app_count = count_applications(org.id)
    
    total_users += user_count
    total_projects += project_count
    total_apps += app_count
    
    {
      organization_id: org.id,
      user_count: user_count,
      project_count: project_count,
      application_count: app_count
    }
  end
  
  # Report counts
  count_request = Zitadel::Client::Models::BetaTelemetryServiceReportResourceCountsRequest.new(
    system_id: ENV['ZITADEL_SYSTEM_ID'],
    report_id: base_response.report_id,
    resource_counts: resource_counts
  )
  
  telemetry_service.report_resource_counts(count_request)
  
  # Return summary
  {
    instances: instances.size,
    organizations: organizations.size,
    users: total_users,
    projects: total_projects,
    applications: total_apps
  }
end

Capacity Planning Report

def capacity_planning_report
  metrics = system_growth_metrics
  
  # Calculate averages
  avg_users_per_org = metrics[:users] / [metrics[:organizations], 1].max
  avg_projects_per_org = metrics[:projects] / [metrics[:organizations], 1].max
  avg_apps_per_project = metrics[:applications] / [metrics[:projects], 1].max
  
  report = <<~REPORT
    Capacity Planning Report
    =======================
    
    System Overview:
    - Instances: #{metrics[:instances]}
    - Organizations: #{metrics[:organizations]}
    - Total Users: #{metrics[:users]}
    - Total Projects: #{metrics[:projects]}
    - Total Applications: #{metrics[:applications]}
    
    Averages:
    - Users per Organization: #{avg_users_per_org.round(1)}
    - Projects per Organization: #{avg_projects_per_org.round(1)}
    - Applications per Project: #{avg_apps_per_project.round(1)}
    
    Growth Rate: (calculate based on historical data)
  REPORT
  
  puts report
  report
end

Feature Usage Tracking

def track_feature_usage
  organizations = list_all_organizations
  
  feature_stats = {
    actions_enabled: 0,
    mfa_enforced: 0,
    custom_domains: 0,
    external_idp: 0
  }
  
  resource_counts = organizations.map do |org|
    # Check features
    features = get_organization_features(org.id)
    feature_stats[:actions_enabled] += 1 if features.actions&.enabled
    
    settings = get_organization_settings(org.id)
    feature_stats[:mfa_enforced] += 1 if settings.force_mfa
    
    # Count resources
    {
      organization_id: org.id,
      user_count: count_users(org.id),
      action_count: count_actions(org.id),
      # Add custom metrics
      custom_metrics: {
        actions_enabled: features.actions&.enabled,
        mfa_enforced: settings.force_mfa
      }
    }
  end
  
  # Report to telemetry
  base = telemetry_service.report_base_information(...)
  telemetry_service.report_resource_counts(
    system_id: ENV['ZITADEL_SYSTEM_ID'],
    report_id: base.report_id,
    resource_counts: resource_counts
  )
  
  feature_stats
end

Batch Reporting

For large installations, report in batches:
def batch_resource_report(batch_size: 100)
  base_response = telemetry_service.report_base_information(...)
  report_id = base_response.report_id
  
  organizations = list_all_organizations
  
  organizations.each_slice(batch_size).with_index do |batch, index|
    puts "Processing batch #{index + 1}..."
    
    counts = batch.map { |org| collect_org_counts(org) }
    
    telemetry_service.report_resource_counts(
      system_id: ENV['ZITADEL_SYSTEM_ID'],
      report_id: report_id,
      resource_counts: counts
    )
    
    # Small delay between batches
    sleep(1)
  end
  
  puts "Batch reporting complete"
end

Report Linking

Reports are linked by:
  • system_id: Identifies your ZITADEL installation
  • report_id: Links resource counts to base information
# Base report creates report_id
base = telemetry_service.report_base_information(
  system_id: 'sys_123'
)

# Use same report_id for all resource count batches
telemetry_service.report_resource_counts(
  system_id: 'sys_123',
  report_id: base.report_id, # Same ID
  resource_counts: batch_1
)

telemetry_service.report_resource_counts(
  system_id: 'sys_123',
  report_id: base.report_id, # Same ID  
  resource_counts: batch_2
)

Resource Types

Typical resources to count:
  • Users: Total users per organization
  • Organizations: Total organizations
  • Projects: Projects per organization
  • Applications: Applications per project/organization
  • Sessions: Active sessions
  • Actions: Configured actions/targets
  • Authorizations: User grants
  • Identity Providers: Configured IDPs

Privacy Considerations

Telemetry should only include aggregate counts and metadata, not personally identifiable information (PII).
What to include:
  • Resource counts
  • Feature flags
  • Configuration settings
  • System version
  • Creation dates
What NOT to include:
  • User names
  • Email addresses
  • Personal data
  • Sensitive configuration values

Error Handling

def safe_telemetry_report
  begin
    base = telemetry_service.report_base_information(...)
    telemetry_service.report_resource_counts(...)
    puts "Telemetry reported successfully"
  rescue Zitadel::Client::ApiError => e
    # Log error but don't fail main application
    Rails.logger.error "Telemetry reporting failed: #{e.message}"
  rescue => e
    Rails.logger.error "Unexpected telemetry error: #{e.message}"
  end
end

Automated Monitoring

class TelemetryReporter
  def initialize
    @telemetry_service = Zitadel::Client::Api::BetaTelemetryServiceApi.new
  end
  
  def daily_report
    # Collect system information
    base_info = collect_base_information
    
    # Report base information
    base_response = @telemetry_service.report_base_information(base_info)
    
    # Collect and report resource counts
    report_all_resources(base_response.report_id)
    
    # Log metrics
    log_metrics(base_response.report_id)
  end
  
  private
  
  def collect_base_information
    instances = InstanceService.list_instances.result
    
    Zitadel::Client::Models::BetaTelemetryServiceReportBaseInformationRequest.new(
      system_id: ENV['ZITADEL_SYSTEM_ID'],
      version: ZITADEL::VERSION,
      instances: instances.map { |i|
        {
          instance_id: i.id,
          creation_date: i.creation_date,
          domains: i.domains
        }
      }
    )
  end
  
  def report_all_resources(report_id)
    organizations = OrganizationService.list_all
    
    organizations.each_slice(100) do |batch|
      counts = batch.map { |org| collect_org_metrics(org) }
      
      @telemetry_service.report_resource_counts(
        system_id: ENV['ZITADEL_SYSTEM_ID'],
        report_id: report_id,
        resource_counts: counts
      )
    end
  end
  
  def collect_org_metrics(org)
    {
      organization_id: org.id,
      user_count: UserService.count(organization_id: org.id),
      project_count: ProjectService.count(organization_id: org.id),
      application_count: AppService.count(organization_id: org.id),
      session_count: SessionService.count_active(organization_id: org.id),
      action_count: ActionService.count(organization_id: org.id)
    }
  end
  
  def log_metrics(report_id)
    Rails.logger.info "Telemetry report completed: #{report_id}"
  end
end

# Usage
reporter = TelemetryReporter.new
reporter.daily_report

Best Practices

  • Report telemetry on a regular schedule (daily or weekly)
  • Use background jobs to avoid blocking main application
  • Handle failures gracefully
  • Ensure counts are accurate and up-to-date
  • Use database queries or caching for performance
  • Verify counts before reporting
  • Never include PII in reports
  • Only send aggregate statistics
  • Follow data protection regulations
  • Don’t let telemetry failures affect main application
  • Log errors for debugging
  • Implement retry logic for transient failures

Migration Guide

Future versions may have updated telemetry APIs:
  1. Monitor ZITADEL release notes
  2. Update reporting structure as needed
  3. Test telemetry integration
  4. Update monitoring dashboards

See Also

Build docs developers (and LLMs) love