PostHog Elixir Client
View SourceA powerful Elixir client for PostHog, providing seamless integration with PostHog's analytics and feature flag APIs.
Features
- 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
Installation
Add posthog
to your list of dependencies in mix.exs
:
def deps do
[
{:posthog, "~> 1.0"}
]
end
Configuration
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)
]
HTTP Client Configuration
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
Disabling PostHog capture
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
Usage
Capturing Events
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"}]
)
Batch Processing
Send multiple events in a single request:
events = [
{"page_view", "user_123", %{}},
{"button_click", "user_123", %{button_id: "signup"}}
]
Posthog.batch(events)
Feature Flags
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: "user@example.com"}
)
Stop sending $feature_flag_called
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)
Local Development
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
Troubleshooting
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
).
Examples
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.
Development Tools
This project uses several development tools to maintain code quality and security:
Credo
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
Contributing
When contributing to this project, please ensure your code passes all the development tool checks:
- Run Credo to ensure code style consistency
- Run Mix Unused to identify any unused code
- Run the test suite with
mix test
License
This project is licensed under the MIT License - see the LICENSE file for details.