diff --git a/Changelog.md b/Changelog.md
index cc34cbc0990f294e321f99730b4fb96529275bc3..5126ac3c547b427b7762d0fa9749b12e0e140323 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -125,6 +125,8 @@ This is disabled by default since it requires the installation of additional pac
 * Truncate too long OpenGraph descriptions [#5387](https://github.com/diaspora/diaspora/pull/5387)
 * Make the source code URL configurable [#5410](https://github.com/diaspora/diaspora/pull/5410)
 * Prefill publisher on the tag pages [#5442](https://github.com/diaspora/diaspora/pull/5442)
+* Allows users to export their data in JSON format from their user settings page [#5354](https://github.com/diaspora/diaspora/pull/5354)
+
 
 # 0.4.1.2
 
diff --git a/Gemfile b/Gemfile
index 838da0b9c68de1cf6572271b141d05730b296a13..8619576608d68ee293398dc5188b1fe82563f03a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -162,6 +162,8 @@ gem 'zip-zip'
 # https://github.com/discourse/discourse/pull/238
 gem 'minitest'
 
+# Serializers
+gem 'active_model_serializers'
 
 # Windows and OSX have an execjs compatible runtime built-in, Linux users should
 # install Node.js or use 'therubyracer'.
diff --git a/Gemfile.lock b/Gemfile.lock
index b732e065505aa20b0d22d180fdef73849a881f5e..ed1961d529d04b7a4224114f2be8aad65311a822 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -22,6 +22,8 @@ GEM
       erubis (~> 2.7.0)
     activemodel (4.1.8)
       activesupport (= 4.1.8)
+    active_model_serializers (0.9.0)
+      activemodel (>= 3.2)
       builder (~> 3.1)
     activerecord (4.1.8)
       activemodel (= 4.1.8)
@@ -606,6 +608,7 @@ DEPENDENCIES
   actionpack-action_caching
   actionpack-page_caching
   activerecord-import (= 0.6.0)
+  active_model_serializers
   acts-as-taggable-on (= 3.4.2)
   acts_as_api (= 0.4.2)
   addressable (= 2.3.6)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 327b6068c0357597e944705f04da493d88765ab4..0e3453a2deff3f3b0fa8aa1ed921d6cad25529db 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -28,6 +28,10 @@ class ApplicationController < ActionController::Base
 
   private
 
+  def default_serializer_options
+    {root: false}
+  end
+
   def ensure_http_referer_is_set
     request.env['HTTP_REFERER'] ||= '/'
   end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index d317734430b305bf1f6d12c4d79b78f8f2e2656a..91ac6b3d3816bae2fd695e2d03865d9b8e2354fd 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -136,8 +136,11 @@ class UsersController < ApplicationController
   end
 
   def export
-    exporter = Diaspora::Exporter.new(Diaspora::Exporters::XML)
-    send_data exporter.execute(current_user), :filename => "#{current_user.username}_diaspora_data.xml", :type => :xml
+    if export = Diaspora::Exporter.new(current_user).execute
+      send_data export, filename: "#{current_user.username}_diaspora_data.json", type: :json
+    else
+      head :not_acceptable
+    end
   end
 
   def export_photos
diff --git a/app/models/user.rb b/app/models/user.rb
index 75cde7fa13328a3d623b1ba157ffea352e2f9ff5..0a7c2d863d72d1d28fa92f66469690e6ac1960c5 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -37,6 +37,8 @@ class User < ActiveRecord::Base
   serialize :hidden_shareables, Hash
 
   has_one :person, :foreign_key => :owner_id
+  has_one :profile, through: :person
+
   delegate :guid, :public_key, :posts, :photos, :owns?, :image_url,
            :diaspora_handle, :name, :public_url, :profile, :url,
            :first_name, :last_name, :gender, :participations, to: :person
diff --git a/app/serializers/export/aspect_serializer.rb b/app/serializers/export/aspect_serializer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5507e516a68904298fc514fed5f656aa95b050ff
--- /dev/null
+++ b/app/serializers/export/aspect_serializer.rb
@@ -0,0 +1,7 @@
+module Export
+  class AspectSerializer < ActiveModel::Serializer
+    attributes :name,
+               :contacts_visible,
+               :chat_enabled
+  end
+end
diff --git a/app/serializers/export/contact_serializer.rb b/app/serializers/export/contact_serializer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..be025304f02362842b2b57c3f1221ed70e3ed78d
--- /dev/null
+++ b/app/serializers/export/contact_serializer.rb
@@ -0,0 +1,12 @@
+module Export
+  class ContactSerializer < ActiveModel::Serializer
+    attributes :sharing,
+               :receiving,
+               :person_guid,
+               :person_name,
+               :person_first_name,
+               :person_diaspora_handle
+
+    has_many :aspects, each_serializer: Export::AspectSerializer
+  end
+end
diff --git a/app/serializers/export/profile_serializer.rb b/app/serializers/export/profile_serializer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b8eb2001f271bb5ca4c7fe619935db2d965bd3b7
--- /dev/null
+++ b/app/serializers/export/profile_serializer.rb
@@ -0,0 +1,14 @@
+module Export
+  class ProfileSerializer < ActiveModel::Serializer
+    attributes :first_name,
+               :last_name,
+               :gender,
+               :bio,
+               :birthday,
+               :location,
+               :image_url,
+               :diaspora_handle,
+               :searchable,
+               :nsfw
+  end
+end
diff --git a/app/serializers/export/user_serializer.rb b/app/serializers/export/user_serializer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..da277dc7fa8d58f225c57e47879b31ad09da5322
--- /dev/null
+++ b/app/serializers/export/user_serializer.rb
@@ -0,0 +1,16 @@
+module Export
+  class UserSerializer < ActiveModel::Serializer
+    attributes :name,
+               :email,
+               :language,
+               :username,
+               :disable_mail,
+               :show_community_spotlight_in_stream,
+               :auto_follow_back,
+               :auto_follow_back_aspect
+    has_one    :profile,  serializer:      Export::ProfileSerializer
+    has_many   :aspects,  each_serializer: Export::AspectSerializer
+    has_many   :contacts, each_serializer: Export::ContactSerializer
+
+  end
+end
\ No newline at end of file
diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml
index 64b7cd5f11769efdcb49a0c83abebab974e7e778..597979811b60027458b0cdb4d6798f4535601ac4 100644
--- a/app/views/users/edit.html.haml
+++ b/app/views/users/edit.html.haml
@@ -180,7 +180,8 @@
         #account_data.span6
           %h3 
             = t('.export_data')
-          = link_to t('.download_xml'), export_user_path, :class => "button"
+          .small-horizontal-spacer          
+          = link_to t('.download_profile'), export_user_path(format: :json), :class => "button"
           .small-horizontal-spacer
           = link_to t('.download_photos'), "#", :class => "button", :id => "photo-export-button", :title => t('.photo_export_unavailable')
 
diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml
index e41deb7eac485e5459f39f4b0e47638d3395bdf0..ccd08851b29858544a2cd8695be7e90f846a7334 100644
--- a/config/locales/diaspora/en.yml
+++ b/config/locales/diaspora/en.yml
@@ -1266,7 +1266,7 @@ en:
       current_password: "Current password"
       current_password_expl: "the one you sign in with..."
       character_minimum_expl: "must be at least six characters"
-      download_xml: "download my xml"
+      download_profile: "download my profile"
       download_photos: "download my photos"
       your_handle: "Your diaspora* ID"
       your_email: "Your email"
diff --git a/config/routes.rb b/config/routes.rb
index 34118045827fbcbbb7ac95efa5bbf073a2a3e422..ce1211a9755f15895f96d1a89360bec6cd9ad769 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -101,7 +101,7 @@ Diaspora::Application.routes.draw do
 
   resource :user, :only => [:edit, :update, :destroy], :shallow => true do
     get :getting_started_completed
-    get :export
+    get :export, format: :json
     get :export_photos
   end
 
diff --git a/lib/account_deleter.rb b/lib/account_deleter.rb
index 6e52aeaf32c98292f2c035ecc5d4183794fdc719..7aaf4093733a10701e58e3c2a7d5df3dee757ccc 100644
--- a/lib/account_deleter.rb
+++ b/lib/account_deleter.rb
@@ -50,7 +50,7 @@ class AccountDeleter
   end
 
   def special_ar_user_associations
-    [:invitations_from_me, :person, :contacts, :auto_follow_back_aspect]
+    [:invitations_from_me, :person, :profile, :contacts, :auto_follow_back_aspect]
   end
 
   def ignored_ar_user_associations
diff --git a/lib/diaspora/exporter.rb b/lib/diaspora/exporter.rb
index 6360d635c1fb2588960af11b0fe38b422b334b84..e6f65ac7a67222f04176aaf733e1182fb1e09eab 100644
--- a/lib/diaspora/exporter.rb
+++ b/lib/diaspora/exporter.rb
@@ -5,87 +5,23 @@
 module Diaspora
 
   class Exporter
-    def initialize(strategy)
-      self.class.send(:include, strategy)
-    end
-  end
-
-  module Exporters
-    module XML
-      def execute(user)
-        builder = Nokogiri::XML::Builder.new do |xml|
-          user_person_id = user.person_id
-          xml.export {
-            xml.user {
-              xml.username user.username
-              xml.serialized_private_key user.serialized_private_key
-
-              xml.parent << user.person.to_xml
-            }
-
-
-
-            xml.aspects {
-              user.aspects.each do |aspect|
-                xml.aspect {
-                  xml.name aspect.name
 
-#                  xml.person_ids {
-                    #aspect.person_ids.each do |id|
-                      #xml.person_id id
-                    #end
-                  #}
+    SERIALIZED_VERSION = '1.0'
 
-                  xml.post_ids {
-                    aspect.posts.where(author_id: user_person_id).each do |post|
-                      xml.post_id post.id
-                    end
-                  }
-                }
-              end
-            }
-
-            xml.contacts {
-              user.contacts.each do |contact|
-              xml.contact {
-                xml.user_id contact.user_id
-                xml.person_id contact.person_id
-                xml.person_guid contact.person_guid
-
-                xml.aspects {
-                  contact.aspects.each do |aspect|
-                    xml.aspect {
-                      xml.name aspect.name
-                    }
-                  end
-                }
-              }
-              end
-            }
-
-            xml.posts {
-              user.visible_shareables(Post).where(author_id: user_person_id).each do |post|
-                #post.comments.each do |comment|
-                #  post_doc << comment.to_xml
-                #end
-
-                xml.parent << post.to_xml
-              end
-            }
+    def initialize(user)
+      @user = user
+    end
 
-            xml.people {
-              user.contacts.each do |contact|
-                person = contact.person
-                xml.parent << person.to_xml
+    def execute
+      @export ||= JSON.generate serialized_user.merge(version: SERIALIZED_VERSION)
+    end
 
-              end
-            }
-          }
-        end
+    private
 
-        builder.to_xml.to_s
-      end
+    def serialized_user
+      @serialized_user ||= Export::UserSerializer.new(@user).as_json
     end
+
   end
 
 end
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 57fdba9d599e4e8c31671c5fd442d85211796f51..a2bc3d511dace90100d8c771fc53be661577da45 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -12,9 +12,9 @@ describe UsersController, :type => :controller do
   end
 
   describe '#export' do
-    it 'returns an xml file'  do
-      get :export
-      expect(response.header["Content-Type"]).to include "application/xml"
+    it 'can return a json file' do
+      get :export, format: :json
+      expect(response.header["Content-Type"]).to include "application/json"
     end
   end
 
diff --git a/spec/lib/account_deleter_spec.rb b/spec/lib/account_deleter_spec.rb
index 7c890757eb5cf2eed6586c7709e7ace90e21b113..46fe41b9b61c8893605c5236e63c9492635e33e1 100644
--- a/spec/lib/account_deleter_spec.rb
+++ b/spec/lib/account_deleter_spec.rb
@@ -43,6 +43,21 @@ describe AccountDeleter do
       end
     end
 
+    context "profile deletion" do
+      before do
+        @profile_deletion = AccountDeleter.new(remote_raphael.diaspora_handle)
+        @profile = remote_raphael.profile
+      end
+
+      it "nulls out fields in the profile" do
+        @profile_deletion.perform!
+        expect(@profile.reload.first_name).to be_blank
+        expect(@profile.last_name).to be_blank
+        expect(@profile.searchable).to be_falsey
+      end
+
+    end
+
     context "person deletion" do
       before do
         @person_deletion = AccountDeleter.new(remote_raphael.diaspora_handle)
diff --git a/spec/lib/diaspora/exporter_spec.rb b/spec/lib/diaspora/exporter_spec.rb
index 63d3c2316a88f25f8fafe5d93a4d375144053152..412be8a8fd2f9478fdaba528c624912166e065dd 100644
--- a/spec/lib/diaspora/exporter_spec.rb
+++ b/spec/lib/diaspora/exporter_spec.rb
@@ -9,8 +9,6 @@ describe Diaspora::Exporter do
 
   before do
     @user1 =  alice
-    @user2 =  FactoryGirl.create(:user)
-    @user3 =  bob
 
     @user1.person.profile.first_name = "<script>"
     @user1.person.profile.gender = "<script>"
@@ -19,108 +17,70 @@ describe Diaspora::Exporter do
     @user1.person.profile.save
 
     @aspect  =  @user1.aspects.first
-    @aspect1 =  @user1.aspects.create(:name => "Work")
-    @aspect2 =  @user2.aspects.create(:name => "Family")
-    @aspect3 =  @user3.aspects.first
+    @aspect1 =  @user1.aspects.create(:name => "Work", :contacts_visible => false)
     @aspect.name = "<script>"
     @aspect.save
-
-    @status_message1 =  @user1.post(:status_message, :text => "One", :public => true, :to => @aspect1.id)
-    @status_message2 =  @user1.post(:status_message, :text => "Two", :public => true, :to => @aspect1.id)
-    @status_message3 =  @user2.post(:status_message, :text => "Three", :public => false, :to => @aspect2.id)
-    @status_message4 =  @user1.post(:status_message, :text => "<script>", :public => true, :to => @aspect2.id)
-  end
-
-  def exported
-    Nokogiri::XML(Diaspora::Exporter.new(Diaspora::Exporters::XML).execute(@user1))
-  end
-
-  it 'escapes xml relevant characters' do
-    expect(exported.to_s).to_not include "<script>"
   end
 
-  context '<user/>' do
-    let(:user_xml) { exported.xpath('//user').to_s }
+  context "json" do
 
-    it 'includes a users private key' do
-      expect(user_xml).to include @user1.serialized_private_key
+    def json
+      @json ||= JSON.parse Diaspora::Exporter.new(@user1).execute
     end
 
-    it 'includes the profile as xml' do
-      expect(user_xml).to include "<profile>"
+    it { matches :version, to: '1.0' }
+    it { matches :user, :name }
+    it { matches :user, :email }
+    it { matches :user, :username }
+    it { matches :user, :language }
+    it { matches :user, :disable_mail }
+    it { matches :user, :show_community_spotlight_in_stream }
+    it { matches :user, :auto_follow_back }
+    it { matches :user, :auto_follow_back_aspect }
+
+    it { matches :user, :profile, :first_name,      root: @user1.person.profile }
+    it { matches :user, :profile, :last_name,       root: @user1.person.profile }
+    it { matches :user, :profile, :gender,          root: @user1.person.profile }
+    it { matches :user, :profile, :bio,             root: @user1.person.profile }
+    it { matches :user, :profile, :location,        root: @user1.person.profile }
+    it { matches :user, :profile, :image_url,       root: @user1.person.profile }
+    it { matches :user, :profile, :diaspora_handle, root: @user1.person.profile }
+    it { matches :user, :profile, :searchable,      root: @user1.person.profile }
+    it { matches :user, :profile, :nsfw,            root: @user1.person.profile }
+
+    it { matches_relation :aspects,  :name,
+                                     :contacts_visible,
+                                     :chat_enabled }
+
+    it { matches_relation :contacts, :sharing,
+                                     :receiving,
+                                     :person_guid,
+                                     :person_name,
+                                     :person_first_name,
+                                     :person_diaspora_handle }
+
+    private
+
+    def matches(*fields, to: nil, root: @user1)
+      expected = to || root.send(fields.last)
+      expect(recurse_field(json, fields)).to eq expected
     end
-  end
 
-  context '<aspects/>' do
-    let(:aspects_xml) { exported.xpath('//aspects').to_s }
-
-    it 'includes the post_ids' do
-      expect(aspects_xml).to include @status_message1.id.to_s
-      expect(aspects_xml).to include @status_message2.id.to_s
+    def matches_relation(relation, *fields, to: nil, root: @user1)
+      array = json['user'][to || relation.to_s]
+      fields.each do |field|
+        expected = root.send(relation).map(&:"#{field}")
+        expect(array.map { |f| f[field.to_s] }).to eq expected
+      end
     end
-  end
 
-  context '<contacts/>' do
-
-    before do
-      @aspect.name = "Safe"
-      @aspect.save
-      @user1.add_contact_to_aspect(@user1.contact_for(@user3.person), @aspect1)
-      @user1.reload
-    end
-
-    let(:contacts_xml) {exported.xpath('//contacts').to_s}
-    it "includes a person's guid" do
-      expect(contacts_xml).to include @user3.person.guid
+    def recurse_field(json, fields)
+      if fields.any?
+        recurse_field json[fields.shift.to_s], fields
+      else
+        json
+      end
     end
 
-    it "includes the names of all aspects they are in" do
-      #contact specific xml needs to be tested
-      expect(@user1.contacts.find_by_person_id(@user3.person.id).aspects.count).to be > 0
-      @user1.contacts.find_by_person_id(@user3.person.id).aspects.each { |aspect|
-        expect(contacts_xml).to include aspect.name
-      }
-    end
-  end
-
-  context '<people/>' do
-    let(:people_xml) {exported.xpath('//people').to_s}
-
-    it 'includes their guid' do
-      expect(people_xml).to include @user3.person.guid
-    end
-
-    it 'includes their profile' do
-      expect(people_xml).to include @user3.person.profile.first_name
-      expect(people_xml).to include @user3.person.profile.last_name
-    end
-
-    it 'includes their public key' do
-      expect(people_xml).to include @user3.person.exported_key
-    end
-
-    it 'includes their diaspora handle' do
-      expect(people_xml).to include @user3.person.diaspora_handle
-    end
-  end
-
-  context '<posts>' do
-    let(:posts_xml) {exported.xpath('//posts').to_s}
-    it "includes many posts' xml" do
-      expect(posts_xml).to include @status_message1.text
-      expect(posts_xml).to include @status_message2.text
-      expect(posts_xml).not_to include @status_message3.text
-    end
-
-    it "includes the post's created at time" do
-      @status_message1.update_attribute(:created_at, Time.now - 1.day) # make sure they have different created at times
-
-      doc = Nokogiri::XML::parse(posts_xml)
-      created_at_text = doc.xpath('//posts/status_message').detect do |status|
-        status.to_s.include?(@status_message1.guid)
-      end.xpath('created_at').text
-
-      expect(Time.zone.parse(created_at_text).to_i).to eq(@status_message1.created_at.to_i)
-    end
   end
 end