---
title: Example: Create visitor group criteria
slug: cms-11/dev-docs/example-create-your-own-visitor-group-criteria
docTags: 
createdAt: 2026-07-22T19:45:18.655Z
---

(Thanks to [Ted & Gustaf](https://tedgustaf.com/) for this example.)

One usage scenario could be to check for a cookie that says that the visitor has previously completed a purchase on the website and is a returning customer.

## Create the settings and criterion classes

Visitor group criteria require a `settings` class and a `criterion` class.

- The `settings` class is used to persist any settings available to editors when creating visitor groups.
- The `criterion` class contains the logic to determine whether or not a visitor belongs to the visitor group.

You should create the two classes in a suitable folder structure:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/yscfAY60n2mCe3ygyD8J--20260722-194635.png "create_classes.png")

## Implement the settings class

The only setting required for this visitor group criterion is the cookie name you should look for.

1. First, make the `CookieExistsCriterionSettings` class inherits the `CriterionModelBase` class:

```csharp
public class CookieExistsCriterionSettings : CriterionModelBase
```

2. Add a public property to let editors specify the cookie name:

```csharp
[Required]
public string CookieName { 
  get; 
  set; 
}
```

3. If you need custom validation logic when you save a criterion, you can make your settings class implement the `IValidateCriterionModel` interface (this is optional). By implementing that interface’s `Validate` method, you can customize how you validate settings before saving a criterion for a visitor group.
   The abstract `CriterionModelBase` class requires you to implement the `Copy()` method. Because you are not using complex reference types, you can implement it by returning a shallow copy as shown (see [Create custom visitor group criteria](docId\:sSsuWY6oBpd7gUSaVD6l2)):

```csharp
public override ICriterionModel Copy() {
  return ShallowCopy();
}
```

The following code shows the complete `CookieExistsCriterionSettings` class:

```csharp
public class CookieExistsCriterionSettings: CriterionModelBase {
  [Required]
  public string CookieName {
    get;
    set;
  }

  public override ICriterionModel Copy() {
    return ShallowCopy();
  }
}
```

## Implement the criterion class

1. Make the `CookieExistsCriterionclass` inherit the abstract `CriterionBaseclass` with the settings class as the type parameter:

```csharp
public class CookieExistsCriterion : CriterionBase<CookieExistsCriterionSettings>
```

2. Add a `VisitorGroupCriterion` attribute to set the category, name, and description of your criterion (for more available `VisitorGroupCriterion` properties, see [Create custom visitor group criteria](docId\:sSsuWY6oBpd7gUSaVD6l2):

```csharp
[VisitorGroupCriterion(   
   Category = "Technical",
   DisplayName = "Cookie Exists",
   Description = "Checks if a specific cookie exists")]
```

3. The abstract `CriterionBase` class requires you to implement an `IsMatch()` method, which determines whether the current user matches this visitor group criterion. You should check if a specific cookie exists based on the criterion settings:

```csharp
public override bool IsMatch(IPrincipal principal, HttpContextBase httpContext) {
  return httpContext.Request.Cookies[Model.CookieName] != null;
}
```

The criterion class displays as follows:

```csharp
[VisitorGroupCriterion(
  Category = "Technical",
  DisplayName = "Cookie Exists",
  Description = "Checks if a specific cookie exists")]

public class CookieExistsCriterion: CriterionBase<CookieExistsCriterionSettings> {
  public override bool IsMatch(IPrincipal principal, HttpContextBase httpContext) {
    return httpContext.Request.Cookies[Model.CookieName] != null;
  }
}
```

:::hint{type="info"}
**Note**
You access the criterion settings instance through the `Modelproperty`.
:::

## Test the criterion

Create a visitor group using the new cookie criterion to test the criterion.

1. Set the cookie name to **.EPiServerLogin**, the name of the cookie created when a user logs in:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/8rmmQjN87xCRbEp20T416-20260722-184805.png)

If you are on CMS version 10 or 11, it will look like this:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/uUAjy3YyNULPIJ4Kl_M1P-20260722-184805.png)

2. Select some content in the editor that you should display only to logged-in Episerver users.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/VkiZXJb459hsrjQFR6dbA-20260722-184805.png)

3. Click **Personalized Content** and select the **Episerver User** visitor group.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/kDTEnujnpucf1fNZbY6aD-20260722-184805.png)

This content is now only displayed to users logged into Episerver:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/NYADsxaSZLjhhJ5Y2ZQab-20260722-194635.png "personalizedcontenttinymce.png")

After publishing the page, you see this:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/btI9qecI0Y9oY9wE8hfEg-20260722-194635.png "logged_in2.png")

However, you no longer see the personalized content if you log out.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/X3AkJZ68ztE48Tg2fibu7-20260722-194635.png "not_logged_in.png")
