Skip to content

Commit 0148b5e

Browse files
feat: Allow UUID to be set in events
This is a feature that exists in other libraries, so let's port it to Elixir as well We're introducing some breaking changes here, so this will be merged on the v1 branch rather than `main`
1 parent 7bc72ef commit 0148b5e

File tree

9 files changed

+177
-102
lines changed

9 files changed

+177
-102
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- PostHog now requires you to initialize `Posthog.Application` alongside your supervisor tree. This is required because of our `Cachex` system to properly track your FF usage.
1212
- We'll also include local evaluation in the near term, which will also require a GenServer, therefore, requiring us to use a Supervisor.
1313
- Added `enabled_capture` configuration option to disable PostHog tracking in development/test environments
14+
- `Posthog.capture` now requires `distinct_id` as a required second argument
1415

1516
## 0.4.4 - 2025-04-14
1617

MIGRATION.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,35 @@ defmodule MyApp.Application do
4545
end
4646
```
4747

48-
#### Customizing the Cache (Optional)
48+
### `Posthog.capture` new signature
4949

50-
By default, `Posthog.Application` starts a Cachex instance under the name `:posthog_feature_flag_cache`. You can override this by passing options:
50+
The signature to `Posthog.capture` has changed. `distinct_id` is now a required argument.
51+
52+
Here are some examples on how the method is now used:
5153

5254
```elixir
53-
{Posthog.Application, cache_name: :my_custom_cache}
55+
# Basic event with `event` and `distinct_id`, both required
56+
Posthog.capture("page_view", "user_123")
57+
58+
# Event with properties
59+
Posthog.capture("purchase", "user_123", %{
60+
product_id: "prod_123",
61+
price: 99.99,
62+
currency: "USD"
63+
})
64+
65+
# Event with custom timestamp
66+
Posthog.capture("signup_completed", "user_123", %{}, timestamp: DateTime.utc_now())
67+
68+
# Event with custom UUID
69+
uuid = "..."
70+
Posthog.capture("signup_completed", "user_123", %{}, uuid: uuid)
71+
72+
# Event with custom headers
73+
Posthog.capture(
74+
"login",
75+
"user_123",
76+
%{},
77+
headers: [{"x-forwarded-for", "127.0.0.1"}]
78+
)
5479
```

README.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Add your PostHog configuration to your application's config:
7070
```elixir
7171
# config/config.exs
7272
config :posthog,
73-
api_url: "https://app.posthog.com", # Or your self-hosted PostHog instance URL
73+
api_url: "https://us.posthog.com", # Or `https://eu.posthog.com` or your self-hosted PostHog instance URL
7474
api_key: "phc_your_project_api_key"
7575

7676
# Optional configurations
@@ -116,29 +116,29 @@ config :posthog,
116116
Simple event capture:
117117

118118
```elixir
119-
# Basic event
120-
Posthog.capture("page_view", distinct_id: "user_123")
119+
# Basic event with `event` and `distinct_id`, both required
120+
Posthog.capture("page_view", "user_123")
121121

122122
# Event with properties
123-
Posthog.capture("purchase", [
124-
distinct_id: "user_123",
125-
properties: %{
123+
Posthog.capture("purchase", "user_123", %{
126124
product_id: "prod_123",
127125
price: 99.99,
128126
currency: "USD"
129-
}
130-
])
127+
})
131128

132129
# Event with custom timestamp
133-
Posthog.capture("signup_completed",
134-
[distinct_id: "user_123"],
135-
DateTime.utc_now()
136-
)
130+
Posthog.capture("signup_completed", "user_123", %{}, timestamp: DateTime.utc_now())
131+
132+
# Event with custom UUID
133+
uuid = "..."
134+
Posthog.capture("signup_completed", "user_123", %{}, uuid: uuid)
137135

138136
# Event with custom headers
139-
Posthog.capture("login",
140-
[distinct_id: "user_123"],
141-
[headers: [{"x-forwarded-for", "127.0.0.1"}]]
137+
Posthog.capture(
138+
"login",
139+
"user_123",
140+
%{},
141+
headers: [{"x-forwarded-for", "127.0.0.1"}]
142142
)
143143
```
144144

@@ -148,8 +148,8 @@ Send multiple events in a single request:
148148

