---
title: Customize customer eligibility
related:
  - https://docs.kentico.com/documentation/developers-and-admins/digital-commerce-setup/promotions.md
  - https://docs.kentico.com/documentation/developers-and-admins/digital-commerce-setup/promotions/catalog-discounts.md
  - https://docs.kentico.com/documentation/developers-and-admins/digital-commerce-setup/promotions/order-discounts.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

> **License:** Advanced license required.
>
> Features described on this page require the Xperience by Kentico **Advanced** license tier.

You can extend the customer eligibility system by adding custom eligibility options (e.g., "Premium members", "Loyalty tier members") that appear alongside the built-in options in the [promotion](https://docs.kentico.com/documentation/developers-and-admins/digital-commerce-setup/promotions.md#customer-eligibility) form. This example targets members with a specific [member role](https://docs.kentico.com/documentation/developers-and-admins/development/registration-and-authentication/member-roles.md) – see the linked page for role setup.

Customization involves two components connected by a shared string identifier:

1. **Options provider** (`IPromotionCustomerEligibilityOptionsProvider`) – adds custom options to the **Target customers** field in the admin UI with a string identifier (e.g., `"premium-members"`).
2. **Eligibility validator** (`IPromotionCustomerEligibilityValidator`) – evaluates the stored eligibility value at runtime and decides whether the buyer is eligible.

When a store manager selects your custom option and saves the promotion, the system stores the string identifier (e.g., `"premium-members"`) on the `PromotionInfo` record. During price calculation, the framework reads this stored value and passes it to the validator chain. Your validator matches on the same string value and runs the custom eligibility logic.

![Customer eligibility customization flow](https://docs.kentico.com/docsassets/documentation/customer-eligibility-customization/customer-eligibility-customization-flow.drawio.svg "Customer eligibility customization flow")

## Add custom eligibility options

Implement `IPromotionCustomerEligibilityOptionsProvider` to extend and filter the available customer eligibility options in the promotion admin form. The `GetOptions` method receives the current set of options and the promotion type, allowing you to add new options or filter existing ones per promotion type.

```csharp title="Custom eligibility options provider"
using System.Collections.Generic;
using System.Linq;

using CMS.Commerce;

using Kentico.Xperience.Admin.DigitalCommerce;

public class PremiumMemberEligibilityOptionsProvider
    : IPromotionCustomerEligibilityOptionsProvider
{
    // Defines a custom eligibility value
    public static readonly PromotionCustomerEligibility PremiumMembersOnly =
        new PromotionCustomerEligibility("premium-members");

    public IEnumerable<PromotionCustomerEligibilityOption> GetOptions(
        IEnumerable<PromotionCustomerEligibilityOption> options,
        PromotionType promotionType)
    {
        // Adds the custom option to the existing built-in options
        return options.Append(
            new PromotionCustomerEligibilityOption(PremiumMembersOnly, "Premium members only"));
    }
}
```

Register the provider in the DI container:

```csharp title="Program.cs"
using CMS;

using Kentico.Xperience.Admin.DigitalCommerce;

// Registers the custom eligibility options provider in the DI container
[assembly: RegisterImplementation(
    implementedType: typeof(IPromotionCustomerEligibilityOptionsProvider),
    implementation: typeof(PremiumMemberEligibilityOptionsProvider))]
```

## Validate custom eligibility

Implement `IPromotionCustomerEligibilityValidator` using the decorator pattern to handle your custom eligibility values. The default validator returns `false` for unknown values, so your implementation handles custom values and delegates to the inner (default) validator for built-in values.

In this example, the validator injects `IHttpContextAccessor` and uses `ClaimsPrincipal.IsInRole()` to check whether the current buyer has the required member role. This works because ASP.NET Identity adds role claims to the `ClaimsPrincipal` when you configure [role management](https://docs.kentico.com/documentation/developers-and-admins/development/registration-and-authentication/member-roles.md).

```csharp title="Custom eligibility validator (decorator)"
using System.Threading;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Http;

using CMS.Commerce;

public class PremiumMemberEligibilityValidator
    : IPromotionCustomerEligibilityValidator
{
    private readonly IPromotionCustomerEligibilityValidator baseValidator;
    private readonly IHttpContextAccessor httpContextAccessor;

    public PremiumMemberEligibilityValidator(
        IPromotionCustomerEligibilityValidator baseValidator,
        IHttpContextAccessor httpContextAccessor)
    {
        // The base validator instance decorated with premium eligibility checks
        this.baseValidator = baseValidator;
        this.httpContextAccessor = httpContextAccessor;
    }

    public async Task<PromotionCustomerEligibilityValidationResult> Validate(
        PromotionCustomerEligibility eligibility,
        BuyerIdentifier buyerIdentifier,
        CancellationToken cancellationToken)
    {
        // Handles the custom "premium-members" eligibility value
        if (eligibility == PremiumMemberEligibilityOptionsProvider.PremiumMembersOnly)
        {
            bool isPremium = CheckPremiumRole();

            return new PromotionCustomerEligibilityValidationResult
            {
                IsEligible = isPremium
            };
        }

        // Delegates to the default validator for built-in values
        return await baseValidator.Validate(
            eligibility, buyerIdentifier, cancellationToken);
    }

    private bool CheckPremiumRole()
    {
        System.Security.Claims.ClaimsPrincipal? user =
            httpContextAccessor.HttpContext?.User;

        if (user?.Identity?.IsAuthenticated != true)
        {
            return false;
        }

        // Checks if the current member has the "codesamples.premium" role
        return user.IsInRole("codesamples.premium");
    }
}
```

Register the validator as a decorator of the `IPromotionCustomerEligibilityValidator` type:

```csharp title="Program.cs"
using CMS;

using CMS.Commerce;

// Registers the custom validator as a decorator in the DI container
[assembly: RegisterImplementation(
    implementedType: typeof(IPromotionCustomerEligibilityValidator),
    implementation: typeof(PremiumMemberEligibilityValidator))]
```

## Result

The admin UI now shows the custom eligibility option for premium members.

![Customer eligibility configuration](https://docs.kentico.com/docsassets/documentation/customer-eligibility-customization/customer_eligibility.png "Customer eligibility configuration")

For a promotion to apply, it must pass this general eligibility check and the check in its corresponding [IsApplicable implementation](https://docs.kentico.com/documentation/developers-and-admins/digital-commerce-setup/promotions/catalog-discounts.md#filter-promotion-applicability).
