diff --git a/app/assets/javascripts/admin/templates/badges.js.handlebars b/app/assets/javascripts/admin/templates/badges.js.handlebars
index e11ba2ff7..dc34984a1 100644
--- a/app/assets/javascripts/admin/templates/badges.js.handlebars
+++ b/app/assets/javascripts/admin/templates/badges.js.handlebars
@@ -50,6 +50,13 @@
         {{/if}}
       </div>
 
+      <div>
+        <span>
+          {{input type="checkbox" checked=allow_title}}
+          {{i18n admin.badges.allow_title}}
+        </span>
+      </div>
+
       <div class='buttons'>
         <button {{action save}} {{bind-attr disabled=controller.disableSave}} class='btn btn-primary'>{{i18n admin.badges.save}}</button>
         <span class='saving'>{{savingStatus}}</span>
diff --git a/app/assets/javascripts/discourse/controllers/preferences_badge_title_controller.js b/app/assets/javascripts/discourse/controllers/preferences_badge_title_controller.js
index 85352626d..a7af81ee4 100644
--- a/app/assets/javascripts/discourse/controllers/preferences_badge_title_controller.js
+++ b/app/assets/javascripts/discourse/controllers/preferences_badge_title_controller.js
@@ -18,10 +18,7 @@ Discourse.PreferencesBadgeTitleController = Ember.ArrayController.extend({
     }
   }.property('saving'),
 
