A powerful Elixir client for PostHog, providing seamless integration with PostHog's analytics and feature flag APIs.
- Event Capture: Track user actions and custom events
- Feature Flags: Manage feature flags and multivariate tests
- Batch Processing: Send multiple events efficiently
- Custom Properties: Support for user, group, and person properties
- Flexible Configuration: Customizable JSON library and API version
- Environment Control: Disable tracking in development/test environments
- Configurable HTTP Client: Customizable timeouts, retries, and HTTP client implementation
Add posthog
to your list of dependencies in mix.exs
:
def deps do
[
{:posthog, "~> 1.0"}
]
end
You'll also need to include this library under your application tree. You can do so by including :posthog
under your :extra_applications
key inside mix.exs
# mix.exs
def application do
[
extra_applications: [
# ... your existing applications
:posthog
]
]
or if you already have a YourApp.Application
application, you can also add Posthog.Application
under your supervision tree:
# lib/my_app/application.ex
defmodule MyApp.Application do
use Application
def start(_type, _args) do
children = [
# Your other children...
{Posthog.Application, []}
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
This library includes a Posthog.Application
because we bundle Cachex
to allow you to track inside PostHog your FF usage.
This cache is located under :posthog_feature_flag_cache
. If you want more control over the application, you can init it yourself in your own application.ex
# lib/my_app/application.ex
defmodule MyApp.Application do
use Application
def start(_type, _args) do
children = [
# Your other application children...
{Posthog.Application, []}
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
Add your PostHog configuration to your application's config:
# config/config.exs
config :posthog,
api_url: "https://us.posthog.com", # Or `https://eu.posthog.com` or your self-hosted PostHog instance URL
api_key: "phc_your_project_api_key"
# Optional configurations
config :posthog,
json_library: Jason, # Default JSON parser (optional)
capture_enabled: true, # Whether to enable PostHog tracking (optional, defaults to true)
http_client: Posthog.HTTPClient.Hackney, # Default HTTP client (optional)
http_client_opts: [ # HTTP client options (optional)
timeout: 5_000, # Request timeout in milliseconds (default: 5_000)
retries: 3, # Number of retries on failure (default: 3)
retry_delay: 1_000 # Delay between retries in milliseconds (default: 1_000)
]
The library uses Hackney as the default HTTP client, but you can configure its behavior or even swap it for a different implementation by simply implementing the Posthog.HTTPClient
behavior:
# config/config.exs
config :posthog,
# Use a different HTTP client implementation
http_client: MyCustomHTTPClient,
# Configure HTTP client options
http_client_opts: [
timeout: 10_000, # 10 seconds timeout
retries: 5, # 5 retries
retry_delay: 2_000 # 2 seconds between retries
]
For testing, you might want to use a mock HTTP client:
# test/support/mocks.ex
defmodule Posthog.HTTPClient.Test do
@behaviour Posthog.HTTPClient
def post(url, body, headers, _opts) do
# Return mock responses for testing
{:ok, %{status: 200, headers: [], body: %{}}}
end
end
# config/test.exs
config :posthog,
http_client: Posthog.HTTPClient.Test
You can disable PostHog tracking by setting enabled_capture: false
in your configuration. This is particularly useful in development or test environments where you don't want to send actual events to PostHog.
When enabled_capture
is set to false
:
- All
Posthog.capture/3
andPosthog.batch/2
calls will succeed silently - PostHog will still communicate with the server for Feature Flags
This is useful for:
- Development and test environments where you don't want to pollute your PostHog instance
- Situations where you need to temporarily disable tracking
Example configuration for development:
# config/dev.exs
config :posthog,
enabled_capture: false # Disable tracking in development
Example configuration for test:
# config/test.exs
config :posthog,
enabled_capture: false # Disable tracking in test environment
Simple event capture:
# Basic event with `event` and `distinct_id`, both required
Posthog.capture("page_view", "user_123")
# Event with properties
Posthog.capture("purchase", "user_123", %{
product_id: "prod_123",
price: 99.99,
currency: "USD"
})
# Event with custom timestamp
Posthog.capture("signup_completed", "user_123", %{}, timestamp: DateTime.utc_now())
# Event with custom UUID
uuid = "..."
Posthog.capture("signup_completed", "user_123", %{}, uuid: uuid)
# Event with custom headers
Posthog.capture(
"login",
"user_123",
%{},
headers: [{"x-forwarded-for", "127.0.0.1"}]
)
Send multiple events in a single request:
events = [
{"page_view", "user_123", %{}},
{"button_click", "user_123", %{button_id: "signup"}}
]
Posthog.batch(events)
Get all feature flags for a user:
{:ok, flags} = Posthog.feature_flags("user_123")
# Response format:
# %{
# "featureFlags" => %{"flag-1" => true, "flag-2" => "variant-b"},
# "featureFlagPayloads" => %{
# "flag-1" => true,
# "flag-2" => %{"color" => "blue", "size" => "large"}
# }
# }
Check specific feature flag:
# Boolean feature flag
{:ok, flag} = Posthog.feature_flag("new-dashboard", "user_123")
# Returns: %Posthog.FeatureFlag{name: "new-dashboard", payload: true, enabled: true}
# Multivariate feature flag
{:ok, flag} = Posthog.feature_flag("pricing-test", "user_123")
# Returns: %Posthog.FeatureFlag{
# name: "pricing-test",
# payload: %{"price" => 99, "period" => "monthly"},
# enabled: "variant-a"
# }
# Quick boolean check
if Posthog.feature_flag_enabled?("new-dashboard", "user_123") do
# Show new dashboard
end
Feature flags with group properties:
Posthog.feature_flags("user_123",
groups: %{company: "company_123"},
group_properties: %{company: %{industry: "tech"}},
person_properties: %{email: "[email protected]"}
)
We automatically send $feature_flag_called
events so that you can properly keep track of which feature flags you're accessing via Posthog.feature_flag()
calls. If you wanna save some events, you can disable this by adding send_feature_flag_event: false
to the call:
# Boolean feature flag
{:ok, flag} = Posthog.feature_flag("new-dashboard", "user_123", send_feature_flag_event: false)
Run bin/setup
to install development dependencies or run the following commands manually:
We recommend using asdf
to manage Elixir and Erlang versions:
# Install required versions
asdf install
# Install dependencies
mix deps.get
mix compile
Run tests:
bin/test
(This runs mix test
).
Format code:
bin/fmt
If you encounter WX library issues during Erlang installation:
# Disable WX during installation
export KERL_CONFIGURE_OPTIONS="--without-wx"
To persist this setting, add it to your shell configuration file (~/.bashrc
, ~/.zshrc
, or ~/.profile
).
There's an example console project in examples/feature_flag_demo
that shows how to use the client. Follow the instructions in the README to run it.
This project uses several development tools to maintain code quality and security:
Credo is a static code analysis tool that helps enforce coding standards and catch potential issues. Run it with:
mix credo --strict
For more detailed output:
mix credo --strict --verbose
Mix Audit helps identify security vulnerabilities in dependencies. Run it with:
mix deps.audit
When contributing to this project, please ensure your code passes all the development tool checks:
- Run Credo to ensure code style consistency
- Run Mix Audit to check for security vulnerabilities
- Run Mix Unused to identify any unused code
- Run the test suite with
mix test
This project is licensed under the MIT License - see the LICENSE file for details.