defmodule Plausible do @moduledoc """ `Plausible` is a library to push analytics event to [Plausible Analytics]("https://plausible.io"). The library provides two working mode to push events. ## Installation 1. Add `:plausible` to your project `mix.exs` dependencies ```elixir def deps() do [ #other dependendencies excluded here {:plausible, "~> 0.1.0"} ] end ``` 2. Initialize `finch` process in your app supervision tree. ```elixir def start(_type, _arg) do children = [{Finch, name: MyApp.Finch}] end ``` ## Usages The library provides two working modes as listed below 1. Use `Plausible.Client` as the wrapper to `Plausible` module so you can pass in less parameters. 2. Or use `Plausible` directly that accepts a finch process name and keyword `opts` parameter directly to send event to Plausible Analytics Host. The document can be found on each `Plausible` and `Plausible.Client` ## Contributions All contributions are welcome. Please visit https://github.com/blisscs/plausible and create issue or pull request there. """ @doc """ Create Plausible Event Currently only returns `:ok` ## Examples iex> create_event(MyApp.Finch, user_agent: user_agent, x_forwarded_for: x_forwarded_for, url: url, domain: domain) :ok """ @spec create_event(String.t(), atom(), Keyword.t() | map) :: :ok | {:error, Exception.t()} | {:error, Mint.Types.status(), binary()} def create_event(endpoint \\ "https://plausible.io", finch_process, opts) do path = "/api/event" user_agent = opts[:user_agent] || raise """ user_agent not defined """ x_forwarded_for = opts[:x_forwarded_for] || raise """ x_forwarded_for not defined """ domain = opts[:domain] || raise """ domain not defined """ url = opts[:url] || raise """ url not defined """ referrer = opts[:referrer] event_name = opts[:event_name] || "pageview" body = %{name: event_name, url: url, referrer: referrer, domain: domain} |> Jason.encode!() # TODO handle custom properties Finch.build( :post, "#{endpoint}#{path}", [ {"User-Agent", user_agent}, {"X-Forwarded-For", x_forwarded_for}, {"Content-Type", "application/json"} ], body ) |> Finch.request(finch_process) |> handle_request() end @spec create_event!(String.t(), atom(), Keyword.t() | map()) :: :ok def create_event!(endpoint \\ "https://plausible.io", finch_process, opts) do create_event(endpoint, finch_process, opts) |> case do :ok -> :ok {:error, code, message} -> raise Plausible.Exception, message: "status_code: #{code}, error: #{message}" {:error, %Mint.TransportError{} = mint_error} -> raise Plausible.Exception, message: to_string(mint_error.reason) end end defp handle_request({:error, _} = error), do: error defp handle_request({:ok, %Finch.Response{status: 202}}), do: :ok defp handle_request({:ok, %Finch.Response{status: status, body: body}}), do: {:error, status, body} end