-  selectableUserBadges: Em.computed.filter('model', function(userBadge) {
-    var badgeType = userBadge.get('badge.badge_type.name');
-    return (badgeType === "Gold" || badgeType === "Silver");
-  }),
+  selectableUserBadges: Em.computed.filterBy('model', 'badge.allow_title', true),
 
   selectedUserBadge: function() {
     var selectedUserBadgeId = parseInt(this.get('selectedUserBadgeId'));
@@ -34,9 +31,7 @@ Discourse.PreferencesBadgeTitleController = Ember.ArrayController.extend({
     return selectedUserBadge;
   }.property('selectedUserBadgeId'),
 
-  titleNotChanged: function() {
-    return this.get('user.title') === this.get('selectedUserBadge.badge.name');
-  }.property('selectedUserBadge', 'user.title'),
+  titleNotChanged: Discourse.computed.propertyEqual('user.title', 'selectedUserBadge.badge.name'),
 
   disableSave: Em.computed.or('saving', 'titleNotChanged'),
 
diff --git a/app/assets/javascripts/discourse/controllers/preferences_controller.js b/app/assets/javascripts/discourse/controllers/preferences_controller.js
index 851dce9ac..d837e6ac1 100644
--- a/app/assets/javascripts/discourse/controllers/preferences_controller.js
+++ b/app/assets/javascripts/discourse/controllers/preferences_controller.js
@@ -33,15 +33,8 @@ Discourse.PreferencesController = Discourse.ObjectController.extend({
   canEditName: Discourse.computed.setting('enable_names'),
 
   canSelectTitle: function() {
-    if (!Discourse.SiteSettings.enable_badges || this.get('model.badge_count') === 0) {
-      return false;
-    }
-
-    // If the first featured badge isn't gold or silver we know the user won't have
-    // _any_ gold or silver badges.
-    var badgeType = this.get('model.featured_user_badges')[0].get('badge.badge_type.name');
-    return (badgeType === "Gold" || badgeType === "Silver");
-  }.property('model.badge_count', 'model.featured_user_badges.@each.badge.badge_type.name'),
+    return Discourse.SiteSettings.enable_badges && this.get('model.badge_count') > 0;
+  }.property('model.badge_count'),
 
   availableLocales: function() {
     return Discourse.SiteSettings.available_locales.split('|').map( function(s) {
diff --git a/app/assets/javascripts/discourse/models/badge.js b/app/assets/javascripts/discourse/models/badge.js
index c802f356d..0d629d175 100644
--- a/app/assets/javascripts/discourse/models/badge.js
+++ b/app/assets/javascripts/discourse/models/badge.js
@@ -101,7 +101,8 @@ Discourse.Badge = Discourse.Model.extend({
       data: {
         name: this.get('name'),
         description: this.get('description'),
-        badge_type_id: this.get('badge_type_id')
+        badge_type_id: this.get('badge_type_id'),
+        allow_title: this.get('allow_title')
       }
     }).then(function(json) {
       self.updateFromJson(json);
diff --git a/app/assets/javascripts/discourse/routes/badges_index_route.js b/app/assets/javascripts/discourse/routes/badges_index_route.js
index 6563af0d7..520677d24 100644
--- a/app/assets/javascripts/discourse/routes/badges_index_route.js
+++ b/app/assets/javascripts/discourse/routes/badges_index_route.js
@@ -8,6 +8,12 @@
 **/
 Discourse.BadgesIndexRoute = Discourse.Route.extend({
   model: function() {
-    return Discourse.Badge.findAll();
+    if (PreloadStore.get('badges')) {
+      return PreloadStore.getAndRemove('badges').then(function(json) {
+        return Discourse.Badge.createFromJson(json);
+      });
+    } else {
+      return Discourse.Badge.findAll();
+    }
   }
 });
diff --git a/app/assets/javascripts/discourse/routes/badges_show_route.js b/app/assets/javascripts/discourse/routes/badges_show_route.js
index 0db79c9df..a4c4cc831 100644
--- a/app/assets/javascripts/discourse/routes/badges_show_route.js
+++ b/app/assets/javascripts/discourse/routes/badges_show_route.js
@@ -12,7 +12,13 @@ Discourse.BadgesShowRoute = Ember.Route.extend({
   },
 
   model: function(params) {
-    return Discourse.Badge.findById(params.id);
+    if (PreloadStore.get('badge')) {
+      return PreloadStore.getAndRemove('badge').then(function(json) {
+        return Discourse.Badge.createFromJson(json);
+      });
+    } else {
+      return Discourse.Badge.findById(params.id);
+    }
   },
 
   setupController: function(controller, model) {
diff --git a/app/assets/javascripts/discourse/routes/preferences_routes.js b/app/assets/javascripts/discourse/routes/preferences_routes.js
index ef59b99d4..eae59f72e 100644
--- a/app/assets/javascripts/discourse/routes/preferences_routes.js
+++ b/app/assets/javascripts/discourse/routes/preferences_routes.js
@@ -194,7 +194,7 @@ Discourse.PreferencesBadgeTitleRoute = Discourse.RestrictedUserRoute.extend({
         controller.set('selectedUserBadgeId', userBadge.get('id'));
       }
     });
-    if (!controller.get('selectedUserBadgeId')) {
+    if (!controller.get('selectedUserBadgeId') && controller.get('selectableUserBadges.length') > 0) {
       controller.set('selectedUserBadgeId', controller.get('selectableUserBadges')[0].get('id'));
     }
   }
diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss
index 6412c8369..0ef6d1dbd 100644
--- a/app/assets/stylesheets/common/admin/admin_base.scss
+++ b/app/assets/stylesheets/common/admin/admin_base.scss
@@ -348,6 +348,10 @@ section.details {
       width: 350px;
     }
 
+    input[type="checkbox"] {
+      width: 20px;
+    }
+
     textarea {
       height: 200px;
     }
diff --git a/app/controllers/admin/badges_controller.rb b/app/controllers/admin/badges_controller.rb
index 92b119af8..08991e8ef 100644
--- a/app/controllers/admin/badges_controller.rb
+++ b/app/controllers/admin/badges_controller.rb
@@ -30,10 +30,11 @@ class Admin::BadgesController < Admin::AdminController
     end
 
     def update_badge_from_params(badge)
-      params.permit(:name, :description, :badge_type_id)
+      params.permit(:name, :description, :badge_type_id, :allow_title)
       badge.name = params[:name]
       badge.description = params[:description]
       badge.badge_type = BadgeType.find(params[:badge_type_id])
+      badge.allow_title = params[:allow_title]
       badge
     end
 end
diff --git a/app/controllers/badges_controller.rb b/app/controllers/badges_controller.rb
index a8908afd4..03f825c5f 100644
--- a/app/controllers/badges_controller.rb
+++ b/app/controllers/badges_controller.rb
@@ -1,12 +1,28 @@
 class BadgesController < ApplicationController
+  skip_before_filter :check_xhr, only: [:index, :show]
+
   def index
     badges = Badge.all.to_a
-    render_serialized(badges, BadgeSerializer, root: "badges")
+    serialized = MultiJson.dump(serialize_data(badges, BadgeSerializer, root: "badges"))
+    respond_to do |format|
+      format.html do
+        store_preloaded "badges", serialized
+        render "default/empty"
+      end
+      format.json { render json: serialized }
+    end
   end
 
   def show
     params.require(:id)
     badge = Badge.find(params[:id])
-    render_serialized(badge, BadgeSerializer, root: "badge")
+    serialized = MultiJson.dump(serialize_data(badge, BadgeSerializer, root: "badge"))
+    respond_to do |format|
+      format.html do
+        store_preloaded "badge", serialized
+        render "default/empty"
+      end
+      format.json { render json: serialized }
+    end
   end
 end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 9ed1fac36..826304797 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -68,7 +68,7 @@ class UsersController < ApplicationController
     guardian.ensure_can_edit!(user)
 
     user_badge = UserBadge.find(params[:user_badge_id])
-    if user_badge.user == user && ["Gold", "Silver"].include?(user_badge.badge.badge_type.name)
+    if user_badge.user == user && user_badge.badge.allow_title?
       user.title = user_badge.badge.name
       user.save!
     end
diff --git a/app/models/badge.rb b/app/models/badge.rb
index aea3895c4..9f8cee902 100644
--- a/app/models/badge.rb
+++ b/app/models/badge.rb
@@ -4,6 +4,7 @@ class Badge < ActiveRecord::Base
 
   validates :name, presence: true, uniqueness: true
   validates :badge_type, presence: true
+  validates :allow_title, inclusion: [true, false]
 end
 
 # == Schema Information
@@ -17,8 +18,10 @@ end
 #  grant_count   :integer          default(0), not null
 #  created_at    :datetime
 #  updated_at    :datetime
+#  allow_title   :boolean          default(FALSE), not null
 #
 # Indexes
 #
-#  index_badges_on_name  (name) UNIQUE
+#  index_badges_on_badge_type_id  (badge_type_id)
+#  index_badges_on_name           (name) UNIQUE
 #
diff --git a/app/serializers/badge_serializer.rb b/app/serializers/badge_serializer.rb
index 34b729598..90be747c4 100644
--- a/app/serializers/badge_serializer.rb
+++ b/app/serializers/badge_serializer.rb
@@ -1,5 +1,5 @@
 class BadgeSerializer < ApplicationSerializer
-  attributes :id, :name, :description, :grant_count
+  attributes :id, :name, :description, :grant_count, :allow_title
 
   has_one :badge_type
 end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 89b96f933..db1573c91 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1749,6 +1749,7 @@ en:
         grant: Grant
         no_user_badges: "%{name} has not been granted any badges."
         no_badges: There are no badges that can be granted.
+        allow_title: Allow badge to be used as a title
 
     lightbox:
       download: "download"
diff --git a/db/migrate/20140425172618_add_titleable_to_badges.rb b/db/migrate/20140425172618_add_titleable_to_badges.rb
new file mode 100644
index 000000000..346f3314f
--- /dev/null
+++ b/db/migrate/20140425172618_add_titleable_to_badges.rb
@@ -0,0 +1,5 @@
+class AddTitleableToBadges < ActiveRecord::Migration
+  def change
+    add_column :badges, :allow_title, :boolean, null: false, default: false
+  end
+end
diff --git a/spec/controllers/admin/badges_controller_spec.rb b/spec/controllers/admin/badges_controller_spec.rb
index 62674af34..b507c6a7a 100644
--- a/spec/controllers/admin/badges_controller_spec.rb
+++ b/spec/controllers/admin/badges_controller_spec.rb
@@ -35,12 +35,12 @@ describe Admin::BadgesController do
 
     context '.update' do
       it 'returns success' do
-        xhr :put, :update, id: badge.id, name: "123456", badge_type_id: badge.badge_type_id
+        xhr :put, :update, id: badge.id, name: "123456", badge_type_id: badge.badge_type_id, allow_title: false
         response.should be_success
       end
 
       it 'updates the badge' do
-        xhr :put, :update, id: badge.id, name: "123456", badge_type_id: badge.badge_type_id
+        xhr :put, :update, id: badge.id, name: "123456", badge_type_id: badge.badge_type_id, allow_title: false
         badge.reload.name.should eq('123456')
       end
     end
diff --git a/spec/controllers/badges_controller_spec.rb b/spec/controllers/badges_controller_spec.rb
index 945d64151..adc3957d0 100644
--- a/spec/controllers/badges_controller_spec.rb
+++ b/spec/controllers/badges_controller_spec.rb
@@ -5,7 +5,7 @@ describe BadgesController do
 
   context 'index' do
     it 'should return a list of all badges' do
-      xhr :get, :index
+      get :index, format: :json
 
       response.status.should == 200
       parsed = JSON.parse(response.body)
@@ -15,7 +15,7 @@ describe BadgesController do
 
   context 'show' do
     it "should return a badge" do
-      xhr :get, :show, id: badge.id
+      get :show, id: badge.id, format: :json
       response.status.should == 200
       parsed = JSON.parse(response.body)
       parsed["badge"].should be_present
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index bd607088a..d2ed036b0 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -979,6 +979,21 @@ describe UsersController do
     end
   end
 
+  describe "badge_title" do
+    let(:user) { Fabricate(:user) }
+    let(:badge) { Fabricate(:badge) }
+    let(:user_badge) { BadgeGranter.grant(badge, user) }
+
+    it "sets the user's title to the badge name if it is titleable" do
+      log_in_user user
+      xhr :put, :badge_title, user_badge_id: user_badge.id, username: user.username
+      user.reload.title.should_not == badge.name
+      badge.update_attributes allow_title: true
+      xhr :put, :badge_title, user_badge_id: user_badge.id, username: user.username
+      user.reload.title.should == badge.name
+    end
+  end
+
   describe "search_users" do
 
     let(:topic) { Fabricate :topic }