---
title: Manage groups
slug: cms-12/api/managing-groups
docTags: 
createdAt: 2026-08-07T16:45:43.000Z
---

Optimizely Community API represents a group with the **Group** class.

An instance of the Group class is constructed with a name (string) and a description (string). An example of this construction is below:

```csharp
var group = new Group("Marketing Department", "A group for collaborating within the Marketing Department.");
```

Groups are managed through a service implementing the interface `IGroupService`. This service lets you persist, retrieve, update, and remove groups you define.

## Access an IGroupService

When the Groups feature is installed on an Optimizely CMS site with the feature's site integration package, you can get an instance of this service from the inversion of control (IoC) container.

Example:

```csharp
var groupService = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IGroupService>();
```

When the feature is installed on a non-Optimizely CMS site, you can get an instance of a service from the default `factory` class provided in the package.

Example:

```csharp
var factory = new EPiServer.Social.Groups.DefaultGroupServiceFactory();
var groupService = factory.Create();
```

## Add a group

To add a group, use the `Add(Group)` method of the `IGroupService`. This method accepts an instance of the `Group` class and returns a reference to an instance of that class, populated with any additional, system-generated data (for example, a unique ID).

```csharp
IGroupService groupService;

// ...
var group = new Group("Marketing Department", "A group for collaborating within the Marketing Department.");
groupService.Add(group);
```

The above example invokes the request to add a group synchronously. An example of adding a group asynchronously using the asynchronous overload with C#'s async and await keywords is described below.

```csharp
private async Task<Group> AddGroupAsync(IGroupService groupService) {
  // ...
  var group = new Group("Marketing Department", "A group for collaborating within the Marketing Department.");
  var addGroupTask = groupService.AddAsync(group);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var addedGroup = await addGroupTask;
  return addedGroup;
}
```

## Update a group

To update a group which was previously added through the platform, use the `Update(Group)` method of the `IGroupService`.

```csharp
IGroupService groupService;
Group existingGroup;
// ...
var group = new Group(existingGroup.Id, "New name", "A new description");
groupService.Update(group);
```

If the `Group` to be updated does not exist, a `GroupDoesNotExistException` is thrown.

The above example invokes the request to update a group synchronously. Below is an example of updating a group asynchronously using the asynchronous overload with C#'s async and await keywords.

```csharp
private async Task<Group> UpdateGroupAsync(IGroupService groupService) {
  Group existingGroup;

  // ...
  var group = new Group(existingGroup.Id, "New name", "A new description");
  var updateGroupTask = groupService.UpdateAsync(group);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var updatedGroup = await updateGroupTask;

  return updatedGroup;
}
```

If the identified `Group` is a Composite Group, its name and description are updated, and its associated extension data remains intact. For information on Composite Groups, see Extending Groups with Composites.

## Retrieve a group

To retrieve a specific instance of a `Group`, which has previously been added through the platform, use the `Get(GroupId)` method of `IGroupService`. This method accepts an instance of the `GroupId` class, which identifies the `Group` to retrieve. It returns the instance of the `Group` class corresponding to that identifier.

```csharp
IGroupService groupService;

// ...

// Construct a GroupId corresponding to the desired group
var groupId = GroupId.Create("...")
var group = groupService.Get(groupId);
```

If the requested `Group` cannot be found, a `GroupDoesNotExistException` is thrown.

The above example invokes the request to retrieve a group synchronously. An example of retrieving a group asynchronously using the asynchronous overload with C#'s async and await keywords is described below.

```csharp
private async Task<Group> GetGroupAsync(IGroupService groupService) {
  //...

  // Construct a GroupId corresponding to the desired group
  var groupId = GroupId.Create("...");

  var getGroupTask = groupService.GetAsync(groupId);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var group = await getGroupTask;
  return group;
}
```

To retrieve a collection of groups which were previously added through the platform, use the `Get(Criteria<GroupFilter>`)  method. This method accepts an instance of `Criteria`, which contains the specifications necessary to retrieve the desired groups.

The `Filter` property of the `Criteria <GroupFilter>` class accepts an instance of the `GroupFilter` class. This class contains the specifications that let you refine the result set of groups that you want to retrieve.

The properties of the `GroupFilter` include:

- `Name` – Assigning a value (`String`) to this property refines a result set to `Groups` with the specified name.
- `GroupIds` – Assigning a value (`IEnumerable<GroupId>`) to this property refines a result set to `Groups` with IDs included in that collection.

The specifications of the `GroupFilter` may be applied in conjunction with one another. Each specification assigned a value in the filter further refines the result set (that is, a logical AND).

The example below demonstrates the retrieval of a result page of `Groups`, which exist in a set of identified groups.

```csharp
IGroupService groupService;

// ...

// Define a collection identifying the various groups to be retrieved
var knownGroups = new List<GroupId> {
  GroupId.Create("..."),
  GroupId.Create("..."),
  GroupId.Create("...")
};

var criteria = new Criteria<GroupFilter> {
  Filter = new GroupFilter {
    GroupIds = knownGroups
  }
};

var pageOfGroups = groupService.Get(criteria);
```

