---
title: Handle content events
related:
  - https://docs.kentico.com/documentation/developers-and-admins/customization/handle-global-events/reference-global-system-events.md
  - https://docs.kentico.com/documentation/developers-and-admins/customization/handle-global-events.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).

Content events allow you to execute custom code when actions occur during the lifecycle of [content items](https://docs.kentico.com/documentation/business-users/content-hub/content-items.md), [website channel pages](https://docs.kentico.com/documentation/business-users/website-content.md), and [headless items](https://docs.kentico.com/documentation/business-users/headless-content.md). These events are triggered when content is created, updated, published, unpublished, deleted, or moved.

## Content event handlers with async support

To handle a content event, create a class implementing the `IAsyncEventHandler<TAsyncEvent>` interface (from the `CMS.Base` namespace), where `TAsyncEvent` is one of the available [content event classes](#content-event-classes).

Define the `HandleAsync` method in the handler class:

```csharp title="Content event handling"
using System.Threading;
using System.Threading.Tasks;

using CMS.Base;
using CMS.ContentEngine;

// Handler triggered after a content item is published
public class ContentItemPublishHandler : IAsyncEventHandler<AfterPublishContentItemEvent>
{
    public async Task HandleAsync(AfterPublishContentItemEvent asyncEvent, CancellationToken cancellationToken)
    {
        // Accesses the strongly-typed event data
        PublishContentItemEventData data = asyncEvent.Data;

        string contentType = data.ContentTypeName;
        int contentItemId = data.ID;

        // Implement custom logic, e.g., notify an external system
    }
}
```

The `HandleAsync` method receives the content event object as a parameter. Access the object's `Data` property to get a strongly-typed data object with properties specific to the event action.

Content events fall into two categories – compound and after-only.

### Compound before/after events

Most content events come in **Before** and **After** pairs:

- **Before** handlers execute before the operation. You can modify mutable properties (marked with a `set` accessor) of the `Data` object to influence the operation.
- **After** handlers execute after the operation completes. Properties that are only available after the operation (such as `ID` and `Guid` of newly created items) are populated in the `Data` object at this stage.

Both the Before and After handlers of a compound event pair share the same `Data` object instance, as well as a `State` property for passing custom state. See [Pass state between before and after events](#pass-state-between-before-and-after-events).

### After-only events

Some content events are standalone, with no Before counterpart to the After handler. These represent irreversible or notification-only operations such as publish, unpublish, delete, and move.

After-only events do not have a `State` property because there is no Before handler to set state values.

## Register content event handlers

Register content event handlers using the `AddEventHandler<TAsyncEvent, THandler>()` extension method on [IServiceCollection](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.iservicecollection). You can create a [custom module with initialization code](https://docs.kentico.com/documentation/developers-and-admins/customization/run-code-on-application-startup.md) and access `IServiceCollection` in the `OnPreInit` override.

```csharp title="Register a content event handler"
using CMS;
using CMS.Base;
using CMS.ContentEngine;
using CMS.Core;
using CMS.DataEngine;

[assembly: RegisterModule(typeof(ContentEventModule))]

public class ContentEventModule : Module
{
    public ContentEventModule() : base(nameof(ContentEventModule))
    {
    }

    protected override void OnPreInit(ModulePreInitParameters parameters)
    {
        base.OnPreInit(parameters);

        // Registers a handler for the AfterPublishContentItemEvent
        parameters.Services.AddEventHandler<AfterPublishContentItemEvent, ContentItemPublishHandler>();
    }
}
```

Handlers registered via `AddEventHandler` are added to the dependency injection container as singletons. You can use standard constructor dependency injection to resolve services within your handler classes.

## Pass state between before and after events

For [compound before/after events](#compound-beforeafter-events), you can pass custom state from a Before handler to an After handler using the `State` property of the event object. The `State` property is an `EventStateStore` that provides a key-value store with the following methods:

- `SetValue<TValue>` – stores a value in the Before handler
- `TryGetValue<TValue>` – retrieves the value in the After handler

```csharp title="Set state in a Before handler"
// Handler triggered before a content item's language-specific metadata is updated
public class ContentItemBeforeUpdateLanguageMetadataHandler :
    IAsyncEventHandler<BeforeUpdateContentItemLanguageMetadataEvent>
{
    public async Task HandleAsync(BeforeUpdateContentItemLanguageMetadataEvent asyncEvent, CancellationToken cancellationToken)
    {
        // Stores the original display name before the content item update,
        // under the "CustomHandler.OriginalDisplayName" key
        asyncEvent.State.SetValue<string>("CustomHandler.OriginalDisplayName",
                                          asyncEvent.Data.OriginalDisplayName);
    }
}
```

```csharp title="Get state in an After handler"
// Handler triggered after a content item's language-specific metadata is updated
public class ContentItemAfterUpdateLanguageMetadataHandler :
    IAsyncEventHandler<AfterUpdateContentItemLanguageMetadataEvent>
{
    public async Task HandleAsync(AfterUpdateContentItemLanguageMetadataEvent asyncEvent, CancellationToken cancellationToken)
    {
        // Retrieves the state value stored in the Before handler
        if (asyncEvent.State.TryGetValue<string>("CustomHandler.OriginalDisplayName",
                                                 out string originalDisplayName))
        {
            // Gets the current display name after the update operation
            string currentDisplayName = asyncEvent.Data.DisplayName;

            // Compares the old and new display names
            if (!string.Equals(originalDisplayName, currentDisplayName))
            {
                // Custom logic if the display name was changed
            }
        }
    }
}
```

> **Note:** **Use unique State keys**
>
> State key values are shared across all handlers registered for a given event class. Use namespaced keys (e.g., `"CustomHandler.PropertyName"`) to avoid collisions between different handlers.

## Content event classes

### Content item events

The following events from the `CMS.ContentEngine` namespace cover [reusable content items](https://docs.kentico.com/documentation/business-users/content-hub/content-items.md):

| Action                   | Event classes                                                                                                                                                    | Description                                                                                                                                                                                                                                                                                                          |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Create                   | `BeforeCreateContentItemEvent`&#xA;`AfterCreateContentItemEvent`<br>Data class:&#xA;`CreateContentItemEventData`                                                 | Occurs when a content item is created. `ID` and `Guid` are only populated in the After event.                                                                                                                                                                                                                        |
| Create language variant  | `BeforeCreateLanguageVariantEvent`&#xA;`AfterCreateLanguageVariantEvent`<br>Data class:&#xA;`CreateLanguageVariantEventData`                                     | Occurs when a new language variant of a content item is created.                                                                                                                                                                                                                                                     |
| Update draft             | `BeforeUpdateDraftEvent`&#xA;`AfterUpdateDraftEvent`<br>Data class:&#xA;`UpdateDraftEventData`                                                                   | Occurs when a content item draft is updated.                                                                                                                                                                                                                                                                         |
| Update metadata          | `BeforeUpdateContentItemMetadataEvent`&#xA;`AfterUpdateContentItemMetadataEvent`<br>Data class:&#xA;`UpdateContentItemMetadataEventData`                         | Occurs when content item metadata (e.g., the code name or security settings) is updated.                                                                                                                                                                                                                             |
| Update language metadata | `BeforeUpdateContentItemLanguageMetadataEvent`&#xA;`AfterUpdateContentItemLanguageMetadataEvent`<br>Data class:&#xA;`UpdateContentItemLanguageMetadataEventData` | Occurs when language-specific metadata (e.g., display name, publish/unpublish [scheduling](https://docs.kentico.com/documentation/business-users/content-hub/content-items.md#scheduled-publishing), or [content lock status](https://docs.kentico.com/documentation/business-users/content-locking.md)) is updated. |
| Publish                  | `AfterPublishContentItemEvent`<br>Data class:&#xA;`PublishContentItemEventData`                                                                                  | Occurs after a content item is published. After-only event.                                                                                                                                                                                                                                                          |
| Unpublish                | `AfterUnpublishContentItemEvent`<br>Data class:&#xA;`UnpublishContentItemEventData`                                                                              | Occurs after a content item is unpublished. After-only event.                                                                                                                                                                                                                                                        |
| Delete                   | `AfterDeleteContentItemEvent`<br>Data class:&#xA;`DeleteContentItemEventData`                                                                                    | Occurs after a content item is deleted. After-only event.                                                                                                                                                                                                                                                            |

### Page events

The following events from the `CMS.Websites` namespace cover [website channel pages](https://docs.kentico.com/documentation/business-users/website-content.md):

| Action                         | Event classes                                                                                                                                        | Description                                                                                                                                                                                                                                                                                                                                 |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Create                         | `BeforeCreateWebPageEvent`&#xA;`AfterCreateWebPageEvent`<br>Data class:&#xA;`CreateWebPageEventData`                                                 | Occurs when a page is created. `ID`, `Guid`, and `TreePath` are only populated in the After event.                                                                                                                                                                                                                                          |
| Create language variant        | `BeforeCreateWebPageLanguageVariantEvent`&#xA;`AfterCreateWebPageLanguageVariantEvent`<br>Data class:&#xA;`CreateWebPageLanguageVariantEventData`    | Occurs when a new language variant of a page is created.                                                                                                                                                                                                                                                                                    |
| Create folder                  | `BeforeCreateFolderEvent`&#xA;`AfterCreateFolderEvent`<br>Data class:&#xA;`CreateFolderEventData`                                                    | Occurs when a folder is created in the page tree. `ID`, `Guid`, and `TreePath` are only populated in the After event.                                                                                                                                                                                                                       |
| Create folder language variant | `BeforeCreateFolderLanguageVariantEvent`&#xA;`AfterCreateFolderLanguageVariantEvent`<br>Data class:&#xA;`CreateFolderLanguageVariantEventData`       | Occurs when a new language variant of a folder is created.                                                                                                                                                                                                                                                                                  |
| Update draft                   | `BeforeUpdateWebPageDraftEvent`&#xA;`AfterUpdateWebPageDraftEvent`<br>Data class:&#xA;`UpdateWebPageDraftEventData`                                  | Occurs when a page draft is updated.                                                                                                                                                                                                                                                                                                        |
| Update metadata                | `BeforeUpdateWebPageMetadataEvent`&#xA;`AfterUpdateWebPageMetadataEvent`<br>Data class:&#xA;`UpdateWebPageMetadataEventData`                         | Occurs when page metadata (e.g., the code name or security settings) is updated.                                                                                                                                                                                                                                                            |
| Update language metadata       | `BeforeUpdateWebPageLanguageMetadataEvent`&#xA;`AfterUpdateWebPageLanguageMetadataEvent`<br>Data class:&#xA;`UpdateWebPageLanguageMetadataEventData` | Occurs when language-specific metadata of a page (e.g., display name, publish/unpublish [scheduling](https://docs.kentico.com/documentation/business-users/website-content/edit-and-publish-pages.md#scheduled-publishing), or [content lock status](https://docs.kentico.com/documentation/business-users/content-locking.md)) is updated. |
| Update tree path slug          | `BeforeUpdateWebPageTreePathSlugEvent`&#xA;`AfterUpdateWebPageTreePathSlugEvent`<br>Data class:&#xA;`UpdateWebPageTreePathSlugEventData`             | Occurs when a page's URL path slug is updated.                                                                                                                                                                                                                                                                                              |
| Update security settings       | `BeforeUpdateWebPageSecuritySettingsEvent`&#xA;`AfterUpdateWebPageSecuritySettingsEvent`<br>Data class:&#xA;`UpdateWebPageSecuritySettingsEventData` | Occurs when a page's security settings are updated.                                                                                                                                                                                                                                                                                         |
| Publish                        | `AfterPublishWebPageEvent`<br>Data class:&#xA;`PublishWebPageEventData`                                                                              | Occurs after a page is published. After-only event.                                                                                                                                                                                                                                                                                         |
| Unpublish                      | `AfterUnpublishWebPageEvent`<br>Data class:&#xA;`UnpublishWebPageEventData`                                                                          | Occurs after a page is unpublished. After-only event.                                                                                                                                                                                                                                                                                       |
| Move                           | `AfterMoveWebPageEvent`<br>Data class:&#xA;`MoveWebPageEventData`                                                                                    | Occurs after a page is moved in the content tree. After-only event.                                                                                                                                                                                                                                                                         |
| Delete                         | `AfterDeleteWebPageEvent`<br>Data class:&#xA;`DeleteWebPageEventData`                                                                                | Occurs after a page is deleted. After-only event.                                                                                                                                                                                                                                                                                           |

### Headless item events

The following events from the `CMS.Headless` namespace cover [headless items](https://docs.kentico.com/documentation/business-users/headless-content.md):

| Action                   | Event classes                                                                                                                                                       | Description                                                                                                                                                                                   |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Create                   | `BeforeCreateHeadlessItemEvent`&#xA;`AfterCreateHeadlessItemEvent`<br>Data class:&#xA;`CreateHeadlessItemEventData`                                                 | Occurs when a headless item is created. `ID` and `Guid` are only populated in the After event.                                                                                                |
| Create language variant  | `BeforeCreateHeadlessItemLanguageVariantEvent`&#xA;`AfterCreateHeadlessItemLanguageVariantEvent`<br>Data class:&#xA;`CreateHeadlessItemLanguageVariantEventData`    | Occurs when a new language variant of a headless item is created.                                                                                                                             |
| Update draft             | `BeforeUpdateHeadlessItemDraftEvent`&#xA;`AfterUpdateHeadlessItemDraftEvent`<br>Data class:&#xA;`UpdateHeadlessItemDraftEventData`                                  | Occurs when a headless item draft is updated.                                                                                                                                                 |
| Update metadata          | `BeforeUpdateHeadlessItemMetadataEvent`&#xA;`AfterUpdateHeadlessItemMetadataEvent`<br>Data class:&#xA;`UpdateHeadlessItemMetadataEventData`                         | Occurs when headless item metadata is updated (e.g., security settings).                                                                                                                      |
| Update language metadata | `BeforeUpdateHeadlessItemLanguageMetadataEvent`&#xA;`AfterUpdateHeadlessItemLanguageMetadataEvent`<br>Data class:&#xA;`UpdateHeadlessItemLanguageMetadataEventData` | Occurs when language-specific metadata of a headless item (e.g., display name or [content lock status](https://docs.kentico.com/documentation/business-users/content-locking.md)) is updated. |
| Publish                  | `AfterPublishHeadlessItemEvent`<br>Data class:&#xA;`PublishHeadlessItemEventData`                                                                                   | Occurs after a headless item is published. After-only event.                                                                                                                                  |
| Unpublish                | `AfterUnpublishHeadlessItemEvent`<br>Data class:&#xA;`UnpublishHeadlessItemEventData`                                                                               | Occurs after a headless item is unpublished. After-only event.                                                                                                                                |
| Delete                   | `AfterDeleteHeadlessItemEvent`<br>Data class:&#xA;`DeleteHeadlessItemEventData`                                                                                     | Occurs after a headless item is deleted. After-only event.                                                                                                                                    |

## Example – CDN cache invalidation on publish

The following example demonstrates a content event handler that invalidates a CDN cache when an article page is published on a website channel.

1. Open your Xperience solution in your preferred IDE.

2. Create a handler class [within a custom assembly](https://docs.kentico.com/documentation/developers-and-admins/customization/integrate-custom-code.md) (_Class Library_ project) referenced by your project:

   ```csharp
   using System;
   using System.Net.Http;
   using System.Threading;
   using System.Threading.Tasks;

   using CMS.Base;
   using CMS.Websites;

   // Handler triggered after a website channel page is published
   public class ArticlePublishCdnHandler : IAsyncEventHandler<AfterPublishWebPageEvent>
   {
       private readonly IHttpClientFactory httpClientFactory;

       public ArticlePublishCdnHandler(IHttpClientFactory httpClientFactory)
       {
           this.httpClientFactory = httpClientFactory;
       }

       public async Task HandleAsync(AfterPublishWebPageEvent asyncEvent, CancellationToken cancellationToken)
       {
           PublishWebPageEventData data = asyncEvent.Data;

           // Only handles pages of the 'Acme.ArticlePage' content type
           if (!string.Equals(data.ContentTypeName, "Acme.ArticlePage", StringComparison.OrdinalIgnoreCase))
           {
               return;
           }

           // Gets the page's tree path and website channel to build the invalidation request
           string treePath = data.TreePath;
           string channelName = data.WebsiteChannelName;

           HttpClient httpClient = httpClientFactory.CreateClient("CdnApi");

           // Sends a cache invalidation request to the CDN
           await httpClient.PostAsJsonAsync(
               "api/cache/invalidate",
               new { Path = treePath, Channel = channelName },
               cancellationToken);
       }
   }
   ```

3. Create a [module class](https://docs.kentico.com/documentation/developers-and-admins/customization/run-code-on-application-startup.md) and [register](#register-content-event-handlers) the handler in the `OnPreInit` override:

   ```csharp
   using CMS;
   using CMS.Base;
   using CMS.Core;
   using CMS.DataEngine;
   using CMS.Websites;

   [assembly: RegisterModule(typeof(CdnInvalidationModule))]

   public class CdnInvalidationModule : Module
   {
       public CdnInvalidationModule() : base(nameof(CdnInvalidationModule))
       {
       }

       // OnPreInit allows you to access IServiceCollection via ModulePreInitParameters
       protected override void OnPreInit(ModulePreInitParameters parameters)
       {
           base.OnPreInit(parameters);

           // Registers the event handler
           parameters.Services.AddEventHandler<AfterPublishWebPageEvent, ArticlePublishCdnHandler>();
       }
   }
   ```

When an article page is published, the handler sends a cache invalidation request to an external CDN API.

## Legacy content event handlers

We strongly recommend using handlers with async support for content events. The event handling approach described on this page provides the following advantages:

- Full async/await support without thread-blocking risk
- Standard constructor dependency injection
- Singleton lifecycle managed by the DI container

However, the system maintains full backward compatibility for legacy synchronous handlers using the `ContentItemEvents`, `WebPageEvents`, and `HeadlessItemEvents` static classes.

See [Reference - Global system events](https://docs.kentico.com/documentation/developers-and-admins/customization/handle-global-events/reference-global-system-events.md) for detailed information.