149149
```elixir
150150
events = [
151-
{"page_view", [distinct_id: "user_123"], nil},
152-
{"button_click", [distinct_id: "user_123", properties: %{button_id: "signup"}], nil}
151+
{"page_view", "user_123", %{}},
152+
{"button_click", "user_123", %{button_id: "signup"}}
153153
]
154154

155155
Posthog.batch(events)

lib/posthog.ex

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,17 @@ defmodule Posthog do
6060
Posthog.capture("page_view", distinct_id: "user_123")
6161
6262
# Event with properties
63-
Posthog.capture("purchase", [
63+
Posthog.capture("purchase", %{
6464
distinct_id: "user_123",
6565
product_id: "prod_123",
6666
price: 99.99
67-
])
67+
})
6868
6969
# Event with custom timestamp
70-
Posthog.capture("signup", [distinct_id: "user_123"], DateTime.utc_now())
70+
Posthog.capture("signup", "user_123", %{}, timestamp: DateTime.utc_now())
7171
7272
# Event with custom headers (e.g., for IP forwarding)
73-
Posthog.capture("login", [distinct_id: "user_123"],
74-
[headers: [{"x-forwarded-for", "127.0.0.1"}]])
73+
Posthog.capture("login", "user_123", %{}, headers: [{"x-forwarded-for", "127.0.0.1"}])
7574
7675
## Feature Flags
7776
@@ -129,24 +128,21 @@ defmodule Posthog do
129128
## Examples
130129
131130
# Basic event
132-
Posthog.capture("page_view", distinct_id: "user_123")
131+
Posthog.capture("page_view", "user_123")
133132
134133
# Event with properties
135-
Posthog.capture("purchase", [
136-
distinct_id: "user_123",
134+
Posthog.capture("purchase", "user_123", %{
137135
product_id: "prod_123",
138136
price: 99.99
139-
])
137+
})
140138
141139
# Event with timestamp
142-
Posthog.capture("signup", [distinct_id: "user_123"], DateTime.utc_now())
140+
Posthog.capture("signup", "user_123", %{}, timestamp: DateTime.utc_now())
143141
144142
# Event with custom headers
145-
Posthog.capture("login", [distinct_id: "user_123"],
146-
[headers: [{"x-forwarded-for", "127.0.0.1"}]])
143+
Posthog.capture("login", "user_123", %{}, headers: [{"x-forwarded-for", "127.0.0.1"}])
147144
"""
148145
@typep result() :: {:ok, term()} | {:error, term()}
149-
@typep timestamp() :: DateTime.t() | NaiveDateTime.t() | String.t() | nil
150146
@typep cache_key() :: {:feature_flag_called, binary(), binary()}
151147
@typep feature_flag_called_event_properties_key() ::
152148
:"$feature_flag"
@@ -162,22 +158,23 @@ defmodule Posthog do
162158

163159
alias Posthog.{Client, FeatureFlag}
164160

165-
@spec capture(atom() | String.t(), keyword() | map(), keyword() | timestamp()) :: result()
166-
defdelegate capture(event, params, opts \\ []), to: Client
161+
@spec capture(Client.event(), Client.distinct_id(), Client.properties(), Client.opts()) ::
162+
result()
163+
defdelegate capture(event, distinct_id, properties, opts \\ []), to: Client
167164

168165
@doc """
169166
Sends multiple events to PostHog in a single request.
170167
171168
## Parameters
172169
173-
* `events` - List of event tuples in the format `{event_name, properties, timestamp}`
170+
* `events` - List of event tuples in the format `{event_name, distinct_id, properties}`
174171
* `opts` - Optional parameters for the batch request
175172
176173
## Examples
177174
178175
events = [
179-
{"page_view", [distinct_id: "user_123"], nil},
180-
{"button_click", [distinct_id: "user_123", button: "signup"], nil}
176+
{"page_view", "user_123", %{}},
177+
{"button_click", "user_123", %{button: "signup"}}
181178
]
182179
183180
Posthog.batch(events)
@@ -244,8 +241,8 @@ defmodule Posthog do
244241
if Keyword.get(opts, :send_feature_flag_event, true),
245242
do:
246243
capture_feature_flag_called_event(
244+
distinct_id,
247245
%{
248-
"distinct_id" => distinct_id,
249246
"$feature_flag" => flag,
250247
"$feature_flag_response" => enabled
251248
},
@@ -259,21 +256,25 @@ defmodule Posthog do
259256
end
260257
end
261258

262-
@spec capture_feature_flag_called_event(feature_flag_called_event_properties(), map()) ::
259+
@spec capture_feature_flag_called_event(
260+
Client.distinct_id(),
261+
feature_flag_called_event_properties(),
262+
map()
263+
) ::
263264
:ok
264-
defp capture_feature_flag_called_event(properties, response) do
265+
defp capture_feature_flag_called_event(distinct_id, properties, response) do
265266
# Create a unique key for this distinct_id and flag combination
266-
cache_key = {:feature_flag_called, properties["distinct_id"], properties["$feature_flag"]}
267+
cache_key = {:feature_flag_called, distinct_id, properties["$feature_flag"]}
267268

268269
# Check if we've seen this combination before using Cachex
269270
case Cachex.exists?(Posthog.Application.cache_name(), cache_key) do
270271
{:ok, false} ->
271-
do_capture_feature_flag_called_event(cache_key, properties, response)
272+
do_capture_feature_flag_called_event(cache_key, distinct_id, properties, response)
272273

273274
# Should be `{:error, :no_cache}` but Dyalixir is wrongly assuming that doesn't exist
274275
{:error, _} ->
275276
# Cache doesn't exist, let's capture the event PLUS notify user they should be initing it
276-
do_capture_feature_flag_called_event(cache_key, properties, response)
277+
do_capture_feature_flag_called_event(cache_key, distinct_id, properties, response)
277278

278279
Logger.error("""
279280
[posthog] Cachex process `#{inspect(Posthog.Application.cache_name())}` is not running.
@@ -299,10 +300,11 @@ defmodule Posthog do
299300

300301
@spec do_capture_feature_flag_called_event(
301302
cache_key(),
303+
Client.distinct_id(),
302304
feature_flag_called_event_properties(),
303305
map()
304306
) :: :ok
305-
defp do_capture_feature_flag_called_event(cache_key, properties, response) do
307+
defp do_capture_feature_flag_called_event(cache_key, distinct_id, properties, response) do
306308
flag = properties["$feature_flag"]
307309

308310
properties =
@@ -324,7 +326,7 @@ defmodule Posthog do
324326
end
325327

326328
# Send the event to our server
327-
Client.capture("$feature_flag_called", properties, [])
329+
Client.capture("$feature_flag_called", distinct_id, properties, [])
328330

329331
# Add new entry to cache using Cachex
330332
Cachex.put(Posthog.Application.cache_name(), cache_key, true)

0 commit comments

Comments
 (0)