diff --git a/Civi/DataProcessor/Factory.php b/Civi/DataProcessor/Factory.php
index a69b8cee3d153c0d785d596c53fea6c3d86b5485..784e3ef4eeec9d66c99ffdbd08cb7c16233a4a2b 100644
--- a/Civi/DataProcessor/Factory.php
+++ b/Civi/DataProcessor/Factory.php
@@ -124,6 +124,7 @@ class Factory {
     $this->addOutput('participant_search', 'CRM_DataprocessorSearch_ParticipantSearch', E::ts('Participant Search'));
     $this->addOutput('export_csv', 'CRM_DataprocessorOutputExport_CSV', E::ts('CSV Export'));
     $this->addFilter('simple_sql_filter', 'Civi\DataProcessor\FilterHandler\SimpleSqlFilter', E::ts('Field filter'));
+    $this->addFilter('contact_in_group_filter', 'Civi\DataProcessor\FilterHandler\ContactInGroupFilter', E::ts('Contact in Group filter'));
     $this->addFilter('case_role_filter', 'Civi\DataProcessor\FilterHandler\CaseRoleFilter', E::ts('Case Role filter'));
     $this->addjoinType('simple_join', 'Civi\DataProcessor\DataFlow\MultipleDataFlows\SimpleJoin', E::ts('Select fields to join on'));
     $this->addjoinType('simple_non_required_join', 'Civi\DataProcessor\DataFlow\MultipleDataFlows\SimpleNonRequiredJoin', E::ts('Select fields to join on (not required)'));
@@ -132,6 +133,7 @@ class Factory {
     $this->addOutputHandler('file_field', 'Civi\DataProcessor\FieldOutputHandler\FileFieldOutputHandler', E::ts('File download link'));
     $this->addOutputHandler('option_label', 'Civi\DataProcessor\FieldOutputHandler\OptionFieldOutputHandler', E::ts('Option label'));
     $this->addOutputHandler('case_roles', 'Civi\DataProcessor\FieldOutputHandler\CaseRolesFieldOutputHandler', E::ts('Case Roles'));
+    $this->addOutputHandler('groups_of_contact', 'Civi\DataProcessor\FieldOutputHandler\GroupsOfContactFieldOutputHandler', E::ts('Display the groups of a contact'));
 
   }
 
diff --git a/Civi/DataProcessor/FieldOutputHandler/GroupsOfContactFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/GroupsOfContactFieldOutputHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..34d63ea6615b3a665298dab5da1467a65f142e04
--- /dev/null
+++ b/Civi/DataProcessor/FieldOutputHandler/GroupsOfContactFieldOutputHandler.php
@@ -0,0 +1,191 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+namespace Civi\DataProcessor\FieldOutputHandler;
+
+use Civi\DataProcessor\ProcessorType\AbstractProcessorType;
+use CRM_Dataprocessor_ExtensionUtil as E;
+use Civi\DataProcessor\Source\SourceInterface;
+use Civi\DataProcessor\DataSpecification\FieldSpecification;
+use Civi\DataProcessor\FieldOutputHandler\FieldOutput;
+
+class GroupsOfContactFieldOutputHandler extends AbstractFieldOutputHandler {
+
+  /**
+   * @var \Civi\DataProcessor\Source\SourceInterface
+   */
+  protected $dataSource;
+
+  /**
+   * @var SourceInterface
+   */
+  protected $contactIdSource;
+
+  /**
+   * @var FieldSpecification
+   */
+  protected $contactIdField;
+
+  /**
+   * @var FieldSpecification
+   */
+  protected $outputFieldSpecification;
+
+  /**
+   * @var int|false
+   */
+  protected $parent_group_id;
+
+  /**
+   * @return \Civi\DataProcessor\DataSpecification\FieldSpecification
+   */
+  public function getOutputFieldSpecification() {
+    return $this->outputFieldSpecification;
+  }
+
+  /**
+   * Returns the data type of this field
+   *
+   * @return String
+   */
+  protected function getType() {
+    return 'String';
+  }
+
+  /**
+   * Initialize the processor
+   *
+   * @param String $alias
+   * @param String $title
+   * @param array $configuration
+   * @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $processorType
+   */
+  public function initialize($alias, $title, $configuration) {
+    $this->outputFieldSpecification = new FieldSpecification($alias, 'String', $title, null, $alias);
+    $this->contactIdSource = $this->dataProcessor->getDataSourceByName($configuration['datasource']);
+    $this->contactIdField = $this->contactIdSource->getAvailableFields()->getFieldSpecificationByName($configuration['field']);
+    $this->contactIdSource->ensureFieldInSource($this->contactIdField);
+
+    $this->outputFieldSpecification = new FieldSpecification($this->contactIdField->name, 'String', $title, null, $alias);
+
+    if (isset($configuration['parent_group']) && $configuration['parent_group']) {
+      $this->parent_group_id = civicrm_api3('Group', 'getvalue', array('return' => 'id', 'name' => $configuration['parent_group']));
+    }
+  }
+
+  /**
+   * Returns the formatted value
+   *
+   * @param $rawRecord
+   * @param $formattedRecord
+   *
+   * @return \Civi\DataProcessor\FieldOutputHandler\FieldOutput
+   */
+  public function formatField($rawRecord, $formattedRecord) {
+    $contactId = $rawRecord[$this->contactIdField->alias];
+    $sql = "SELECT g.title, g.id
+            FROM civicrm_group g 
+            INNER JOIN civicrm_group_contact gc ON gc.group_id = g.id
+            WHERE gc.status = 'Added' AND gc.contact_id = %1";
+    if ($this->parent_group_id) {
+      $childGroupIds = \CRM_Contact_BAO_GroupNesting::getDescendentGroupIds([$this->parent_group_id], FALSE);
+      $sql .= " AND gc.group_id IN (".implode(", ", $childGroupIds).")";
+    }
+    $sql .= " ORDER BY g.title";
+    $sqlParams[1] = array($contactId, 'Integer');
+    $dao = \CRM_Core_DAO::executeQuery($sql, $sqlParams);
+    $rawValues = array();
+    $formattedValues = array();
+    while($dao->fetch()) {
+      $rawValues[] = array(
+        'group_id' => $dao->id,
+        'group' => $dao->title,
+      );
+      $formattedValues[] = $dao->title;
+    }
+    $output = new FieldOutput($rawValues);
+    $output->formattedValue = implode(", ", $formattedValues);
+    return $output;
+  }
+
+  /**
+   * Returns true when this handler has additional configuration.
+   *
+   * @return bool
+   */
+  public function hasConfiguration() {
+    return true;
+  }
+
+  /**
+   * When this handler has additional configuration you can add
+   * the fields on the form with this function.
+   *
+   * @param \CRM_Core_Form $form
+   * @param array $field
+   */
+  public function buildConfigurationForm(\CRM_Core_Form $form, $field=array()) {
+    $fieldSelect = \CRM_Dataprocessor_Utils_DataSourceFields::getAvailableFieldsInDataSources($field['data_processor_id']);
+    $groupsApi = civicrm_api3('Group', 'get', array('is_active' => 1, 'options' => array('limit' => 0)));
+    $groups = array();
+    foreach($groupsApi['values'] as $group) {
+      $groups[$group['name']] = $group['title'];
+    }
+
+    $form->add('select', 'contact_id_field', E::ts('Contact ID Field'), $fieldSelect, true, array(
+      'style' => 'min-width:250px',
+      'class' => 'crm-select2 huge',
+      'placeholder' => E::ts('- select -'),
+    ));
+    $form->add('select', 'parent_group', E::ts('Show only subgroup(s) of'), $groups, false, array(
+      'style' => 'min-width:250px',
+      'class' => 'crm-select2 huge',
+      'placeholder' => E::ts('- Show all groups -'),
+      'multiple' => false,
+    ));
+
+    if (isset($field['configuration'])) {
+      $configuration = $field['configuration'];
+      $defaults = array();
+      if (isset($configuration['field']) && isset($configuration['datasource'])) {
+        $defaults['contact_id_field'] = $configuration['datasource'] . '::' . $configuration['field'];
+      }
+      if (isset($configuration['parent_group'])) {
+        $defaults['parent_group'] = $configuration['parent_group'];
+      }
+      $form->setDefaults($defaults);
+    }
+  }
+
+  /**
+   * When this handler has configuration specify the template file name
+   * for the configuration form.
+   *
+   * @return false|string
+   */
+  public function getConfigurationTemplateFileName() {
+    return "CRM/Dataprocessor/Form/Field/Configuration/GroupsOfContactFieldOutputHandler.tpl";
+  }
+
+
+  /**
+   * Process the submitted values and create a configuration array
+   *
+   * @param $submittedValues
+   * @return array
+   */
+  public function processConfiguration($submittedValues) {
+    list($datasource, $field) = explode('::', $submittedValues['contact_id_field'], 2);
+    $configuration['field'] = $field;
+    $configuration['datasource'] = $datasource;
+    $configuration['parent_group'] = isset($submittedValues['parent_group']) ? $submittedValues['parent_group'] : false;
+    return $configuration;
+  }
+
+
+
+
+}
\ No newline at end of file
diff --git a/Civi/DataProcessor/FilterHandler/ContactInGroupFilter.php b/Civi/DataProcessor/FilterHandler/ContactInGroupFilter.php
new file mode 100644
index 0000000000000000000000000000000000000000..04f3e63095c43667773e47bf1a440e4f3bf0f6ee
--- /dev/null
+++ b/Civi/DataProcessor/FilterHandler/ContactInGroupFilter.php
@@ -0,0 +1,226 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+namespace Civi\DataProcessor\FilterHandler;
+
+use Civi\DataProcessor\DataFlow\SqlDataFlow;
+use Civi\DataProcessor\DataFlow\SqlTableDataFlow;
+use Civi\DataProcessor\DataSpecification\CustomFieldSpecification;
+use Civi\DataProcessor\DataSpecification\FieldSpecification;
+use Civi\DataProcessor\Source\SourceInterface;
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+class ContactInGroupFilter extends AbstractFilterHandler {
+
+  /**
+   * @var \Civi\DataProcessor\DataSpecification\FieldSpecification
+   */
+  protected $fieldSpecification;
+
+  /**
+   * @var SourceInterface
+   */
+  protected $dataSource;
+
+  /**
+   * @var array
+   */
+  protected $parent_group_id = false;
+
+  public function __construct() {
+    parent::__construct();
+  }
+
+  /**
+   * Initialize the processor
+   *
+   * @param String $alias
+   * @param String $title
+   * @param bool $is_required
+   * @param array $configuration
+   */
+  public function initialize($alias, $title, $is_required, $configuration) {
+    if ($this->fieldSpecification) {
+      return; // Already initialized.
+    }
+    if (!isset($configuration['datasource']) || !isset($configuration['field'])) {
+      return; // Invalid configuration
+    }
+
+    $this->is_required = $is_required;
+
+    $this->dataSource = $this->data_processor->getDataSourceByName($configuration['datasource']);
+    if ($this->dataSource) {
+      $this->fieldSpecification  =  clone $this->dataSource->getAvailableFilterFields()->getFieldSpecificationByName($configuration['field']);
+      $this->fieldSpecification->alias = $alias;
+      $this->fieldSpecification->title = $title;
+    }
+
+    if (isset($configuration['parent_group']) && $configuration['parent_group']) {
+      $this->parent_group_id = civicrm_api3('Group', 'getvalue', array('return' => 'id', 'name' => $configuration['parent_group']));
+    }
+  }
+
+  /**
+   * @return \Civi\DataProcessor\DataSpecification\FieldSpecification
+   */
+  public function getFieldSpecification() {
+    return $this->fieldSpecification;
+  }
+
+  /**
+   * @param array $filter
+   *   The filter settings
+   * @return mixed
+   */
+  public function setFilter($filter) {
+    $dataFlow  = $this->dataSource->ensureField($this->fieldSpecification->name);
+    $group_ids = $filter['value'];
+    if (!is_array($group_ids)) {
+      $group_ids = array($group_ids);
+    }
+    $groupTableAlias = 'civicrm_group_contact_'.$this->fieldSpecification->alias;
+    $groupFilters = array(
+      new SqlDataFlow\SimpleWhereClause($groupTableAlias, 'status', '=', 'Added'),
+      new SqlDataFlow\SimpleWhereClause($groupTableAlias, 'group_id', 'IN', $group_ids),
+    );
+
+    if ($dataFlow && $dataFlow instanceof SqlDataFlow) {
+      $whereClause = new SqlDataFlow\InTableWhereClause(
+        'contact_id',
+        'civicrm_group_contact',
+        $groupTableAlias,
+        $groupFilters,
+        $dataFlow->getName(),
+        $this->fieldSpecification->name,
+        $filter['op']
+      );
+
+      $dataFlow->addWhereClause($whereClause);
+    }
+  }
+
+  /**
+   * Returns true when this filter has additional configuration
+   *
+   * @return bool
+   */
+  public function hasConfiguration() {
+    return true;
+  }
+
+  /**
+   * When this filter type has additional configuration you can add
+   * the fields on the form with this function.
+   *
+   * @param \CRM_Core_Form $form
+   * @param array $filter
+   */
+  public function buildConfigurationForm(\CRM_Core_Form $form, $filter=array()) {
+    $fieldSelect = \CRM_Dataprocessor_Utils_DataSourceFields::getAvailableFilterFieldsInDataSources($filter['data_processor_id']);
+    $groupsApi = civicrm_api3('Group', 'get', array('is_active' => 1, 'options' => array('limit' => 0)));
+    $groups = array();
+    foreach($groupsApi['values'] as $group) {
+      $groups[$group['name']] = $group['title'];
+    }
+
+    $form->add('select', 'contact_id_field', E::ts('Contact ID Field'), $fieldSelect, true, array(
+      'style' => 'min-width:250px',
+      'class' => 'crm-select2 huge',
+      'placeholder' => E::ts('- select -'),
+    ));
+
+    $form->add('select', 'parent_group', E::ts('Show only subgroup(s) of'), $groups, false, array(
+      'style' => 'min-width:250px',
+      'class' => 'crm-select2 huge',
+      'placeholder' => E::ts('- Show all groups -'),
+      'multiple' => false,
+    ));
+
+    if (isset($filter['configuration'])) {
+      $configuration = $filter['configuration'];
+      $defaults = array();
+      if (isset($configuration['field']) && isset($configuration['datasource'])) {
+        $defaults['contact_id_field'] = $configuration['datasource'] . '::' . $configuration['field'];
+      }
+      if (isset($configuration['parent_group'])) {
+        $defaults['parent_group'] = $configuration['parent_group'];
+      }
+      $form->setDefaults($defaults);
+    }
+  }
+
+  /**
+   * When this filter type has configuration specify the template file name
+   * for the configuration form.
+   *
+   * @return false|string
+   */
+  public function getConfigurationTemplateFileName() {
+    return "CRM/Dataprocessor/Form/Filter/Configuration/ContactInGroupFilter.tpl";
+  }
+
+
+  /**
+   * Process the submitted values and create a configuration array
+   *
+   * @param $submittedValues
+   * @return array
+   */
+  public function processConfiguration($submittedValues) {
+    list($datasource, $field) = explode('::', $submittedValues['contact_id_field'], 2);
+    $configuration['field'] = $field;
+    $configuration['datasource'] = $datasource;
+    $configuration['parent_group'] = isset($submittedValues['parent_group']) ? $submittedValues['parent_group'] : false;
+    return $configuration;
+  }
+
+  /**
+   * Add the elements to the filter form.
+   *
+   * @param \CRM_Core_Form $form
+   * @return array
+   *   Return variables belonging to this filter.
+   */
+  public function addToFilterForm(\CRM_Core_Form $form) {
+    $fieldSpec = $this->getFieldSpecification();
+    $operations = $this->getOperatorOptions($fieldSpec);
+
+    $title = $fieldSpec->title;
+    if ($this->isRequired()) {
+      $title .= ' <span class="crm-marker">*</span>';
+    }
+
+    $api_params['is_active'] = 1;
+    if ($this->parent_group_id) {
+      $childGroupIds = \CRM_Contact_BAO_GroupNesting::getDescendentGroupIds([$this->parent_group_id], FALSE);
+      $api_params['id']['IN'] = $childGroupIds;
+    }
+
+    $form->addElement('select', "{$fieldSpec->alias}_op", E::ts('Operator:'), $operations);
+    $form->addEntityRef( "{$fieldSpec->alias}_value", NULL, array(
+      'placeholder' => E::ts('Select a group'),
+      'entity' => 'Group',
+      'api' => array('params' => $api_params),
+      'create' => false,
+      'multiple' => true,
+    ));
+
+    $filter['type'] = $fieldSpec->type;
+    $filter['title'] = $title;
+
+    return $filter;
+  }
+
+  protected function getOperatorOptions(\Civi\DataProcessor\DataSpecification\FieldSpecification $fieldSpec) {
+    return array(
+      'IN' => E::ts('Is one of'),
+      'NOT IN' => E::ts('Is not one of'),
+    );
+  }
+
+
+}
\ No newline at end of file
diff --git a/templates/CRM/Dataprocessor/Form/Field/Configuration/GroupsOfContactFieldOutputHandler.tpl b/templates/CRM/Dataprocessor/Form/Field/Configuration/GroupsOfContactFieldOutputHandler.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..b35503fcac911e14a56dafbdf70a93970e381edd
--- /dev/null
+++ b/templates/CRM/Dataprocessor/Form/Field/Configuration/GroupsOfContactFieldOutputHandler.tpl
@@ -0,0 +1,12 @@
+{crmScope extensionKey='dataprocessor'}
+    <div class="crm-section">
+        <div class="label">{$form.contact_id_field.label}</div>
+        <div class="content">{$form.contact_id_field.html}</div>
+        <div class="clear"></div>
+    </div>
+    <div class="crm-section">
+        <div class="label">{$form.parent_group.label}</div>
+        <div class="content">{$form.parent_group.html}</div>
+        <div class="clear"></div>
+    </div>
+{/crmScope}
\ No newline at end of file
diff --git a/templates/CRM/Dataprocessor/Form/Filter/Configuration/ContactInGroupFilter.tpl b/templates/CRM/Dataprocessor/Form/Filter/Configuration/ContactInGroupFilter.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..f71c32a0c6cc3e5dfdf0577465e694d25a824d96
--- /dev/null
+++ b/templates/CRM/Dataprocessor/Form/Filter/Configuration/ContactInGroupFilter.tpl
@@ -0,0 +1,12 @@
+{crmScope extensionKey='dataprocessor'}
+<div class="crm-section">
+    <div class="label">{$form.contact_id_field.label}</div>
+    <div class="content">{$form.contact_id_field.html}</div>
+    <div class="clear"></div>
+</div>
+<div class="crm-section">
+    <div class="label">{$form.parent_group.label}</div>
+    <div class="content">{$form.parent_group.html}</div>
+    <div class="clear"></div>
+</div>
+{/crmScope}
\ No newline at end of file