Ruby

Ruby SDK

Official Klime SDK for Ruby. Track events, identify users, and associate them with groups.

Installation

Add this line to your application's Gemfile:

gem 'klime'

And then execute:

bundle install

Or install it yourself as:

gem install klime

Quick Start

require 'klime'

client = Klime::Client.new(
  write_key: 'your-write-key'
)

# Identify a user
client.identify('user_123', {
  email: 'user@example.com',
  name: 'Stefan'
})

# Track an event
client.track('Button Clicked', {
  button_name: 'Sign up',
  plan: 'pro'
}, user_id: 'user_123')

# Associate user with a group and set group traits
client.group('org_456', {
  name: 'Acme Inc',
  plan: 'enterprise'
}, user_id: 'user_123')

# Or just link the user to a group (if traits are already set)
client.group('org_456', user_id: 'user_123')

# Shutdown gracefully
client.shutdown

Installation Prompt

Copy and paste this prompt into Cursor, Copilot, or your favorite AI editor to integrate Klime:

Integrate Klime for customer analytics. Klime tracks user activity to identify which customers are healthy vs at risk of churning.

ANALYTICS MODES (determine which applies):
- Companies & Teams: Your customers are companies with multiple team members (SaaS, enterprise tools)
  → Use identify() + group() + track()
- Individual Customers: Your customers are individuals with private accounts (consumer apps, creator tools)
  → Use identify() + track() only (no group() needed)

KEY CONCEPTS:
- Every track() call requires either user_id OR group_id (no anonymous events)
- Use group_id alone for org-level events (webhooks, cron jobs, system metrics)
- group() links a user to a company AND sets company traits (only for Companies & Teams mode)
- Order doesn't matter - events before identify/group still get attributed correctly

BEST PRACTICES:
- Initialize client ONCE at app startup (initializer or singleton)
- Store write key in KLIME_WRITE_KEY environment variable
- Call shutdown on process exit to flush remaining events (auto-registered via at_exit)

Add to Gemfile: gem 'klime'
Then run: bundle install

Or install directly: gem install klime

require 'klime'

client = Klime::Client.new(write_key: ENV['KLIME_WRITE_KEY'])

# Identify users at signup/login:
client.identify('usr_abc123', { email: 'jane@acme.com', name: 'Jane Smith' })

# Track key activities:
client.track('Report Generated', { report_type: 'revenue' }, user_id: 'usr_abc123')
client.track('Feature Used', { feature: 'export', format: 'csv' }, user_id: 'usr_abc123')
client.track('Teammate Invited', { role: 'member' }, user_id: 'usr_abc123')

# If Companies & Teams mode: link user to their company and set company traits
client.group('org_456', { name: 'Acme Inc', plan: 'enterprise' }, user_id: 'usr_abc123')

INTEGRATION WORKFLOW:

Phase 1: Discover
Explore the codebase to understand:
1. What framework is used? (Rails, Sinatra, Hanami, Rack, etc.)
2. Where is user identity available? (e.g., current_user.id, @current_user.id, session[:user_id], warden.user)
3. Is this Companies & Teams or Individual Customers?
   - Look for: organization, workspace, tenant, team, account models → Companies & Teams (use group())
   - No company/org concept, just individual users → Individual Customers (skip group())
4. Where do core user actions happen? (controllers, service objects, jobs, callbacks)
5. Is there existing analytics? (search: segment, posthog, mixpanel, amplitude, track)
Match your integration style to the framework's conventions.

Phase 2: Instrument
Add these calls using idiomatic patterns for the framework:
- Initialize client once (Rails: config/initializers/klime.rb, Sinatra: before app.run, Rack: middleware)
- identify() in auth/login success handler
- group() when user-org association is established (Companies & Teams mode only)
- track() for key user actions (see below)

WHAT TO TRACK:
Active engagement (primary): feature usage, resource creation, collaboration, completing flows
Session signals (secondary): login/session start, dashboard access - distinguishes "low usage" from "churned"
Do NOT track: every request, health checks, before_action filters, background jobs

Phase 3: Verify
Confirm: client initialized, shutdown handled, identify/group/track calls added

Phase 4: Summarize
Report what you added:
- Files modified and what was added to each
- Events being tracked (list event names and what triggers them)
- How user_id is obtained (and group_id if Companies & Teams mode)
- Any assumptions made or questions

