diff --git a/app/assets/javascripts/admin/controllers/admin-reports.js.es6 b/app/assets/javascripts/admin/controllers/admin-reports.js.es6
index bdafff9f0..9ceb1b0b0 100644
--- a/app/assets/javascripts/admin/controllers/admin-reports.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-reports.js.es6
@@ -1,6 +1,7 @@
 import { exportEntity } from 'discourse/lib/export-csv';
 import { outputExportResult } from 'discourse/lib/export-result';
 import Report from 'admin/models/report';
+import computed from 'ember-addons/ember-computed-decorators';
 
 export default Ember.Controller.extend({
   viewMode: 'table',
@@ -9,22 +10,32 @@ export default Ember.Controller.extend({
   startDate: null,
   endDate: null,
   categoryId: null,
+  groupId: null,
   refreshing: false,
 
-  categoryOptions: function() {
-    var arr = [{name: I18n.t('category.all'), value: 'all'}];
-    return arr.concat( Discourse.Site.currentProp('sortedCategories').map(function(i) { return {name: i.get('name'), value: i.get('id') }; }) );
-  }.property(),
+  @computed()
+  categoryOptions() {
+    const arr = [{name: I18n.t('category.all'), value: 'all'}];
+    return arr.concat(Discourse.Site.currentProp('sortedCategories').map((i) => {return {name: i.get('name'), value: i.get('id')};}));
+  },
+
+  @computed()
+  groupOptions() {
+    const arr = [{name: I18n.t('admin.dashboard.reports.groups'), value: 'all'}];
+    return arr.concat(this.site.groups.map((i) => {return {name: i['name'], value: i['id']};}));
+  },
+
+  @computed('model.type')
+  showGroupOptions(modelType) {
+    return modelType === "visits" || modelType === "signups" || modelType === "profile_views";
+  },
 
   actions: {
     refreshReport() {
       var q;
       this.set("refreshing", true);
-      if (this.get('categoryId') === "all") {
-        q = Report.find(this.get("model.type"), this.get("startDate"), this.get("endDate"));
-      } else {
-        q = Report.find(this.get("model.type"), this.get("startDate"), this.get("endDate"), this.get("categoryId"));
-      }
+
+      q = Report.find(this.get("model.type"), this.get("startDate"), this.get("endDate"), this.get("categoryId"), this.get("groupId"));
       q.then(m => this.set("model", m)).finally(() => this.set("refreshing", false));
     },
 
@@ -41,7 +52,8 @@ export default Ember.Controller.extend({
         name: this.get("model.type"),
         start_date: this.get('startDate'),
         end_date: this.get('endDate'),
-        category_id: this.get('categoryId') === 'all' ? undefined : this.get('categoryId')
+        category_id: this.get('categoryId') === 'all' ? undefined : this.get('categoryId'),
+        group_id: this.get('groupId') === 'all' ? undefined : this.get('groupId')
       }).then(outputExportResult);
     }
   }
diff --git a/app/assets/javascripts/admin/models/report.js.es6 b/app/assets/javascripts/admin/models/report.js.es6
index b4b5912ee..1891984b4 100644
--- a/app/assets/javascripts/admin/models/report.js.es6
+++ b/app/assets/javascripts/admin/models/report.js.es6
@@ -131,12 +131,13 @@ const Report = Discourse.Model.extend({
 
 Report.reopenClass({
 
-  find(type, startDate, endDate, categoryId) {
+  find(type, startDate, endDate, categoryId, groupId) {
     return Discourse.ajax("/admin/reports/" + type, {
       data: {
         start_date: startDate,
         end_date: endDate,
-        category_id: categoryId
+        category_id: categoryId,
+        group_id: groupId
       }
     }).then(json => {
       // Add a percent field to each tuple
diff --git a/app/assets/javascripts/admin/templates/reports.hbs b/app/assets/javascripts/admin/templates/reports.hbs
index 718a61a2c..1f5360a8a 100644
--- a/app/assets/javascripts/admin/templates/reports.hbs
+++ b/app/assets/javascripts/admin/templates/reports.hbs
@@ -1,9 +1,12 @@
 <h3>{{model.title}}</h3>
 
-<div>
+<div class="admin-reports-filter">
   {{i18n 'admin.dashboard.reports.start_date'}} {{input type="date" value=startDate}}
   {{i18n 'admin.dashboard.reports.end_date'}} {{input type="date" value=endDate}}
   {{combo-box valueAttribute="value" content=categoryOptions value=categoryId}}
+  {{#if showGroupOptions}}
+    {{combo-box valueAttribute="value" content=groupOptions value=groupId}}
+  {{/if}}
   {{d-button action="refreshReport" class="btn-primary" label="admin.dashboard.reports.refresh_report" icon="refresh"}}
   {{d-button action="exportCsv" label="admin.export_csv.button_text" icon="download"}}
 </div>
diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss
index 85e9ac30e..5a5df3b73 100644
--- a/app/assets/stylesheets/common/admin/admin_base.scss
+++ b/app/assets/stylesheets/common/admin/admin_base.scss
@@ -38,6 +38,12 @@ $mobile-breakpoint: 700px;
   .filters input { margin-bottom: 0; }
 }
 
+.admin-contents .admin-reports-filter {
+  input[type="date"] {
+    width: 140px;
+  }
+}
+
 td.flaggers td {
   border-bottom: none;
   border-top: none;
diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb
index e4416b130..f24ee3f52 100644
--- a/app/controllers/admin/reports_controller.rb
+++ b/app/controllers/admin/reports_controller.rb
@@ -13,11 +13,19 @@ class Admin::ReportsController < Admin::AdminController
     end_date = start_date + 1.month
     end_date = Time.parse(params[:end_date]) if params[:end_date].present?
 
-    category_id = if params.has_key?(:category_id)
-      params[:category_id].blank? ? SiteSetting.uncategorized_category_id : params[:category_id].to_i
+    if params.has_key?(:category_id) && params[:category_id].to_i > 0
+      category_id = params[:category_id].to_i
+    else
+      category_id = nil
     end
 
-    report = Report.find(report_type, start_date: start_date, end_date: end_date, category_id: category_id)
+    if params.has_key?(:group_id) && params[:group_id].to_i > 0
+      group_id = params[:group_id].to_i
+    else
+      group_id = nil
+    end
+
+    report = Report.find(report_type, start_date: start_date, end_date: end_date, category_id: category_id, group_id: group_id)
 
     raise Discourse::NotFound if report.blank?
 
diff --git a/app/controllers/export_csv_controller.rb b/app/controllers/export_csv_controller.rb
index f632b93be..cbb6399ac 100644
--- a/app/controllers/export_csv_controller.rb
+++ b/app/controllers/export_csv_controller.rb
@@ -30,7 +30,7 @@ class ExportCsvController < ApplicationController
       @_export_params ||= begin
         params.require(:entity)
         params.require(:entity_type)
-        params.permit(:entity, :entity_type, args: [:name, :start_date, :end_date, :category_id])
+        params.permit(:entity, :entity_type, args: [:name, :start_date, :end_date, :category_id, :group_id])
       end
     end
 end
diff --git a/app/jobs/regular/export_csv_file.rb b/app/jobs/regular/export_csv_file.rb
index d32f1a3f7..bacf8c6f7 100644
--- a/app/jobs/regular/export_csv_file.rb
+++ b/app/jobs/regular/export_csv_file.rb
@@ -151,6 +151,7 @@ module Jobs
       @extra[:start_date] = @extra[:start_date].to_date if @extra[:start_date].is_a?(String)
       @extra[:end_date]   = @extra[:end_date].to_date   if @extra[:end_date].is_a?(String)
       @extra[:category_id] = @extra[:category_id].to_i  if @extra[:category_id]
+      @extra[:group_id] = @extra[:group_id].to_i        if @extra[:group_id]
       r = Report.find(@extra[:name], @extra)
       r.data.map do |row|
         [row[:x].to_s(:db), row[:y].to_s(:db)]
diff --git a/app/models/report.rb b/app/models/report.rb
index 1da795401..e5135dcac 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -2,7 +2,7 @@ require_dependency 'topic_subtype'
 
 class Report
 
-  attr_accessor :type, :data, :total, :prev30Days, :start_date, :end_date, :category_id
+  attr_accessor :type, :data, :total, :prev30Days, :start_date, :end_date, :category_id, :group_id
 
   def self.default_days
     30
@@ -25,6 +25,7 @@ class Report
      start_date: start_date,
      end_date: end_date,
      category_id: category_id,
+     group_id: group_id,
      prev30Days: self.prev30Days
     }
   end
@@ -41,6 +42,7 @@ class Report
     report.start_date = opts[:start_date] if opts[:start_date]
     report.end_date = opts[:end_date] if opts[:end_date]
     report.category_id = opts[:category_id] if opts[:category_id]
+    report.group_id = opts[:group_id] if opts[:group_id]
     report_method = :"report_#{type}"
 
     if respond_to?(report_method)
@@ -85,7 +87,8 @@ class Report
 
 
   def self.report_visits(report)
-    basic_report_about report, UserVisit, :by_day, report.start_date, report.end_date
+    basic_report_about report, UserVisit, :by_day, report.start_date, report.end_date, report.group_id
+
     add_counts report, UserVisit, 'visited_at'
   end
 
@@ -96,13 +99,19 @@ class Report
   end
 
   def self.report_signups(report)
-    report_about report, User.real, :count_by_signup_date
+    if report.group_id
+      basic_report_about report, User.real, :count_by_signup_date, report.start_date, report.end_date, report.group_id
+      add_counts report, User.real, 'users.created_at'
+    else
+      report_about report, User.real, :count_by_signup_date
+    end
   end
 
   def self.report_profile_views(report)
     start_date = report.start_date.to_date
     end_date = report.end_date.to_date
-    basic_report_about report, UserProfileView, :profile_views_by_day, start_date, end_date
+    basic_report_about report, UserProfileView, :profile_views_by_day, start_date, end_date, report.group_id
+
     report.total = UserProfile.sum(:views)
     report.prev30Days = UserProfileView.where("viewed_at >= ? AND viewed_at < ?", start_date - 30.days, start_date + 1).count
   end
diff --git a/app/models/user.rb b/app/models/user.rb
index 6a74a641e..639846ee2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -110,7 +110,7 @@ class User < ActiveRecord::Base
   attr_accessor :import_mode
 
   # excluding fake users like the system user or anonymous users
-  scope :real, -> { where('id > 0').where('NOT EXISTS(
+  scope :real, -> { where('users.id > 0').where('NOT EXISTS(
                      SELECT 1
                      FROM user_custom_fields ucf
                      WHERE
@@ -637,8 +637,14 @@ class User < ActiveRecord::Base
         .limit(limit)
   end
 
-  def self.count_by_signup_date(start_date, end_date)
-    where('created_at >= ? and created_at <= ?', start_date, end_date).group('date(created_at)').order('date(created_at)').count
+  def self.count_by_signup_date(start_date, end_date, group_id=nil)
+    result = where('users.created_at >= ? and users.created_at <= ?', start_date, end_date)
+
+    if group_id
+      result = result.joins("INNER JOIN group_users ON group_users.user_id = users.id")
+      result = result.where("group_users.group_id = ?", group_id)
+    end
+    result.group('date(users.created_at)').order('date(users.created_at)').count
   end
 
 
diff --git a/app/models/user_profile_view.rb b/app/models/user_profile_view.rb
index 0a62a426d..2fd3cd1c2 100644
--- a/app/models/user_profile_view.rb
+++ b/app/models/user_profile_view.rb
@@ -40,8 +40,13 @@ class UserProfileView < ActiveRecord::Base
     end
   end
 
-  def self.profile_views_by_day(start_date, end_date)
+  def self.profile_views_by_day(start_date, end_date, group_id=nil)
     profile_views = self.where("viewed_at >= ? AND viewed_at < ?", start_date, end_date + 1.day)
+    if group_id
+      profile_views = profile_views.joins("INNER JOIN users ON users.id = user_profile_views.user_id")
+      profile_views = profile_views.joins("INNER JOIN group_users ON group_users.user_id = users.id")
+      profile_views = profile_views.where("group_users.group_id = ?", group_id)
+    end
     profile_views.group("date(viewed_at)").order("date(viewed_at)").count
   end
 end
diff --git a/app/models/user_visit.rb b/app/models/user_visit.rb
index 551361586..5ebe05916 100644
--- a/app/models/user_visit.rb
+++ b/app/models/user_visit.rb
@@ -1,16 +1,23 @@
 class UserVisit < ActiveRecord::Base
 
-  def self.counts_by_day_query(start_date, end_date)
-    where('visited_at >= ? and visited_at <= ?', start_date.to_date, end_date.to_date).group(:visited_at).order(:visited_at)
+  def self.counts_by_day_query(start_date, end_date, group_id=nil)
+    result = where('visited_at >= ? and visited_at <= ?', start_date.to_date, end_date.to_date)
+
+    if group_id
+      result = result.joins("INNER JOIN users ON users.id = user_visits.user_id")
+      result = result.joins("INNER JOIN group_users ON group_users.user_id = users.id")
+      result = result.where("group_users.group_id = ?", group_id)
+    end
+    result.group(:visited_at).order(:visited_at)
   end
 
   # A count of visits in a date range by day
-  def self.by_day(start_date, end_date)
-    counts_by_day_query(start_date, end_date).count
+  def self.by_day(start_date, end_date, group_id=nil)
+    counts_by_day_query(start_date, end_date, group_id).count
   end
 
-  def self.mobile_by_day(start_date, end_date)
-    counts_by_day_query(start_date, end_date).where(mobile: true).count
+  def self.mobile_by_day(start_date, end_date, group_id=nil)
+    counts_by_day_query(start_date, end_date, group_id).where(mobile: true).count
   end
 
   def self.ensure_consistency!
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 4feee950c..d98e1eb65 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1929,6 +1929,7 @@ en:
           refresh_report: "Refresh Report"
           start_date: "Start Date"
           end_date: "End Date"
+          groups: "All groups"
 
       commits:
         latest_changes: "Latest changes: please update often!"