diff --git a/Common/gmsh.cpp b/Common/gmsh.cpp
index f8eb0938496c241fdbd48d58da60229aaeded64c..b650792c0694be42f44033305cede6b621098700 100644
--- a/Common/gmsh.cpp
+++ b/Common/gmsh.cpp
@@ -42,6 +42,10 @@
 #include "PViewOptions.h"
 #endif
 
+#if defined(HAVE_PLUGINS)
+#include "PluginManager.h"
+#endif
+
 static int _initialized = 0;
 
 static bool _isInitialized()
@@ -1941,6 +1945,7 @@ void gmshViewDelete(const int tag)
     Msg::Error("Unknown view with tag %d", tag);
     throw 2;
   }
+  delete view;
 #else
   Msg::Error("Views require the post-processing module");
   throw -1;
@@ -1963,6 +1968,19 @@ int gmshViewGetIndex(const int tag)
 #endif
 }
 
+void gmshViewGetTags(std::vector<int> &tags)
+{
+  if(!_isInitialized()){ throw -1; }
+#if defined(HAVE_POST)
+  tags.clear();
+  for(unsigned int i = 0; i < PView::list.size(); i++)
+    tags.push_back(PView::list[i]->getTag());
+#else
+  Msg::Error("Views require the post-processing module");
+  throw -1;
+#endif
+}
+
 void gmshViewAddModelData(const int tag, const std::string &modelName,
                           const std::string &dataType,
                           const std::vector<int> &tags,
@@ -2052,3 +2070,55 @@ void gmshViewExport(const int tag, const std::string &fileName,
   throw -1;
 #endif
 }
+
+// gmshPlugin
+
+void gmshPluginSetNumber(const std::string &name, const std::string &option,
+                         const double value)
+{
+#if defined(HAVE_PLUGINS)
+  try {
+    PluginManager::instance()->setPluginOption(name, option, value);
+  }
+  catch(...) {
+    Msg::Error("Unknown plugin or plugin option");
+    throw 2;
+  }
+#else
+  Msg::Error("Views require the post-processing and plugin modules");
+  throw -1;
+#endif
+}
+
+void gmshPluginSetString(const std::string &name, const std::string &option,
+                         const std::string &value)
+{
+#if defined(HAVE_PLUGINS)
+  try {
+    PluginManager::instance()->setPluginOption(name, option, value);
+  }
+  catch(...) {
+    Msg::Error("Unknown plugin or plugin option");
+    throw 2;
+  }
+#else
+  Msg::Error("Views require the post-processing and plugin modules");
+  throw -1;
+#endif
+}
+
+void gmshPluginRun(const std::string &name)
+{
+#if defined(HAVE_PLUGINS)
+  try {
+    PluginManager::instance()->action(name, "Run", 0);
+  }
+  catch(...) {
+    Msg::Error("Unknown plugin or plugin action");
+    throw 2;
+  }
+#else
+  Msg::Error("Views require the post-processing and plugin modules");
+  throw -1;
+#endif
+}
diff --git a/Common/gmsh.h b/Common/gmsh.h
index 98001e41817191a1095cb79cfe21647d02a677eb..971102939dd9533af9382dc56859a4110cb30341 100644
--- a/Common/gmsh.h
+++ b/Common/gmsh.h
@@ -775,6 +775,9 @@ GMSH_API void gmshViewDelete(const int tag);
 // access view options with the gmshOption functions.
 GMSH_API int gmshViewGetIndex(const int tag);
 
+// Gets the tags of all views.
+GMSH_API void gmshViewGetTags(std::vector<int> &tags);
+
 // Adds model-based post-processing data to the view with tag `tag'. `modelName'
 // identifies the model the data is attached to. `dataType' specifies the type
 // of data, currently either "NodeData", "ElementData" or
@@ -800,6 +803,23 @@ GMSH_API void gmshViewAddModelData(const int tag, const std::string &modelName,
 GMSH_API void gmshViewExport(const int tag, const std::string &fileName,
                              const bool append = false);
 
+// -----------------------------------------------------------------------------
+// Module gmshPlugin: plugin functions
+// -----------------------------------------------------------------------------
+
+// Sets the numerical option `option` to the value `value' for plugin `name'.
+GMSH_API void gmshPluginSetNumber(const std::string &name,
+                                  const std::string &option,
+                                  const double value);
+
+// Sets the string option `option` to the value `value' for plugin `name'.
+GMSH_API void gmshPluginSetString(const std::string &name,
+                                  const std::string &option,
+                                  const std::string &value);
+
+// Runs the plugin `name'.
+GMSH_API void gmshPluginRun(const std::string &name);
+
 #undef GMSH_API
 
 #endif
diff --git a/Plugin/Levelset.cpp b/Plugin/Levelset.cpp
index 6b1830f9f72bdc17c8ed94ee8579895557317da5..9ae408015803635ed67d8d68f8a2614186981452 100644
--- a/Plugin/Levelset.cpp
+++ b/Plugin/Levelset.cpp
@@ -466,8 +466,7 @@ PView *GMSH_LevelsetPlugin::execute(PView *v)
   double scalarValues[8] = {0., 0., 0., 0., 0., 0., 0., 0.};
 
   if(_valueIndependent) {
-    // create a single output view containing the (possibly
-    // multi-step) levelset
+    // create a single output view containing the (possibly multi-step) levelset
     int firstNonEmptyStep = vdata->getFirstNonEmptyTimeStep();
     PViewDataList *out = getDataList(new PView());
     for(int ent = 0; ent < vdata->getNumEntities(firstNonEmptyStep); ent++){
diff --git a/Post/PViewDataGModelIO.cpp b/Post/PViewDataGModelIO.cpp
index c1b59a98e43ebb9f07744efc743ad66b17b93458..70827db45fd6c421dcbc1143b98e06d09066be93 100644
--- a/Post/PViewDataGModelIO.cpp
+++ b/Post/PViewDataGModelIO.cpp
@@ -53,7 +53,6 @@ bool PViewDataGModel::addData(GModel *model,
                               const std::vector<std::vector<double> > &data,
                               int step, double time, int partition, int numComp)
 {
-  printf("data size %d tag size %d\n", data.size() , tags.size());
   if(data.empty() || tags.empty() || data.size() != tags.size()) return false;
 
   if (numComp < 0){
diff --git a/demos/api/plugin.cpp b/demos/api/plugin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..feba77fc57cd88c5735c775bd9df9a6dbc0cf834
--- /dev/null
+++ b/demos/api/plugin.cpp
@@ -0,0 +1,43 @@
+#include <gmsh.h>
+
+int main(int argc, char **argv)
+{
+  gmshInitialize();
+  gmshOptionSetNumber("General.Terminal", 1);
+
+  // Copied from discrete.cpp...
+  gmshModelCreate("test");
+  gmshModelAddDiscreteEntity(2, 1);
+  gmshModelSetMeshVertices(2, 1, {1, 2, 3, 4},
+                           {0., 0., 0.,
+                            1., 0., 0.,
+                            1., 1., 0.,
+                            0., 1., 0.});
+  gmshModelSetMeshElements(2, 1, {2}, {{1, 2}},
+                           {{1, 2, 3,
+                             1, 3, 4}});
+  // ... end of copy
+
+  // create a view with some data
+  int t = gmshViewCreate("some data");
+  gmshViewAddModelData(t, "test", "NodeData",
+                       {1, 2, 3, 4},
+                       {{1.},{10.},{20.},{1.}});
+
+  // compute the iso-curve at value 11
+  gmshPluginSetNumber("Isosurface", "Value", 11.);
+  gmshPluginRun("Isosurface");
+
+  // delete the source view
+  gmshViewDelete(t);
+
+  // check how many views the plugin created (a priori, a single one)
+  std::vector<int> tags;
+  gmshViewGetTags(tags);
+  if(tags.size() == 1)
+    gmshViewExport(tags[0], "iso.msh");
+
+  gmshFinalize();
+  return 0;
+}
+
diff --git a/demos/api/plugin.py b/demos/api/plugin.py
new file mode 100644
index 0000000000000000000000000000000000000000..70dfe49067a83c82c42025accc52b009440ed93d
--- /dev/null
+++ b/demos/api/plugin.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+from gmsh import *
+import sys
+
+gmshInitialize(sys.argv)
+gmshOptionSetNumber("General.Terminal", 1)
+
+# Copied from discrete.py...
+gmshModelCreate("test");
+gmshModelAddDiscreteEntity(2, 1)
+gmshModelSetMeshVertices(2, 1, [1, 2, 3, 4],
+                         [0., 0., 0.,
+                          1., 0., 0.,
+                          1., 1., 0.,
+                          0., 1., 0.])
+gmshModelSetMeshElements(2, 1, [2], [[1, 2]],
+                         [[1, 2, 3,
+                           1, 3, 4]])
+# ... end of copy
+
+# create a view with some data
+t = gmshViewCreate("some data")
+gmshViewAddModelData(t, "test", "NodeData",
+                     [1, 2, 3, 4],
+                     [[1.],[10.],[20.],[1.]])
+
+# compute the iso-curve at value 11
+gmshPluginSetNumber("Isosurface", "Value", 11.)
+gmshPluginRun("Isosurface")
+
+# delete the source view
+gmshViewDelete(t)
+
+# check how many views the plugin created (a priori, a single one)
+tags = IntVector()
+gmshViewGetTags(tags)
+if tags.size() == 1:
+    gmshViewExport(tags[0], "iso.msh")
+
+gmshFinalize()
+
+