@@ -22,33 +22,41 @@ mix deps.get
2222
2323## Quick Start
2424
25+ 1 . Configure in ` config/config.exs ` :
26+
2527``` elixir
26- # Start the client (typically in your application supervision tree)
27- {:ok , client} = Klime .Client .start_link (write_key: " your-write-key" )
28+ config :klime ,
29+ write_key: System .get_env (" KLIME_WRITE_KEY" )
30+ ```
31+
32+ 2 . Add to your supervision tree in ` application.ex ` :
33+
34+ ``` elixir
35+ children = [
36+ Klime .Client
37+ ]
38+ ```
39+
40+ 3 . Track events anywhere in your app:
2841
42+ ``` elixir
2943# Identify a user
30- Klime .identify (client, " user_123" , %{
44+ Klime .identify (" user_123" , %{
31453246 name: " Stefan"
3347})
3448
3549# Track an event
36- Klime .track (client, " Button Clicked" , %{
50+ Klime .track (" Button Clicked" , %{
3751 button_name: " Sign up" ,
3852 plan: " pro"
3953}, user_id: " user_123" )
4054
41- # Associate user with a group and set group traits
42- Klime .group (client, " org_456" , %{
55+ # Associate user with a group
56+ Klime .group (" org_456" , %{
4357 name: " Acme Inc" ,
4458 plan: " enterprise"
4559}, user_id: " user_123" )
46-
47- # Or just link the user to a group (if traits are already set)
48- Klime .group (client, " org_456" , %{}, user_id: " user_123" )
49-
50- # Shutdown gracefully
51- Klime .shutdown (client)
5260```
5361
5462## Installation Prompt
@@ -70,29 +78,28 @@ KEY CONCEPTS:
7078- group() links a user to a company AND sets company traits (only for Companies & Teams mode)
7179- Order doesn't matter - events before identify/group still get attributed correctly
7280
81+ SETUP:
82+ 1. Add to mix.exs: {:klime, "~> 1.0"}
83+ 2. Run: mix deps.get
84+ 3. Configure in config/config.exs:
85+ config :klime, write_key: System.get_env("KLIME_WRITE_KEY")
86+ 4. Add Klime.Client to your application.ex supervision tree:
87+ children = [Klime.Client]
88+
7389BEST PRACTICES:
74- - Add Klime.Client to your application supervision tree
7590- Store write key in KLIME_WRITE_KEY environment variable
7691- Client automatically handles graceful shutdown when supervisor stops
7792
78- Add to mix.exs: {:klime, "~> 1.0"}
79- Then run: mix deps.get
80-
81- # In application.ex
82- children = [
83- {Klime.Client, write_key: System.get_env("KLIME_WRITE_KEY"), name: Klime}
84- ]
85-
8693# Identify users at signup/login:
87- Klime.identify(Klime, "usr_abc123", %{email: "[email protected] ", name: "Jane Smith"}) 94+ Klime.identify("usr_abc123", %{email: "[email protected] ", name: "Jane Smith"}) 8895
8996# Track key activities:
90- Klime.track(Klime, "Report Generated", %{report_type: "revenue"}, user_id: "usr_abc123")
91- Klime.track(Klime, "Feature Used", %{feature: "export", format: "csv"}, user_id: "usr_abc123")
92- Klime.track(Klime, "Teammate Invited", %{role: "member"}, user_id: "usr_abc123")
97+ Klime.track("Report Generated", %{report_type: "revenue"}, user_id: "usr_abc123")
98+ Klime.track("Feature Used", %{feature: "export", format: "csv"}, user_id: "usr_abc123")
99+ Klime.track("Teammate Invited", %{role: "member"}, user_id: "usr_abc123")
93100
94101# If Companies & Teams mode: link user to their company and set company traits
95- Klime.group(Klime, "org_456", %{name: "Acme Inc", plan: "enterprise"}, user_id: "usr_abc123")
102+ Klime.group("org_456", %{name: "Acme Inc", plan: "enterprise"}, user_id: "usr_abc123")
96103
97104INTEGRATION WORKFLOW:
98105
@@ -132,47 +139,53 @@ Report what you added:
132139
133140## API Reference
134141
142+ ### Configuration
143+
144+ Configure Klime in ` config/config.exs ` :
145+
146+ ``` elixir
147+ config :klime ,
148+ write_key: System .get_env (" KLIME_WRITE_KEY" ), # Required
149+ endpoint: " https://i.klime.com" , # Optional (default)
150+ flush_interval: 2000 , # Optional: ms between flushes (default: 2000)
151+ max_batch_size: 20 , # Optional: max events per batch (default: 20, max: 100)
152+ max_queue_size: 1000 , # Optional: max queued events (default: 1000)
153+ retry_max_attempts: 5 , # Optional: max retry attempts (default: 5)
154+ retry_initial_delay: 1000 , # Optional: initial retry delay in ms (default: 1000)
155+ flush_on_shutdown: true , # Optional: auto-flush on shutdown (default: true)
156+ on_error: & MyApp .Analytics .handle_error / 2 , # Optional: callback for batch failures
157+ on_success: & MyApp .Analytics .handle_success / 1 # Optional: callback for successful sends
158+ ```
159+
135160### Starting the Client
136161
162+ Add to your supervision tree in ` application.ex ` :
163+
137164``` elixir
138- # Option 1: Start directly
139- {:ok , client} = Klime .Client .start_link (
140- write_key: " your-write-key" , # Required
141- endpoint: " https://i.klime.com" , # Optional (default)
142- flush_interval: 2000 , # Optional: ms between flushes (default: 2000)
143- max_batch_size: 20 , # Optional: max events per batch (default: 20, max: 100)
144- max_queue_size: 1000 , # Optional: max queued events (default: 1000)
145- retry_max_attempts: 5 , # Optional: max retry attempts (default: 5)
146- retry_initial_delay: 1000 , # Optional: initial retry delay in ms (default: 1000)
147- flush_on_shutdown: true , # Optional: auto-flush on shutdown (default: true)
148- on_error: & handle_error/ 2 , # Optional: callback for batch failures
149- on_success: & handle_success/ 1 , # Optional: callback for successful sends
150- name: MyApp .Klime # Optional: registered name
151- )
152-
153- # Option 2: Add to supervision tree (recommended for Phoenix apps)
154165children = [
155- { Klime .Client , write_key: System . get_env ( " KLIME_WRITE_KEY " ), name: Klime }
166+ Klime .Client
156167]
157168```
158169
170+ The client reads configuration from the application environment and registers itself as ` :klime ` by default.
171+
159172### Methods
160173
161- #### ` track(client, event_name, properties \\ %{}, opts \\ []) `
174+ #### ` track(event_name, properties \\ %{}, opts \\ []) `
162175
163176Track an event. Events can be attributed in two ways:
164177- ** User events** : Provide ` user_id: ` to track user activity (most common)
165178- ** Group events** : Provide ` group_id: ` without ` user_id: ` for organization-level events
166179
167180``` elixir
168181# User event (most common)
169- Klime .track (client, " Button Clicked" , %{
182+ Klime .track (" Button Clicked" , %{
170183 button_name: " Sign up" ,
171184 plan: " pro"
172185}, user_id: " user_123" )
173186
174187# Group event (for webhooks, cron jobs, system events)
175- Klime .track (client, " Events Received" , %{
188+ Klime .track (" Events Received" , %{
176189 count: 100 ,
177190 source: " webhook"
178191}, group_id: " org_456" )
@@ -186,13 +199,13 @@ For cases where you need guaranteed delivery or want to handle errors explicitly
186199
187200``` elixir
188201# Sync track - blocks until sent, returns {:ok, response} or {:error, error}
189- {:ok , response} = Klime .track! (client, " Button Clicked" , %{button: " signup" }, user_id: " user_123" )
202+ {:ok , response} = Klime .track! (" Button Clicked" , %{button: " signup" }, user_id: " user_123" )
190203
191204# Sync identify
192- {
:ok , response}
= Klime .
identify! (
client, " user_123" , %{
email: " [email protected] " })
205+ {
:ok , response}
= Klime .
identify! (
" user_123" , %{
email: " [email protected] " })
193206
194207# Sync group
195- {:ok , response} = Klime .group! (client, " org_456" , %{name: " Acme Inc" }, user_id: " user_123" )
208+ {:ok , response} = Klime .group! (" org_456" , %{name: " Acme Inc" }, user_id: " user_123" )
196209```
197210
198211These methods:
@@ -203,52 +216,52 @@ These methods:
203216
204217Use sync methods sparingly - they add latency to your code. The async methods are preferred for most use cases.
205218
206- #### ` identify(client, user_id, traits \\ %{}) `
219+ #### ` identify(user_id, traits \\ %{}) `
207220
208221Identify a user with traits.
209222
210223``` elixir
211- Klime .identify (client, " user_123" , %{
224+ Klime .identify (" user_123" , %{
212225213226 name: " Stefan"
214227})
215228```
216229
217- #### ` group(client, group_id, traits \\ %{}, opts \\ []) `
230+ #### ` group(group_id, traits \\ %{}, opts \\ []) `
218231
219232Associate a user with a group and/or set group traits.
220233
221234``` elixir
222235# Associate user with a group and set group traits (most common)
223- Klime .group (client, " org_456" , %{
236+ Klime .group (" org_456" , %{
224237 name: " Acme Inc" ,
225238 plan: " enterprise"
226239}, user_id: " user_123" )
227240
228241# Just link a user to a group (traits already set or not needed)
229- Klime .group (client, " org_456" , %{}, user_id: " user_123" )
242+ Klime .group (" org_456" , %{}, user_id: " user_123" )
230243
231244# Just update group traits (e.g., from a webhook or background job)
232- Klime .group (client, " org_456" , %{
245+ Klime .group (" org_456" , %{
233246 plan: " enterprise" ,
234247 employee_count: 50
235248})
236249```
237250
238- #### ` flush(client ) `
251+ #### ` flush() `
239252
240253Manually flush queued events immediately.
241254
242255``` elixir
243- :ok = Klime .flush (client )
256+ :ok = Klime .flush ()
244257```
245258
246- #### ` shutdown(client ) `
259+ #### ` shutdown() `
247260
248261Gracefully shutdown the client, flushing remaining events.
249262
250263``` elixir
251- :ok = Klime .shutdown (client )
264+ :ok = Klime .shutdown ()
252265```
253266
254267## Features
@@ -257,14 +270,15 @@ Gracefully shutdown the client, flushing remaining events.
257270- ** Automatic Retries** : Failed requests are automatically retried with exponential backoff
258271- ** Async & Sync Methods** : Use async methods for fire-and-forget, or sync (` track! ` , ` identify! ` , ` group! ` ) for guaranteed delivery
259272- ** OTP Supervision** : GenServer-based client integrates naturally with OTP supervision trees
273+ - ** Application Config** : Configure once in ` config.exs ` , no need to pass client around
260274- ** Plug Middleware** : Optional ` Klime.Plug ` for per-request flush in Phoenix/Plug apps
261275- ** Graceful Shutdown** : Automatically flushes events when the supervisor stops (with ` flush_on_shutdown: true ` )
262276- ** Callbacks** : ` on_error ` and ` on_success ` callbacks for monitoring
263277- ** Minimal Dependencies** : Only requires ` jason ` for JSON encoding (` plug ` optional for middleware)
264278
265279## Performance
266280
267- When you call ` track/4 ` , ` identify/3 ` , or ` group/4 ` , the SDK:
281+ When you call ` track/3 ` , ` identify/2 ` , or ` group/3 ` , the SDK:
268282
2692831 . Adds the event to an in-memory queue (microseconds)
2702842 . Returns immediately without waiting for network I/O
@@ -277,13 +291,13 @@ Events are sent to Klime's servers asynchronously. This means:
277291
278292``` elixir
279293# This returns immediately - no HTTP request is made here
280- Klime .track (client, " Button Clicked" , %{button: " signup" }, user_id: " user_123" )
294+ Klime .track (" Button Clicked" , %{button: " signup" }, user_id: " user_123" )
281295
282296# Your code continues without waiting
283297json (conn, %{success: true })
284298```
285299
286- The only blocking operation is ` flush/1 ` , which waits for all queued events to be sent. This is typically only called during graceful shutdown.
300+ The only blocking operation is ` flush/0 ` , which waits for all queued events to be sent. This is typically only called during graceful shutdown.
287301
288302## Configuration
289303
@@ -299,17 +313,16 @@ The only blocking operation is `flush/1`, which waits for all queued events to b
299313### Callbacks
300314
301315``` elixir
302- {Klime .Client ,
316+ # In config/config.exs
317+ config :klime ,
303318 write_key: System .get_env (" KLIME_WRITE_KEY" ),
304- name: Klime ,
305319 on_error: fn error, _events ->
306320 Logger .error (" Klime error: #{ inspect (error)} " )
307321 Sentry .capture_exception (error)
308322 end ,
309323 on_success: fn response ->
310324 Logger .info (" Sent #{ response.accepted } events" )
311325 end
312- }
313326```
314327
315328### Plug Middleware
@@ -318,7 +331,7 @@ For guaranteed per-request delivery, use `Klime.Plug` to flush events after each
318331
319332``` elixir
320333# In your Phoenix endpoint.ex or router.ex
321- plug Klime .Plug , client: Klime
334+ plug Klime .Plug , client: :klime
322335```
323336
324337> ** Note** : This adds latency to every request as it waits for the flush.
@@ -343,6 +356,12 @@ Events exceeding these limits are rejected and logged.
343356
344357## Phoenix Example
345358
359+ ``` elixir
360+ # config/config.exs
361+ config :klime ,
362+ write_key: System .get_env (" KLIME_WRITE_KEY" )
363+ ```
364+
346365``` elixir
347366# lib/my_app/application.ex
348367defmodule MyApp .Application do
@@ -351,7 +370,7 @@ defmodule MyApp.Application do
351370 def start (_type , _args ) do
352371 children = [
353372 MyAppWeb .Endpoint ,
354- { Klime .Client , write_key: System . get_env ( " KLIME_WRITE_KEY " ), name: Klime }
373+ Klime .Client
355374 ]
356375
357376 opts = [strategy: :one_for_one , name: MyApp .Supervisor ]
@@ -368,7 +387,7 @@ defmodule MyAppWeb.ButtonController do
368387 def click (conn, %{" button_name" => button_name}) do
369388 user_id = conn.assigns[:current_user ] && conn.assigns.current_user.id
370389
371- Klime .track (Klime , " Button Clicked" , %{
390+ Klime .track (" Button Clicked" , %{
372391 button_name: button_name
373392 }, user_id: user_id)
374393
@@ -387,15 +406,15 @@ defmodule MyAppWeb.DashboardLive do
387406 def mount (_params , _session , socket) do
388407 user = socket.assigns.current_user
389408
390- Klime .track (Klime , " Dashboard Viewed" , %{}, user_id: user.id)
409+ Klime .track (" Dashboard Viewed" , %{}, user_id: user.id)
391410
392411 {:ok , socket}
393412 end
394413
395414 def handle_event (" export" , %{" format" => format}, socket) do
396415 user = socket.assigns.current_user
397416
398- Klime .track (Klime , " Export Clicked" , %{format: format}, user_id: user.id)
417+ Klime .track (" Export Clicked" , %{format: format}, user_id: user.id)
399418
400419 {:noreply , socket}
401420 end
0 commit comments