# Mixpanel
[![Module Version](https://img.shields.io/hexpm/v/mixpanel_api_ex.svg)](https://hex.pm/packages/mixpanel_api_ex)
[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/mixpanel_api_ex/)
[![Total Downloads](https://img.shields.io/hexpm/dt/mixpanel_api_ex.svg)](https://hex.pm/packages/mixpanel_api_ex)
[![License](https://img.shields.io/hexpm/l/mixpanel_api_ex.svg)](https://github.com/asakura/mixpanel_api_ex/blob/master/LICENSE)
[![Last Updated](https://img.shields.io/github/last-commit/asakura/mixpanel_api_ex.svg)](https://github.com/asakura/mixpanel_api_ex/commits/master)
[![Coverage Status](https://coveralls.io/repos/github/asakura/mixpanel_api_ex/badge.svg?branch=master)](https://coveralls.io/github/asakura/mixpanel_api_ex?branch=master)
[![CI](https://github.com/asakura/mixpanel_api_ex/actions/workflows/elixir.yml/badge.svg)](https://github.com/asakura/mixpanel_api_ex/actions)
This is a non-official third-party Elixir client for the
[Mixpanel](https://mixpanel.com/).
> Note that this README refers to the `master` branch of `mixpanel_api_ex`, not
the latest released version on Hex. See
[the documentation](https://hexdocs.pm/mixpanel_api_ex) for the documentation
of the version you're using.
For the list of changes, checkout the latest
[release notes](https://github.com/asakura/mixpanel_api_ex/CHANGESET.md).
## Installation
Add `mixpanel_api_ex` to your list of dependencies in `mix.exs`.
```elixir
def deps do
[
{:mixpanel_api_ex, "~> 1.2.0"},
# optional, but recommended adapter
{:hackney, "~> 1.20"}
]
end
```
> The default adapter is Erlang's built-in `httpc`, but it is not recommended to
use it in a production environment as it does not validate SSL certificates
among other issues.
And ensure that `mixpanel_api_ex` is started before your application:
```elixir
def application do
[applications: [:mixpanel_api_ex, :my_app]]
end
```
## Usage Example
Define an interface module with `use Mixpanel`.
```elixir
# lib/my_app/mixpanel.ex
defmodule MyApp.Mixpanel do
use Mixpanel
end
```
Configure the interface module in `config/config.exs`.
```elixir
# config/config.exs
config :mixpanel_api_ex, MyApp.Mixpanel,
project_token: System.get_env("MIXPANEL_PROJECT_TOKEN")
```
And then to track an event:
```elixir
MyApp.Mixpanel.track("Signed up", %{"Referred By" => "friend"}, distinct_id: "13793")
# => :ok
```
## TOC
- [Configuration](#configuration)
- [EU Data Residency](#eu-data-residency)
- [Supported HTTP clients](#supported-http-clients)
- [Running multiple instances](#running-multiple-instances)
- [Running tests](#running-tests)
- [Telemetry](#telemetry)
- [Usage](#usage)
- [Contributing](#contributing)
- [License](#license)
## Configuration
### EU Data Residency
By default `mixpanel_api_ex` sends data to Mixpanels's US Servers. However,
this can be changes via `:base_url` parameter:
```elixir
# config/config.exs
config :mixpanel_api_ex, MyApp.Mixpanel,
base_url: "https://api-eu.mixpanel.com",
project_token: System.get_env("MIXPANEL_PROJECT_TOKEN")
```
`:base_url` is not limited specifically to this URL. So if you need you can
provide an proxy address to route Mixpanel events via.
### Supported HTTP clients
At the moment `httpc` and `hackney` libraries are supported. `:http_adapter`
param can be used to select which HTTP adapter you want to use.
```elixir
# config/config.exs
config :mixpanel_api_ex, MyApp.Mixpanel,
http_adapter: Mixpanel.HTTP.Hackney,
project_token: System.get_env("MIXPANEL_PROJECT_TOKEN")
```
> The default adapter is Erlang's built-in `httpc`, but it is not recommended to
use it in a production environment as it does not validate SSL certificates
among other issues.
### Running multiple instances
You can configure multiple instances to be used by different applications within
your VM. For instance the following example demonstrates having separate client
which is used specifically to sending data to Mixpanel's EU servers.
```elixir
# config/config.exs
config :mixpanel_api_ex, MyApp.Mixpanel,
project_token: System.get_env("MIXPANEL_PROJECT_TOKEN")
config :mixpanel_api_ex, MyApp.Mixpanel.EU,
base_url: "https://api-eu.mixpanel.com",
project_token: System.get_env("MIXPANEL_EU_PROJECT_TOKEN")
```
```elixir
# lib/my_app/mixpanel.ex
defmodule MyApp.Mixpanel do
use Mixpanel
end
```
```elixir
# lib/my_app/mixpanel_eu.ex
defmodule MyApp.MixpanelEU do
use Mixpanel
end
```
### Running tests
Other than not running `mixpanel_api_ex` application in test environment you
have got two other options. Which one you need to use depends on if you want the
client process running or not.
If you prefer the client process to be up and running during the test suite
running you may provide `Mixpanel.HTTP.NoOp` adapter to `:http_adapter` param.
As the adapter's name suggests it won't do any actual work sending data to
Mixpanel, but everything else will be running (including emitting Telemetry's
event).
```elixir
# config/test.exs
config :mixpanel_api_ex, MyApp.Mixpanel,
project_token: "",
http_adapter: Mixpanel.HTTP.NoOp
```
The second options would be simply assign `nil` as configuration value. This way
that client won't be started by the application supervisor.
```elixir
# config/test.exs
config :mixpanel_api_ex, MyApp.Mixpanel, nil
```
## Usage
### Tracking events
Use `Mixpanel.track/3` function to track events:
```elixir
MyApp.Mixpanel.track(
"Signed up",
%{"Referred By" => "friend"},
distinct_id: "13793"
)
# => :ok
```
The time an event occurred and IP address of an user can be provided via opts:
```elixir
MyApp.Mixpanel.track(
"Level Complete",
%{"Level Number" => 9},
distinct_id: "13793",
time: ~U[2013-01-15 00:00:00Z],
ip: "203.0.113.9"
)
# => :ok
```
### Tracking profile updates
Use `Mixpanel.engage/3,4` function to track profile updates:
```elixir
MyApp.Mixpanel.engage(
"13793",
"$set",
%{"Address" => "1313 Mockingbird Lane"}
)
# => :ok
```
The time an event occurred and IP address of an user can be provided via opts:
```elixir
MyApp.Mixpanel.engage(
"13793",
"$set",
%{"Birthday" => "1948-01-01"},
time: ~U[2013-01-15 00:00:00Z],
ip: "123.123.123.123"
)
# => :ok
```
`Mixpanel.engage/2` works with batches:
```elixir
MyApp.Mixpanel.engage(
[
{"13793", "$set", %{"Address" => "1313 Mockingbird Lane"}},
{"13793", "$set", %{"Birthday" => "1948-01-01"}}
],
ip: "123.123.123.123"
)
# => :ok
```
### Merging two profiles
Use `Mixpanel.create_alias/2` create an alias for a district ID, effectively
merging two profiles:
```elixir
MyApp.Mixpanel.create_alias("13793", "13794")
# => :ok
```
## Telemetry
`mixpanel_api_ex` uses Telemetry to provide instrumentation. See the
`Mixpanel.Telemetry` module for details on specific events.
## Contributing
1. Fork it (https://github.com/asakura/mixpanel_api_ex/fork)
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Test your changes by running unit tests and property based tests
(`mix t && mix p`)
4. Check that provided changes does not have type errors (`mix dialyzer`)
5. Additionally you might run Gradient to have extra insight into type problems
(`mix gradient`)
6. Make sure that code is formatted (`mix format`)
7. Run Credo to make sure that there is no code readability/maintainability
issues (`mix credo --strict`)
8. Commit your changes (`git commit -am 'Add some feature'`)
9. Push to the branch (`git push origin my-new-feature`)
10. Create new Pull Request
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
Copyright (c) 2016-2023 [Mikalai Seva](https://github.com/asakura/)