In the above examples, the request to retrieve groups is invoked synchronously. An example of retrieving groups asynchronously using the asynchronous overload with C#'s async and await keywords is described below.

```csharp
private async Task<ResultPage<Group>> GetGroupsAsync(IGroupService groupService) {
  // ...

  // Define a collection identifying the various groups to be retrieved
  var knownGroups = new List<GroupId> {
    GroupId.Create("..."),
    GroupId.Create("..."),
    GroupId.Create("...")
  };

  var criteria = new Criteria<GroupFilter> {
    Filter = new GroupFilter {
      GroupIds = knownGroups
    }
  };
  var getGroupTask = groupService.GetAsync(criteria);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var pageOfGroups = await getGroupTask;
  return pageOfGroups;
}
```

The `GroupSortFields` class exposes a set of fields upon which a result set of groups may be ordered. These fields may be applied when constructing sorting rules you associate with your criteria. These fields include:

- `GroupSortFields.Created`
- `GroupSortFields.Id`
- `GroupSortFields.Name`

The example below demonstrates how to apply sorting rules to order a result set by name, alphabetically from A-Z. A fallback rule, subsequently ordering results with the same name according to when they were created from newest to oldest, is also added.

```csharp
{
  // ...

  OrderBy = new List<SortInfo> {
    new SortInfo(GroupSortFields.Name, true),
    new SortInfo(GroupSortFields.Created, false)
  }
};
```

For more details regarding criteria use, including information on paging and sorting, see *Criteria* in [Discover the platform](docId\:NKmGS-fLtRQIYLEWZfb69).

## Remove a group

To remove a specific instance of a group which has previously been added through the platform, use the `Remove(GroupId)` method. This method accepts an instance of the `GroupId` class, which identifies the `GroupId` to be removed. The result is the deletion of the group corresponding to that ID.

```csharp
IGroupService groupService;

// ...

// Construct or retrieve an ID for an existing Group.
var groupId = GroupId.Create("...");
groupService.Remove(groupId);
```

- If members or content are still associated with the group, the group cannot be deleted.
- If the group being removed has existing members in the system when the remove operation is attempted, a `MemberStillExistsException` is thrown.
- If the group being removed has existing content associations in the system when the remove operation is attempted, an `AssociationStillExistsException` is thrown.

Remove existing members and content before removing a group.

The above example invokes the request to remove a group synchronously. An example of removing a group asynchronously using the asynchronous overload with C#'s async and await keywords is described below.

```csharp
private async Task RemoveGroupAsync(IGroupService groupService) {
  //...

  // Construct or retrieve an ID for an existing Group.
  var groupId = GroupId.Create("...");

  var removeGroupTask = groupService.RemoveAsync(groupId);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  await removeGroupTask;
}
```

## Extend groups with composites

In its simplest form, a group is just a named aggregation of users and content. You may need to associate additional information with `Groups` to further describe and shape them. For example, suppose you are leveraging groups within your application to represent an athletic team. In that case, you might capture information describing the team's location, mascot, or the date it originally formed.

Like many of the other Optimizely Community API features, you can extend a `Group` with data from your design by creating a composite. See *Composites* in [Discover the platform](docId\:NKmGS-fLtRQIYLEWZfb69).

### Add a composite group

To save a Composite Group which you have defined, use the `Add<TExtension>(Group, TExtension)` method of the `IGroupService`. This method accepts an instance of the Group class and an instance of `TExtension`. It returns an instance of `Composite\<Group,TExtension>`.

Consider the following class, which represents a sample of extension data:

```csharp
public class AthleticTeam {
  public string Mascot {
    get;
    set;
  }
  public string Location {
    get;
    set;
  }
  public DateTime Established {
    get;
    set;
  }
}
```

In the example below, a group is composed of an instance of this extension class:

```csharp
IGroupService groupService;

// ...

var group = new Group("The Wombats", "A group for The Wombats team.");
var extension = new AthleticTeam {
  Mascot = "Wombat",
    Location = "Nashua",
    Established = new DateTime(5, 1, 2014)
};

var compositeGroup = groupService.Add(group, extension);
```

The above example invokes the request to add a group synchronously. An example of adding a group asynchronously using the asynchronous overload with C#'s async and await keywords is described below.

```csharp
private async Task<Composite<Group, AthleticTeam>> AddGroupAsync(IGroupService groupService) {
  // ...

  var group = new Group("The Wombats", "A group for The Wombats team.");
  var extension = new AthleticTeam {
    Mascot = "Wombat",
      Location = "Nashua",
      Established = new DateTime(5, 1, 2014)
  };

  var addGroupTask = groupService.AddAsync(group, extension);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var compositeGroup = await addGroupTask;
  return compositeGroup;
}
```

### Update a composite group

To update a specific instance of a Composite Group, which was previously added through the platform, use the `Update(Group,TExtension)` method of the `IGroupService`.

Consider the following class, which represents a sample of extension data:

```csharp
public class AthleticTeam {
  public string Mascot {
    get;
    set;
  }
  public string Location {
    get;
    set;
  }
  public DateTime Established {
    get;
    set;
  }
}
```

