diff --git a/core/client/controllers/settings/tags.js b/core/client/controllers/settings/tags.js
index 92041fd6a2..5b83e9bfd3 100644
--- a/core/client/controllers/settings/tags.js
+++ b/core/client/controllers/settings/tags.js
@@ -4,13 +4,14 @@ import boundOneWay from 'ghost/utils/bound-one-way';
 var TagsController = Ember.ArrayController.extend(PaginationMixin, {
     tags: Ember.computed.alias('model'),
 
+    needs: 'application',
+
     activeTag: null,
     activeTagNameScratch: boundOneWay('activeTag.name'),
     activeTagSlugScratch: boundOneWay('activeTag.slug'),
     activeTagDescriptionScratch: boundOneWay('activeTag.description'),
-
-    // Tag properties that should not be set to the empty string
-    requiredTagProperties: ['name', 'slug'],
+    activeTagMetaTitleScratch: boundOneWay('activeTag.meta_title'),
+    activeTagMetaDescriptionScratch: boundOneWay('activeTag.meta_description'),
 
     init: function (options) {
         options = options || {};
@@ -18,18 +19,30 @@ var TagsController = Ember.ArrayController.extend(PaginationMixin, {
         this._super(options);
     },
 
+    isViewingSubview: Ember.computed('controllers.application.showSettingsMenu', function (key, value) {
+        // Not viewing a subview if we can't even see the PSM
+        if (!this.get('controllers.application.showSettingsMenu')) {
+            return false;
+        }
+        if (arguments.length > 1) {
+            return value;
+        }
+
+        return false;
+    }),
+
+    showErrors: function (errors) {
+        errors = Ember.isArray(errors) ? errors : [errors];
+        this.notifications.showErrors(errors);
+    },
+
     saveActiveTagProperty: function (propKey, newValue) {
         var activeTag = this.get('activeTag'),
             currentValue = activeTag.get(propKey),
-            requiredTagProps = this.get('requiredTagProperties'),
-            self = this,
-            tagName;
+            self = this;
 
         newValue = newValue.trim();
-        // Quit if value is empty for a required property
-        if (!newValue && requiredTagProps.contains(propKey)) {
-            return;
-        }
+
         // Quit if there was no change
         if (newValue === currentValue) {
             return;
@@ -37,19 +50,59 @@ var TagsController = Ember.ArrayController.extend(PaginationMixin, {
 
         activeTag.set(propKey, newValue);
 
-        tagName = activeTag.get('name');
-        // don't save a new tag until it has a name
-        if (!tagName) {
-            return;
-        }
+        this.notifications.closePassive();
 
-        activeTag.save().then(function () {
-            self.notifications.showSuccess('Saved ' + tagName);
-        }).catch(function (error) {
-            self.notifications.showAPIError(error);
+        activeTag.save().catch(function (errors) {
+            self.showErrors(errors);
         });
     },
 
+    seoTitle: Ember.computed('scratch', 'activeTagNameScratch', 'activeTagMetaTitleScratch', function () {
+        var metaTitle = this.get('activeTagMetaTitleScratch') || '';
+
+        metaTitle = metaTitle.length > 0 ? metaTitle : this.get('activeTagNameScratch');
+
+        if (metaTitle && metaTitle.length > 70) {
+            metaTitle = metaTitle.substring(0, 70).trim();
+            metaTitle = Ember.Handlebars.Utils.escapeExpression(metaTitle);
+            metaTitle = new Ember.Handlebars.SafeString(metaTitle + '…');
+        }
+
+        return metaTitle;
+    }),
+
+    seoURL: Ember.computed('activeTagSlugScratch', function () {
+        var blogUrl = this.get('config').blogUrl,
+            seoSlug = this.get('activeTagSlugScratch') ? this.get('activeTagSlugScratch') : '',
+            seoURL = blogUrl + '/tag/' + seoSlug;
+
+        // only append a slash to the URL if the slug exists
+        if (seoSlug) {
+            seoURL += '/';
+        }
+
+        if (seoURL.length > 70) {
+            seoURL = seoURL.substring(0, 70).trim();
+            seoURL = new Ember.Handlebars.SafeString(seoURL + '…');
+        }
+
+        return seoURL;
+    }),
+
+    seoDescription: Ember.computed('scratch', 'activeTagDescriptionScratch', 'activeTagMetaDescriptionScratch', function () {
+        var metaDescription = this.get('activeTagMetaDescriptionScratch') || '';
+
+        metaDescription = metaDescription.length > 0 ? metaDescription : this.get('activeTagDescriptionScratch');
+
+        if (metaDescription && metaDescription.length > 156) {
+            metaDescription = metaDescription.substring(0, 156).trim();
+            metaDescription = Ember.Handlebars.Utils.escapeExpression(metaDescription);
+            metaDescription = new Ember.Handlebars.SafeString(metaDescription + '…');
+        }
+
+        return metaDescription;
+    }),
+
     actions: {
         newTag: function () {
             this.set('activeTag', this.store.createRecord('tag'));
@@ -84,6 +137,22 @@ var TagsController = Ember.ArrayController.extend(PaginationMixin, {
 
         saveActiveTagDescription: function (description) {
             this.saveActiveTagProperty('description', description);
+        },
+
+        saveActiveTagMetaTitle: function (metaTitle) {
+            this.saveActiveTagProperty('meta_title', metaTitle);
+        },
+
+        saveActiveTagMetaDescription: function (metaDescription) {
+            this.saveActiveTagProperty('meta_description', metaDescription);
+        },
+
+        showSubview: function () {
+            this.set('isViewingSubview', true);
+        },
+
+        closeSubview: function () {
+            this.set('isViewingSubview', false);
         }
     }
 });
diff --git a/core/client/mixins/validation-engine.js b/core/client/mixins/validation-engine.js
index 34b951855c..089f1ac06f 100644
--- a/core/client/mixins/validation-engine.js
+++ b/core/client/mixins/validation-engine.js
@@ -9,6 +9,7 @@ import ForgotValidator from 'ghost/validators/forgotten';
 import SettingValidator from 'ghost/validators/setting';
 import ResetValidator from 'ghost/validators/reset';
 import UserValidator from 'ghost/validators/user';
+import TagSettingsValidator from 'ghost/validators/tag-settings';
 
 // our extensions to the validator library
 ValidatorExtensions.init();
@@ -71,7 +72,8 @@ var ValidationEngine = Ember.Mixin.create({
         forgotten: ForgotValidator,
         setting: SettingValidator,
         reset: ResetValidator,
-        user: UserValidator
+        user: UserValidator,
+        tag: TagSettingsValidator
     },
 
     /**
diff --git a/core/client/models/tag.js b/core/client/models/tag.js
index 2ee7407b5c..bc16f8291d 100644
--- a/core/client/models/tag.js
+++ b/core/client/models/tag.js
@@ -1,6 +1,9 @@
+import ValidationEngine from 'ghost/mixins/validation-engine';
 import NProgressSaveMixin from 'ghost/mixins/nprogress-save';
 
-var Tag = DS.Model.extend(NProgressSaveMixin, {
+var Tag = DS.Model.extend(NProgressSaveMixin, ValidationEngine, {
+    validationType: 'tag',
+
     uuid: DS.attr('string'),
     name: DS.attr('string'),
     slug: DS.attr('string'),
diff --git a/core/client/templates/settings/tags/settings-menu.hbs b/core/client/templates/settings/tags/settings-menu.hbs
index 4c530b3110..0ae8c811bd 100644
--- a/core/client/templates/settings/tags/settings-menu.hbs
+++ b/core/client/templates/settings/tags/settings-menu.hbs
@@ -1,6 +1,6 @@
 <div class="content-cover" {{action "closeSettingsMenu"}}></div>
-<div class="settings-menu-container">
-    <div class="settings-menu settings-menu-pane settings-menu-pane-in">
+{{#gh-tabs-manager selected="showSubview" class="settings-menu-container"}}
+    <div {{bind-attr class="isViewingSubview:settings-menu-pane-out-left:settings-menu-pane-in :settings-menu :settings-menu-pane"}}>
         <div class="settings-menu-header">
             <h4>Tag Settings</h4>
             <button class="close icon-x settings-menu-header-action" {{action "closeSettingsMenu"}}>
@@ -11,12 +11,12 @@
             <form>
                 <div class="form-group">
                     <label>Tag Name</label>
-                    {{gh-input type="text" placeholder=activeTag.name value=activeTagNameScratch focus-out="saveActiveTagName"}}
+                    {{gh-input type="text" value=activeTagNameScratch focus-out="saveActiveTagName"}}
                 </div>
 
                 <div class="form-group">
                     <label>Slug</label>{{!--@TODO show full url preview, not just slug--}}
-                    {{gh-input type="text" placeholder=activeTag.slug value=activeTagSlugScratch focus-out="saveActiveTagSlug"}}
+                    {{gh-input type="text" value=activeTagSlugScratch focus-out="saveActiveTagSlug"}}
                 </div>
 
                 <div class="form-group">
@@ -24,10 +24,52 @@
                     {{gh-textarea value=activeTagDescriptionScratch focus-out="saveActiveTagDescription"}}
                 </div>
 
+                <ul class="nav-list nav-list-block">
+                    {{#gh-tab tagName="li" classNames="nav-list-item"}}
+                        <button type="button">
+                            <b>Meta Data</b>
+                            <span>Extra content for SEO and social media.</span>
+                        </button>
+                    {{/gh-tab}}
+                </ul>
+
                 {{#unless activeTag.isNew}}
-                    <button class="btn btn-red icon-trash" {{action "deleteTag" activeTag}}>Delete Tag</button>
+                    <button type="button" class="btn btn-red icon-trash" {{action "deleteTag" activeTag}}>Delete Tag</button>
                 {{/unless}}
             </form>
         </div>
-    </div>
-</div>
+    </div>{{! .settings-menu-pane }}
+
+    <div {{bind-attr class="isViewingSubview:settings-menu-pane-in:settings-menu-pane-out-right :settings-menu :settings-menu-pane"}}>
+        {{#gh-tab-pane}}
+            <div class="settings-menu-header subview">
+                <button {{action "closeSubview"}} class="back icon-chevron-left settings-menu-header-action"><span class="hidden">Back</span></button>
+                <h4>Meta Data</h4>
+            </div>
+
+            <div class="settings-menu-content">
+                <form>
+                <div class="form-group">
+                    <label for="meta-title">Meta Title</label>
+                    {{gh-input type="text" value=activeTagMetaTitleScratch focus-out="saveActiveTagMetaTitle"}}
+                    <p>Recommended: <b>70</b> characters. You’ve used {{gh-count-down-characters activeTagMetaTitleScratch 70}}</p>
+                </div>
+
+                <div class="form-group">
+                    <label for="meta-description">Meta Description</label>
+                    {{gh-textarea value=activeTagMetaDescriptionScratch focus-out="saveActiveTagMetaDescription"}}
+                    <p>Recommended: <b>156</b> characters. You’ve used {{gh-count-down-characters activeTagMetaDescriptionScratch 156}}</p>
+                </div>
+
+                <div class="form-group">
+                    <label>Search Engine Result Preview</label>
+                    <div class="seo-preview">
+                        <div class="seo-preview-title">{{seoTitle}}</div>
+                        <div class="seo-preview-link">{{seoURL}}</div>
+                        <div class="seo-preview-description">{{seoDescription}}</div>
+                    </div>
+                </form>
+            </div>{{! .settings-menu-content }}
+        {{/gh-tab-pane}}
+    </div>{{! .settings-menu-pane }}
+{{/gh-tabs-manager}}
\ No newline at end of file
diff --git a/core/client/validators/tag-settings.js b/core/client/validators/tag-settings.js
new file mode 100644
index 0000000000..883b40bdfe
--- /dev/null
+++ b/core/client/validators/tag-settings.js
@@ -0,0 +1,28 @@
+var TagSettingsValidator = Ember.Object.create({
+    check: function (model) {
+        var validationErrors = [],
+            data = model.getProperties('name', 'meta_title', 'meta_description');
+
+        if (validator.empty(data.name)) {
+            validationErrors.push({
+                message: 'You must specify a name for the tag.'
+            });
+        }
+
+        if (!validator.isLength(data.meta_title, 0, 150)) {
+            validationErrors.push({
+                message: 'Meta Title cannot be longer than 150 characters.'
+            });
+        }
+
+        if (!validator.isLength(data.meta_description, 0, 200)) {
+            validationErrors.push({
+                message: 'Meta Description cannot be longer than 200 characters.'
+            });
+        }
+
+        return validationErrors;
+    }
+});
+
+export default TagSettingsValidator;