Skip to content

Commit c206d94

Browse files
Merge pull request #23 from PostHog/uuid-property
2 parents 7bc72ef + 0148b5e commit c206d94

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)