diff --git a/lib/rack/tracker.rb b/lib/rack/tracker.rb
index 4e10d87..277ee74 100644
--- a/lib/rack/tracker.rb
+++ b/lib/rack/tracker.rb
@@ -13,6 +13,7 @@
require "rack/tracker/handler_delegator"
require "rack/tracker/controller"
require "rack/tracker/google_analytics/google_analytics"
+require "rack/tracker/google_analytics4/google_analytics4"
require "rack/tracker/google_global/google_global"
require "rack/tracker/google_tag_manager/google_tag_manager"
require "rack/tracker/google_adwords_conversion/google_adwords_conversion"
diff --git a/lib/rack/tracker/google_analytics4/google_analytics4.rb b/lib/rack/tracker/google_analytics4/google_analytics4.rb
new file mode 100644
index 0000000..7265ecf
--- /dev/null
+++ b/lib/rack/tracker/google_analytics4/google_analytics4.rb
@@ -0,0 +1,41 @@
+class Rack::Tracker::GoogleAnalytics4 < Rack::Tracker::Handler
+
+ self.allowed_tracker_options = [:cookie_domain, :user_id]
+
+ def initialize(env, options = {})
+ super(env, options)
+ end
+
+ class Send < OpenStruct
+ def initialize(attrs = {})
+ attrs.reverse_merge!(type: 'event')
+ super
+ end
+
+ def write
+ ['send', event].to_json.gsub(/\[|\]/, '')
+ end
+
+ def event
+ { hitType: self.type }.merge(attributes.stringify_values).compact
+ end
+
+ def attributes
+ Hash[to_h.slice(:category, :action, :label, :value).map { |k,v| [self.type.to_s + k.to_s.capitalize, v] }]
+ end
+ end
+
+ def tracker
+ options[:tracker].respond_to?(:call) ? options[:tracker].call(env) : options[:tracker]
+ end
+
+ private
+
+ def tracker_option_key(key)
+ key.to_s.camelize(:lower).to_sym
+ end
+
+ def tracker_option_value(value)
+ value.to_s
+ end
+end
diff --git a/lib/rack/tracker/google_analytics4/template/google_analytics4.erb b/lib/rack/tracker/google_analytics4/template/google_analytics4.erb
new file mode 100644
index 0000000..e8b2b18
--- /dev/null
+++ b/lib/rack/tracker/google_analytics4/template/google_analytics4.erb
@@ -0,0 +1,18 @@
+<% if tracker %>
+
+
+
+
+<% end %>