In the example below, an existing group is updated with an instance of this extension class:

```csharp
IGroupService groupService;
var existingGroup;

// ...

var group = new Group(existingGroup.Id, "New team name", "A new description for the group.");
var extension = new AthleticTeam {
  Mascot = "Lion",
    Location = "Nashua",
    Established = new DateTime(6, 1, 2016)
};

groupService.Update(group, extension);
```

If a Group with the specified ID cannot be found, a `GroupDoesNotExistException` is thrown.

The above example invokes the request to update a group synchronously. Below is an example of updating a group asynchronously using the asynchronous overload with C#'s async and await keywords.

```csharp
private async Task<Composite<Group, AthleticTeam>> UpdateGroupAsync(IGroupService groupService) {
  var existingGroup;

  // ...

  var group = new Group(existingGroup.Id, "New team name", "A new description for the group.");
  var extension = new AthleticTeam {
    Mascot = "Lion",
      Location = "Nashua",
      Established = new DateTime(6, 1, 2016)
  };

  var updateGroupTask = groupService.UpdateAsync(group, extension);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var updatedGroup = await updateGroupTask;
  return updatedGroup;
}
```

### Retrieve a composite group

To retrieve a specific instance of a Composite Group, which was previously added through the platform, use the `Get<TExtension>(GroupId)` method. This method accepts an instance of the `GroupId` class, which identifies the `Group` to retrieve. It returns the instance of the `Composite\<Group,TExtension>` class corresponding to that identifier.

```csharp
IGroupService groupService;

//...

// Construct a GroupId corresponding to the desired group
var groupId = GroupId.Create("...");
var compositeGroup = groupService.Get<MyGroupExtension>(groupId);
```

If a Composite Group with the specified ID and extension type cannot be found, a `GroupDoesNotExistException` is thrown.

The above example invokes the request to retrieve a group synchronously. An example of retrieving a group asynchronously using the asynchronous overload with C#'s async and await keywords is described below.

```csharp
private async Task<Composite<Group, MyGroupExtension>> GetGroupAsync(IGroupService groupService) {
  //...

  // Construct a GroupId corresponding to the desired group
  var groupId = GroupId.Create("...");
  var getGroupTask = groupService.GetAsync<MyGroupExtension>(groupId);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var compositeGroup = await getGroupTask;
  return compositeGroup;
}
```

To retrieve a collection of Composite Groups, which were previously added through the platform, use the `Get<TExtension>(CompositeCriteria\<GroupFilter,TExtension>)` method. This method accepts an instance of `CompositeCriteria\<GroupFilter,TExtension>`, which contains the specifications to retrieve the desired Groups.

The `Filter` property of the `CompositeCriteria\<GroupFilter,TExtension>` class accepts an instance of the `GroupFilter` class. This class contains the specifications that let you refine the result set of `Groups` that you want to retrieve.

The `ExtensionFilter` property of the `CompositeCriteria\<GroupFilter,TExtension>` class accepts a `FilterExpression`, which lets you specify a Boolean expression to refine the result set further by values represented within your extension data. For information on this type of filter, see *Composite Criteria* and *Filter composites* in [Discover the platform](docId\:NKmGS-fLtRQIYLEWZfb69).

Consider the following class, which represents a sample of extension data:

```csharp
public class AthleticTeam {
  public string Mascot {
    get;
    set;
  }
  public string Location {
    get;
    set;
  }
  public DateTime Established {
    get;
    set;
  }
}
```

In the example below, a page of `Groups` composed with `AthleticTeam` is retrieved, where the `Established` property of that extension data contains a date after "1/1/2015".

```csharp
IGroupService groupService;

// ...

var criteria = new CompositeCriteria<GroupFilter,
  AthleticTeam> {
    ExtensionFilter = FilterExpressionBuilder<AthleticTeam> .Field(e => e.Established).GreaterThan(new DateTime(2015, 1, 1))
  };

var resultPage = groupService.Get(criteria);
```

In the above example, the request to retrieve groups is invoked synchronously. An example of retrieving groups asynchronously using the asynchronous overload with C#'s async and await keywords is described below.

```csharp
private async Task<ResultPage<Composite<Group, AthleticTeam>>> GetGroupsAsync(IGroupService groupService) {
  // ...

  var criteria = new CompositeCriteria<GroupFilter,
    AthleticTeam> {
      ExtensionFilter = FilterExpressionBuilder<AthleticTeam> .Field(e => e.Established).GreaterThan(new DateTime(2015, 1, 1))
    };

  var getGroupTask = groupService.GetAsync(criteria);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var pageOfGroups = await getGroupTask;
  return pageOfGroups;
}
```

The fields of your extension data may also be applied when sorting a result set. The example below demonstrates the use of an extension data field in defining a sorting rule.

```csharp
var criteria = new CompositeCriteria<GroupFilter,
  AthleticTeam> {
    OrderBy = new List<SortInfo> {
      new SortInfo(new SortField(FilterExpressionBuilder<AthleticTeam> .Field(e => e.Established)), false)
    }
  }
```
