diff --git a/.env.example b/.env.example
index 174ba9c70..1d372e3e9 100644
--- a/.env.example
+++ b/.env.example
@@ -80,6 +80,10 @@ OIDC_REDIRECT_URI=
PRODUCT_NAME=
BRAND_NAME=
+# PostHog configuration
+POSTHOG_KEY=
+POSTHOG_HOST=
+
# Disable enforcing SSL connections
# DISABLE_SSL=true
diff --git a/Gemfile b/Gemfile
index 9d4ac1fe9..ede71beb3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -40,6 +40,7 @@ gem "rack-mini-profiler"
gem "sentry-ruby"
gem "sentry-rails"
gem "sentry-sidekiq"
+gem "posthog-ruby"
gem "logtail-rails"
gem "skylight", groups: [ :production ]
diff --git a/Gemfile.lock b/Gemfile.lock
index d345ab640..c7df11978 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -425,6 +425,8 @@ GEM
platform_agent (1.0.1)
activesupport (>= 5.2.0)
useragent (~> 0.16.3)
+ posthog-ruby (3.3.3)
+ concurrent-ruby (~> 1)
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
@@ -736,6 +738,7 @@ DEPENDENCIES
pagy
pg (~> 1.5)
plaid
+ posthog-ruby
propshaft
puma (>= 5.0)
rack-attack (~> 6.6)
diff --git a/app/views/layouts/shared/_head.html.erb b/app/views/layouts/shared/_head.html.erb
index bb797c66a..8dd683d4b 100644
--- a/app/views/layouts/shared/_head.html.erb
+++ b/app/views/layouts/shared/_head.html.erb
@@ -27,5 +27,9 @@
+ <% if Rails.env.production? && (posthog_config = Rails.configuration.x.posthog).try(:api_key).present? %>
+ <%= render "shared/posthog", posthog_api_key: posthog_config.api_key, posthog_host: posthog_config.host %>
+ <% end %>
+
<%= yield :head %>
diff --git a/app/views/shared/_posthog.html.erb b/app/views/shared/_posthog.html.erb
new file mode 100644
index 000000000..0b73624a3
--- /dev/null
+++ b/app/views/shared/_posthog.html.erb
@@ -0,0 +1,9 @@
+
+
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
index b3076b38f..834aa2118 100644
--- a/config/initializers/content_security_policy.rb
+++ b/config/initializers/content_security_policy.rb
@@ -11,6 +11,7 @@
# policy.img_src :self, :https, :data
# policy.object_src :none
# policy.script_src :self, :https
+# policy.script_src :self, :https, 'https://us.i.posthog.com'
# policy.style_src :self, :https
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
diff --git a/config/initializers/posthog.rb b/config/initializers/posthog.rb
new file mode 100644
index 000000000..0d87f53b9
--- /dev/null
+++ b/config/initializers/posthog.rb
@@ -0,0 +1,14 @@
+require "posthog"
+
+Rails.configuration.x.posthog = ActiveSupport::OrderedOptions.new
+Rails.configuration.x.posthog.api_key = ENV["POSTHOG_KEY"].presence
+Rails.configuration.x.posthog.host = ENV.fetch("POSTHOG_HOST", "https://us.i.posthog.com")
+
+if (api_key = Rails.configuration.x.posthog.api_key).present?
+ # Initialize PostHog client
+ $posthog = PostHog::Client.new({
+ api_key: api_key,
+ host: Rails.configuration.x.posthog.host,
+ on_error: Proc.new { |status, msg| puts "PostHog error: #{status} - #{msg}" }
+ })
+end