API Reference

Constructor

Klime::Client.new(
  write_key:,              # Required: Your Klime write key
  endpoint: nil,           # Optional: API endpoint (default: https://i.klime.com)
  flush_interval: nil,     # Optional: Milliseconds between flushes (default: 2000)
  max_batch_size: nil,     # Optional: Max events per batch (default: 20, max: 100)
  max_queue_size: nil,     # Optional: Max queued events (default: 1000)
  retry_max_attempts: nil, # Optional: Max retry attempts (default: 5)
  retry_initial_delay: nil, # Optional: Initial retry delay in ms (default: 1000)
  flush_on_shutdown: nil,  # Optional: Auto-flush on exit (default: true)
  on_error: nil,           # Optional: Callback for batch failures
  on_success: nil          # Optional: Callback for successful sends
)

Methods

track(event_name, properties = nil, user_id: nil, group_id: nil)

Track an event. Events can be attributed in two ways:

  • User events: Provide user_id to track user activity (most common)
  • Group events: Provide group_id without user_id for organization-level events
# User event (most common)
client.track('Button Clicked', {
  button_name: 'Sign up',
  plan: 'pro'
}, user_id: 'user_123')

# Group event (for webhooks, cron jobs, system events)
client.track('Events Received', {
  count: 100,
  source: 'webhook'
}, group_id: 'org_456')

Note: The group_id parameter can also be combined with user_id for multi-tenant scenarios where you need to specify which organization context a user event occurred in.

identify(user_id, traits = nil)

Identify a user with traits.

client.identify('user_123', {
  email: 'user@example.com',
  name: 'Stefan'
})

group(group_id, traits = nil, user_id: nil)

Associate a user with a group and/or set group traits.

# Associate user with a group and set group traits (most common)
client.group('org_456', {
  name: 'Acme Inc',
  plan: 'enterprise'
}, user_id: 'user_123')

# Just link a user to a group (traits already set or not needed)
client.group('org_456', user_id: 'user_123')

# Just update group traits (e.g., from a webhook or background job)
client.group('org_456', {
  plan: 'enterprise',
  employee_count: 50
})

flush

Manually flush queued events immediately.

client.flush

shutdown

Gracefully shutdown the client, flushing remaining events.

client.shutdown

Features

  • Automatic Batching: Events are automatically batched and sent every 2 seconds or when the batch size reaches 20 events
  • Automatic Retries: Failed requests are automatically retried with exponential backoff
  • Thread-Safe: Safe to use from multiple threads
  • Fork-Safe: Automatically detects Puma/Unicorn forks and restarts the worker thread
  • Process Exit Handling: Automatically flushes events on process exit (via at_exit)
  • Zero Dependencies: Uses only Ruby standard library

Performance

When you call track(), identify(), or group(), the SDK:

  1. Adds the event to an in-memory queue (microseconds)
  2. Returns immediately without waiting for network I/O

Events are sent to Klime's servers in a background thread. This means:

  • No network blocking: HTTP requests happen asynchronously in a background thread
  • No latency impact: Tracking calls add < 1ms to your request handling time
  • Automatic batching: Events are queued and sent in batches (default: every 2 seconds or 20 events)
# This returns immediately - no HTTP request is made here
client.track('Button Clicked', { button: 'signup' }, user_id: 'user_123')

# Your code continues without waiting
render json: { success: true }

The only blocking operation is flush(), which waits for all queued events to be sent. This is typically only called during graceful shutdown.

Configuration

Default Values

  • flush_interval: 2000ms
  • max_batch_size: 20 events
  • max_queue_size: 1000 events
  • retry_max_attempts: 5 attempts
  • retry_initial_delay: 1000ms
  • flush_on_shutdown: true

Logging

Klime.configure do |config|
  config.logger = Rails.logger
end

Callbacks

Klime.configure do |config|
  config.on_error = Proc.new { |error, batch|
    Sentry.capture_exception(error)
  }

  config.on_success = Proc.new { |response|
    Rails.logger.info "Sent #{response.accepted} events"
  }
end

Error Handling

The SDK automatically handles:

  • Transient errors (429, 503, network failures): Retries with exponential backoff
  • Permanent errors (400, 401): Logs error and drops event
  • Rate limiting: Respects Retry-After header

For synchronous operations, use bang methods (track!, identify!, group!) which raise Klime::SendError on failure.