diff --git a/ProcessLib/Output/IntegrationPointWriter.cpp b/ProcessLib/Output/IntegrationPointWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fc4249e864e8f75031f6646379af9788757ef442
--- /dev/null
+++ b/ProcessLib/Output/IntegrationPointWriter.cpp
@@ -0,0 +1,91 @@
+/**
+ * \file
+ *
+ * \copyright
+ * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#include <nlohmann/json.hpp>
+
+#include "MeshLib/Mesh.h"
+
+#include "IntegrationPointWriter.h"
+
+using nlohmann::json;
+
+/// Adds the integration point data and creates meta data for it.
+///
+/// Returns meta data for the written integration point data.
+static ProcessLib::IntegrationPointMetaData addIntegrationPointData(
+    MeshLib::Mesh& mesh, ProcessLib::IntegrationPointWriter const& writer)
+{
+    auto const& ip_values = writer.values(/*t, x, dof_table*/);
+    assert(ip_values.size() == mesh.getNumberOfElements());
+
+    // create field data and fill it with nodal values, and an offsets cell
+    // array indicating where the cell's integration point data starts.
+    auto& field_data = *MeshLib::getOrCreateMeshProperty<double>(
+        mesh, writer.name(), MeshLib::MeshItemType::IntegrationPoint,
+        writer.numberOfComponents());
+    field_data.clear();
+
+    for (std::size_t e = 0; e < ip_values.size(); ++e)
+    {
+        auto const& element_ip_values = ip_values[e];
+        std::copy(element_ip_values.begin(), element_ip_values.end(),
+                  std::back_inserter(field_data));
+    }
+
+    return {writer.name(), writer.numberOfComponents(),
+            writer.integrationOrder()};
+}
+
+/// Adds integration point meta data as char mesh property encoded in JSON
+/// format, which is then stored as VTK's field data.
+static void addIntegrationPointMetaData(
+    MeshLib::Mesh& mesh,
+    std::vector<ProcessLib::IntegrationPointMetaData> const& meta_data)
+{
+    json json_meta_data;
+    json_meta_data["integration_point_arrays"] = json::array();
+
+    for (auto const& md : meta_data)
+    {
+        json_meta_data["integration_point_arrays"].push_back(
+            {{"name", md.name},
+             {"number_of_components", md.n_components},
+             {"integration_order", md.integration_order}});
+    }
+
+    // Store the field data.
+    std::string const json_string = json_meta_data.dump();
+    auto& dictionary = *MeshLib::getOrCreateMeshProperty<char>(
+        mesh, "IntegrationPointMetaData",
+        MeshLib::MeshItemType::IntegrationPoint, 1);
+    dictionary.clear();
+    std::copy(json_string.begin(), json_string.end(),
+              std::back_inserter(dictionary));
+}
+
+namespace ProcessLib
+{
+void addIntegrationPointWriter(
+    MeshLib::Mesh& mesh,
+    std::vector<std::unique_ptr<IntegrationPointWriter>> const&
+        integration_point_writer)
+{
+    std::vector<IntegrationPointMetaData> meta_data;
+    for (auto const& ip_writer : integration_point_writer)
+    {
+        meta_data.push_back(addIntegrationPointData(mesh, *ip_writer));
+    }
+    if (!meta_data.empty())
+    {
+        addIntegrationPointMetaData(mesh, meta_data);
+    }
+}
+}  // namespace ProcessLib
diff --git a/ProcessLib/Output/IntegrationPointWriter.h b/ProcessLib/Output/IntegrationPointWriter.h
index b442d107f8df9efda4e2a23a6c7629e1ce1a8ae8..da772e81186b23070cc4f1d606f23e901a345dbc 100644
--- a/ProcessLib/Output/IntegrationPointWriter.h
+++ b/ProcessLib/Output/IntegrationPointWriter.h
@@ -1,4 +1,6 @@
 /**
+ * \file
+ *
  * \copyright
  * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org)
  *            Distributed under a Modified BSD License.
@@ -6,9 +8,16 @@
  *              http://www.opengeosys.org/project/license
  *
  */
+#include <memory>
+#include <vector>
 
 #pragma once
 
+namespace MeshLib
+{
+class Mesh;
+}
+
 namespace ProcessLib
 {
 struct IntegrationPointWriter
@@ -21,4 +30,25 @@ struct IntegrationPointWriter
     virtual std::vector<std::vector<double>> values() const = 0;
 };
 
+/// Add integration point data the the mesh's properties.
+///
+/// Adds all integration point data arrays given by the input vector and the
+/// corresponding meta data as VTK's field data.
+/// Integration point data stored as field data (contrary to point or cell
+/// data), as plain double arrays. The data is supplemented with information in
+/// JSON format, which is stored as array of characters.
+void addIntegrationPointWriter(
+    MeshLib::Mesh& mesh,
+    std::vector<std::unique_ptr<IntegrationPointWriter>> const&
+        integration_point_writer);
+
+/// Description of the stored integration point data providing additional
+/// information for reconstruction and post-processing.
+struct IntegrationPointMetaData
+{
+    std::string const name;
+    int const n_components;
+    int const integration_order;
+};
+
 }  // namespace ProcessLib
diff --git a/ProcessLib/Output/ProcessOutput.cpp b/ProcessLib/Output/ProcessOutput.cpp
index 65d13c59d6e0eb25d4a5ff8e44f5a0f641f30755..df6fac6affc9d39f92c41d4c9dddc333dc1cd535 100644
--- a/ProcessLib/Output/ProcessOutput.cpp
+++ b/ProcessLib/Output/ProcessOutput.cpp
@@ -239,6 +239,8 @@ void processOutputData(
     (void)secondary_variables;
     (void)t;
 #endif  // USE_PETSC
+
+    addIntegrationPointWriter(mesh, integration_point_writer);
 }
 
 void makeOutput(std::string const& file_name, MeshLib::Mesh& mesh,