diff --git a/app/controllers/admin/abuse_metrics_controller.rb b/app/controllers/admin/abuse_metrics_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..fcfc2a52aed409c90b3c761141889ef7b36c08fa
--- /dev/null
+++ b/app/controllers/admin/abuse_metrics_controller.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Admin
+  class AbuseMetricsController < BaseController
+    def index
+      authorize :dashboard, :index?
+    end
+  end
+end
diff --git a/app/lib/admin/metrics/dimension.rb b/app/lib/admin/metrics/dimension.rb
index 81b89d9b324dad334f4186a0b3c92145cdaa931f..96c9851f88d2afc04b3344e61595e900ec60c7d1 100644
--- a/app/lib/admin/metrics/dimension.rb
+++ b/app/lib/admin/metrics/dimension.rb
@@ -11,6 +11,8 @@ class Admin::Metrics::Dimension
     tag_languages: Admin::Metrics::Dimension::TagLanguagesDimension,
     instance_accounts: Admin::Metrics::Dimension::InstanceAccountsDimension,
     instance_languages: Admin::Metrics::Dimension::InstanceLanguagesDimension,
+    ips: Admin::Metrics::Dimension::IPsDimension,
+    email_domains: Admin::Metrics::Dimension::EmailDomainsDimension,
   }.freeze
 
   def self.retrieve(dimension_keys, start_at, end_at, limit, params)
diff --git a/app/lib/admin/metrics/dimension/email_domains_dimension.rb b/app/lib/admin/metrics/dimension/email_domains_dimension.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c8e1b97b7c869336af58c5f3b991b70c6f78fefd
--- /dev/null
+++ b/app/lib/admin/metrics/dimension/email_domains_dimension.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Dimension::EmailDomainsDimension < Admin::Metrics::Dimension::BaseDimension
+  def key
+    'email_domains'
+  end
+
+  protected
+
+  def perform_query
+    sql = <<-SQL.squish
+      SELECT split_part(email, '@', 2) AS domain, count(*) AS value
+      FROM users
+      WHERE created_at BETWEEN $1 AND $2
+      GROUP BY split_part(email, '@', 2)
+      ORDER BY count(*) DESC
+      LIMIT $3
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, @limit]])
+
+    rows.map { |row| { key: row['domain'], human_key: row['domain'], value: row['value'].to_s } }
+  end
+end
diff --git a/app/lib/admin/metrics/dimension/ips_dimension.rb b/app/lib/admin/metrics/dimension/ips_dimension.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b6662673341a7f6925f789118f36b16736422a77
--- /dev/null
+++ b/app/lib/admin/metrics/dimension/ips_dimension.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Dimension::IPsDimension < Admin::Metrics::Dimension::BaseDimension
+  def key
+    'ips'
+  end
+
+  protected
+
+  def perform_query
+    sql = <<-SQL.squish
+      SELECT sign_up_ip, count(*) AS value
+      FROM users
+      WHERE created_at BETWEEN $1 AND $2
+      GROUP BY sign_up_ip
+      ORDER BY count(*) DESC
+      LIMIT $3
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, @limit]])
+
+    rows.map { |row| { key: row['sign_up_ip'], human_key: row['sign_up_ip'], value: row['value'].to_s } }
+  end
+end
diff --git a/app/views/admin/abuse_metrics/index.html.haml b/app/views/admin/abuse_metrics/index.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..cac089f8160d474b0c2e116313790df792fd466c
--- /dev/null
+++ b/app/views/admin/abuse_metrics/index.html.haml
@@ -0,0 +1,16 @@
+- content_for :header_tags do
+  = javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous'
+
+.dashboard
+  .dashboard__item
+    = react_admin_component :dimension, dimension: 'ips', start_at: 1.hour.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by IP last hour'
+  .dashboard__item
+    = react_admin_component :dimension, dimension: 'ips', start_at: 1.day.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by IP last day'
+  .dashboard__item
+    = react_admin_component :dimension, dimension: 'ips', start_at: 7.days.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by IP last week'
+  .dashboard__item
+    = react_admin_component :dimension, dimension: 'email_domains', start_at: 1.hour.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by e-mail domain last hour'
+  .dashboard__item
+    = react_admin_component :dimension, dimension: 'email_domains', start_at: 1.day.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by e-mail domain last day'
+  .dashboard__item
+    = react_admin_component :dimension, dimension: 'email_domains', start_at: 7.days.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by e-mail domain last week'
diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb
index 3e5a556176161ec83607359ea5fedc65fe0d7550..ef7f0743c012798a6c6bf5a5c93685b1930e5e9d 100644
--- a/config/initializers/inflections.rb
+++ b/config/initializers/inflections.rb
@@ -25,6 +25,7 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
   inflect.acronym 'REST'
   inflect.acronym 'URL'
   inflect.acronym 'ASCII'
+  inflect.acronym 'IPs'
 
   inflect.singular 'data', 'data'
 end
diff --git a/config/routes.rb b/config/routes.rb
index 7dc9f391db25169f2c7568c9256e7c41039db281..322b3d282d503b2d2546ee5f26eb49e2de023bdf 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -189,6 +189,7 @@ Rails.application.routes.draw do
 
   namespace :admin do
     get '/dashboard', to: 'dashboard#index'
+    get '/abuse_metrics', to: 'abuse_metrics#index'
 
     resources :domain_allows, only: [:new, :create, :show, :destroy]
     resources :domain_blocks, only: [:new, :create, :destroy, :update, :edit]