From 449178bb80634f0216710b175e1a8d430be291a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corn=C3=A9=20Hoskam?= Date: Fri, 28 Nov 2025 10:52:39 +0100 Subject: [PATCH 1/5] Update Engage Documentation for v17 --- .../developers/ab-testing/csharp-api.md | 86 ++++--------------- .../getting-the-correct-ip-address.md | 30 +++---- .../developers/analytics/location.md | 40 +++++---- .../developers/headless/README.md | 6 +- .../module-permissions.md | 22 ++--- .../personalization/custom-scoring.md | 37 +++++--- .../implement-your-own-segment-parameters.md | 2 +- .../personalization/segment-information.md | 19 ++-- .../developers/settings/configuration.md | 15 +++- .../for-developers/system-requirements.md | 5 +- .../personalization/cockpit-insights.md | 4 +- 11 files changed, 120 insertions(+), 146 deletions(-) diff --git a/17/umbraco-engage/developers/ab-testing/csharp-api.md b/17/umbraco-engage/developers/ab-testing/csharp-api.md index 5a3ae2b915f..6a85e9eb632 100644 --- a/17/umbraco-engage/developers/ab-testing/csharp-api.md +++ b/17/umbraco-engage/developers/ab-testing/csharp-api.md @@ -10,75 +10,14 @@ description: >- You can retrieve the active A/B test variants for a visitor in different ways depending on your specific scenario: -* `IAbTestingVisitorService.GetVisitorAbTestVariants(visitorExternalId, pageId, culture, contentTypeId)` +* `IAbTestingVisitorService.GetVisitorAbTestVariants(visitorExternalId, contentId, culture, contentTypeId)` * Namespace: `Umbraco.Engage.Infrastructure.AbTesting.Services.Interfaces` - * Retrieves active A/B test variants on a specific page, without requiring a request context. + * Retrieves active A/B test variants on a specific page using numeric IDs, without requiring a request context. * The visitor external id can be retrieved using `IAnalyticsVisitorExternalIdHandler.GetExternalId()` -* `IAbTestVisitorToVariantManager.GetActiveVisitorVariants(visitorExternalId)` - * Namespace: `Umbraco.Engage.Infrastructure.AbTesting` - * Retrieves _all_ active A/B test variants for the given visitor throughout the website. - * The visitor external id can be retrieved using `IAnalyticsVisitorExternalIdHandler.GetExternalId()` - -### Example - Getting the A/B test variants for the current visitor - -This example demonstrates how to create a service that retrieves the active A/B test variants for a specific visitor, content, and culture variation. The service wraps the `IAbTestingVisitorService.GetVisitorAbTestVariants()` method, using the current HttpContext and UmbracoContext to obtain the visitor ID and requested content. - -```cs -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Web; -using Umbraco.Engage.Infrastructure.AbTesting.Models; -using Umbraco.Engage.Infrastructure.AbTesting.Services.Interfaces; -using Umbraco.Engage.Infrastructure.Analytics.Collection.Visitor; - -namespace Umbraco.Example; - -public class ExampleService -{ - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IAnalyticsVisitorExternalIdHandler _externalIdHandler; - private readonly IAbTestingVisitorService _abTestingVisitorService; - - public ExampleService( - IHttpContextAccessor httpContextAccessor, - IUmbracoContextAccessor umbracoContextAccessor, - IAnalyticsVisitorExternalIdHandler externalIdHandler, - IAbTestingVisitorService abTestingVisitorService) - { - _httpContextAccessor = httpContextAccessor; - _umbracoContextAccessor = umbracoContextAccessor; - _externalIdHandler = externalIdHandler ; - _abTestingVisitorService = abTestingVisitorService; - } - - /// - /// Gets the active A/B test variants for the current visitor. - /// - /// Active s for the visitor, or an empty list if unavailable. - public IEnumerable GetCurrentVisitorActiveAbTestVariants() - { - if (_httpContextAccessor?.HttpContext is not HttpContext httpCtx || - _externalIdHandler.GetExternalId(httpCtx) is not Guid externalId) - return []; - - if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbCtx) || - umbCtx.PublishedRequest?.Culture is not string culture || - umbCtx.PublishedRequest?.PublishedContent is not IPublishedContent content) - return []; - - return _abTestingVisitorService.GetVisitorAbTestVariants(externalId, content.Id, culture, content.ContentType.Id); - } -} -``` - -## Retrieving Active A/B test variants - -You can retrieve the active A/B test variants for a visitor in different ways depending on your specific scenario: - -* `IAbTestingVisitorService.GetVisitorAbTestVariants(visitorExternalId, pageId, culture, contentTypeId)` +* `IAbTestingVisitorService.GetVisitorAbTestVariants(visitorExternalId, contentKey, contentTypeKey, culture)` * Namespace: `Umbraco.Engage.Infrastructure.AbTesting.Services.Interfaces` - * Retrieves active A/B test variants on a specific page, without requiring a request context. - * The visitor external id can be retrieved using `IAnalyticsVisitorExternalIdHandler.GetExternalId()` + * Retrieves active A/B test variants on a specific page using GUID keys, without requiring a request context. + * Preferred for new implementations as it uses Umbraco's GUID-based identifiers. * `IAbTestVisitorToVariantManager.GetActiveVisitorVariants(visitorExternalId)` * Namespace: `Umbraco.Engage.Infrastructure.AbTesting` * Retrieves _all_ active A/B test variants for the given visitor throughout the website. @@ -117,7 +56,7 @@ public class ExampleService } /// - /// Gets the active A/B test variants for the current visitor. + /// Gets the active A/B test variants for the current visitor using GUID keys (recommended). /// /// Active s for the visitor, or an empty list if unavailable. public IEnumerable GetCurrentVisitorActiveAbTestVariants() @@ -125,13 +64,18 @@ public class ExampleService if (_httpContextAccessor?.HttpContext is not HttpContext httpCtx || _externalIdHandler.GetExternalId(httpCtx) is not Guid externalId) return []; - - if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbCtx) || - umbCtx.PublishedRequest?.Culture is not string culture || + + if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbCtx) || + umbCtx.PublishedRequest?.Culture is not string culture || umbCtx.PublishedRequest?.PublishedContent is not IPublishedContent content) return []; - return _abTestingVisitorService.GetVisitorAbTestVariants(externalId, content.Id, culture, content.ContentType.Id); + // Using GUID-based overload (recommended) + return _abTestingVisitorService.GetVisitorAbTestVariants( + externalId, + content.Key, + content.ContentType.Key, + culture); } } ``` diff --git a/17/umbraco-engage/developers/analytics/extending-analytics/getting-the-correct-ip-address.md b/17/umbraco-engage/developers/analytics/extending-analytics/getting-the-correct-ip-address.md index f03d97adccc..489ec8647e9 100644 --- a/17/umbraco-engage/developers/analytics/extending-analytics/getting-the-correct-ip-address.md +++ b/17/umbraco-engage/developers/analytics/extending-analytics/getting-the-correct-ip-address.md @@ -15,43 +15,43 @@ In this case, you may need to provide a custom implementation of the `IHttpConte The default extractor looks like this: ```csharp -using System.Web; -using Umbraco.Engage.Business.Analytics.Collection.Extractors; +using Microsoft.AspNetCore.Http; +using Umbraco.Engage.Infrastructure.Analytics.Collection.Extractors; -public string ExtractIpAddress(HttpContextBase context) +public string? ExtractIpAddress(HttpContext context) { - if (context?.Request?.ServerVariables["X-Forwarded-For"] is string ipAddresses) + if (context?.Request?.Headers["X-Forwarded-For"].FirstOrDefault() is string ipAddresses) { var ipAddress = ipAddresses.Split(',')[0].Trim(); if (System.Net.IPAddress.TryParse(ipAddress, out _)) return ipAddress; } - return context?.Request?.UserHostAddress; + return context?.Connection?.RemoteIpAddress?.ToString(); } ``` To override this behavior, implement your own `IHttpContextIpAddressExtractor` and instruct Umbraco to use your extractor instead of the default extractor: ```cs -using Umbraco.Engage.Business.Analytics.Collection.Extractors; -using Umbraco.Core.Composing; -using Umbraco.Core; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Engage.Infrastructure.Analytics.Collection.Extractors; -[ComposeAfter(typeof(Umbraco.Engage.Business.Analytics.Collection.Extractors.AnalyticsExtractorsComposer))] -public class CustomIpExtractorUserComposer : IUserComposer +[ComposeAfter(typeof(Umbraco.Engage.Infrastructure.Analytics.Collection.Extractors.AnalyticsExtractorsComposer))] +public class CustomIpExtractorComposer : IComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { - composition.RegisterUnique(); + builder.Services.AddUnique(); } } ``` {% hint style="info" %} -It is important that your `UserComposer` adjusts the service registration **after** Umbraco Engage has initialized. +It is important that your `Composer` adjusts the service registration **after** Umbraco Engage has initialized. {% endhint %} -This can be enforced using the `ComposeAfterAttribute`. Failing to add this attribute may result in Umbraco running your IUserComposer before the Umbraco Engage composer, causing your changes to be overwritten. +This can be enforced using the `ComposeAfterAttribute`. Failing to add this attribute may result in Umbraco running your Composer before the Umbraco Engage composer, causing your changes to be overwritten. -Additionally, ensure you use `RegisterUnique<...>()` instead of `Register<...>()`. While you can use Register when multiple implementations of a single service exist, in this case, you want your own extractor to be resolved exclusively. Therefore, RegisterUnique will overwrite the Umbraco Engage extractor. +Additionally, ensure you use `AddUnique<...>()` instead of `AddSingleton<...>()`. While you can use AddSingleton when multiple implementations of a single service exist, in this case, you want your own extractor to be resolved exclusively. Therefore, AddUnique will overwrite the Umbraco Engage extractor. After implementing both classes and running your project, your extractor should be called to resolve IP addresses. You can verify the output of your extractor by inspecting the `umbracoEngageAnalyticsIpAddress` database table. The last portion of the IP address may be anonymized (set to 0) if this option is enabled in the Umbraco Engage configuration file. diff --git a/17/umbraco-engage/developers/analytics/location.md b/17/umbraco-engage/developers/analytics/location.md index 27ae66b24d1..2a21fe21d33 100644 --- a/17/umbraco-engage/developers/analytics/location.md +++ b/17/umbraco-engage/developers/analytics/location.md @@ -16,7 +16,7 @@ Once you have a service that can provide localization information, you must inte Implement the following interface: -`Umbraco.Engage.Business.Analytics.Processing.Extractors.IRawPageviewLocationExtractor` +`Umbraco.Engage.Infrastructure.Analytics.Processing.Extractors.IRawPageviewLocationExtractor` This interface allows information about localization for a pageview, defined as a single visitor's visit to a specific point in time. The page view contains the `IpAddress` property that can be used for Geo IP lookup. @@ -25,8 +25,10 @@ This interface allows information about localization for a pageview, defined as {% code overflow="wrap" %} ```cs -using Umbraco.Engage.Business.Analytics.Processed; -public class GeoIpLocation : ILocation { +using Umbraco.Engage.Infrastructure.Analytics.Processed; + +public class GeoIpLocation : ILocation +{ public string Country { get; set; } public string County { get; set; } public string Province { get; set; } @@ -40,19 +42,21 @@ public class GeoIpLocation : ILocation { {% code overflow="wrap" %} ```cs -using Umbraco.Engage.Business.Analytics.Processing.Extractors; +using Umbraco.Engage.Infrastructure.Analytics.Processing.Extractors; + public class MyCustomLocationExtractor : IRawPageviewLocationExtractor { - public ILocation Extract(IRawPageview rawPageview) + public ILocation? Extract(IRawPageview rawPageview) { - if (!IPAddress.TryParse(rawPageview?.IpAddress, out var ipAddress) || IPAddress.IsLoopback(ipAddress)) return null; - + if (!IPAddress.TryParse(rawPageview?.IpAddress, out var ipAddress) || IPAddress.IsLoopback(ipAddress)) + return null; + string country, county, province, city; - + //... // Perform your own GEO IP lookup here // ... - + var location = new GeoIpLocation { Country = country, @@ -60,7 +64,7 @@ public class MyCustomLocationExtractor : IRawPageviewLocationExtractor Province = province, City = city }; - + return location; } } @@ -69,23 +73,23 @@ public class MyCustomLocationExtractor : IRawPageviewLocationExtractor 4. Let the IoC container know to use your implementation for the `IRawPageviewLocationExtractor`. -Umbraco Engage has a default implementation of this service, which only returns null. This default service is registered using Umbraco's `RegisterUnique` method. +Umbraco Engage has a default implementation of this service, which only returns null. This default service is registered using Umbraco's `AddUnique` method. -5. Override this service by calling `RegisterUnique` **after** the `UmbracoEngageApplicationComposer`. +5. Override this service by calling `AddUnique` **after** the `UmbracoEngageApplicationComposer`. {% code overflow="wrap" %} ```cs -using Umbraco.Engage.Business.Analytics.Processing.Extractors; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Engage.Common.Composing; -using Umbraco.Core; -using Umbraco.Core.Composing; - +using Umbraco.Engage.Infrastructure.Analytics.Processing.Extractors; + [ComposeAfter(typeof(UmbracoEngageApplicationComposer))] -public class UmbracoEngageComposer: IComposer +public class UmbracoEngageComposer : IComposer { public void Compose(IUmbracoBuilder builder) { - builder.services.AddUnique(); + builder.Services.AddUnique(); } } ``` diff --git a/17/umbraco-engage/developers/headless/README.md b/17/umbraco-engage/developers/headless/README.md index e7a0bbf9335..8d3c5242a13 100644 --- a/17/umbraco-engage/developers/headless/README.md +++ b/17/umbraco-engage/developers/headless/README.md @@ -1,12 +1,12 @@ --- description: >- - Discover how to integrate Umbraco.Engage.Headless package with Umbraco 12.0+ + Discover how to integrate Umbraco.Engage.Headless package with Umbraco 17 for a Content Delivery API. --- # Headless -Umbraco Engage offers the **Umbraco.Engage.Headless** package for seamless integration with Umbraco 12.0 and later. This package enables access to the Headless Content Delivery API, enabling personalized content, A/B tests, and segmentation. +Umbraco Engage offers the **Umbraco.Engage.Headless** package for seamless integration with Umbraco 17. This package enables access to the Headless Content Delivery API, enabling personalized content, A/B tests, and segmentation. {% hint style="info" %} All Engage features are supported except: @@ -28,7 +28,7 @@ All Engage features are supported except: To install Umbraco.Engage.Headless, ensure the following prerequisites: -* Umbraco v13 is required to integrate with the [Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api). +* Umbraco v17 is required to integrate with the [Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api). * Enable the [Umbraco Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api#enable-the-content-delivery-api) by adding the following configuration setting in the `appsettings.json` file: ```json diff --git a/17/umbraco-engage/developers/introduction/the-umbraco-engage-cookie/module-permissions.md b/17/umbraco-engage/developers/introduction/the-umbraco-engage-cookie/module-permissions.md index 331cadf18fb..f36bd82edac 100644 --- a/17/umbraco-engage/developers/introduction/the-umbraco-engage-cookie/module-permissions.md +++ b/17/umbraco-engage/developers/introduction/the-umbraco-engage-cookie/module-permissions.md @@ -8,7 +8,7 @@ description: >- You could choose to give visitors control over these settings through a cookie bar on your site. -To do this you have to create an implementation of the `Umbraco.Engage.Business.Permissions.ModulePermissions.IModulePermissions` interface and override our default implementation. +To do this you have to create an implementation of the `Umbraco.Engage.Infrastructure.Permissions.ModulePermissions.IModulePermissions` interface and override our default implementation. This interface defines 3 methods that you will have to implement: @@ -21,7 +21,7 @@ This interface defines 3 methods that you will have to implement: /// /// Context of the request /// True if A/B testing is allowed, otherwise false. -bool AbTestingIsAllowed(HttpContextBase context); +bool AbTestingIsAllowed(HttpContext context); /// /// Indicates if Analytics is allowed for the given request context. @@ -33,7 +33,7 @@ bool AbTestingIsAllowed(HttpContextBase context); /// /// Context of the request /// True if Analytics is allowed, otherwise false. -bool AnalyticsIsAllowed(HttpContextBase context); +bool AnalyticsIsAllowed(HttpContext context); /// /// Indicates if Personalization testing is allowed for the given request context. @@ -41,29 +41,29 @@ bool AnalyticsIsAllowed(HttpContextBase context); /// /// Context of the request /// True if Personalization is allowed, otherwise false. -bool PersonalizationIsAllowed(HttpContextBase context); +bool PersonalizationIsAllowed(HttpContext context); ``` {% endcode %} -Using these methods you can control per visitor whether or not the modules are active. Your implementation will need to be registered with Umbraco using the `RegisterUnique()` method, overriding the default implementation which enables all modules all the time. Make sure your composer runs after the Umbraco Engage composer by using the `[ComposeAfter]` attribute. +Using these methods you can control per visitor whether or not the modules are active. Your implementation will need to be registered with Umbraco using the `AddUnique()` method, overriding the default implementation which enables all modules all the time. Make sure your composer runs after the Umbraco Engage composer by using the `[ComposeAfter]` attribute. It could look something like this: {% code overflow="wrap" %} ```csharp -using Umbraco.Engage.Infrastructure.Permissions.ModulePermissions; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Engage.Common.Composing; -using Umbraco.Core; -using Umbraco.Core.Composing; +using Umbraco.Engage.Infrastructure.Permissions.ModulePermissions; -namespace YourNamespace +namespace YourNamespace { [ComposeAfter(typeof(UmbracoEngageApplicationComposer))] public class YourComposer : IComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { - composition.RegisterUnique(); + builder.Services.AddUnique(); } } } diff --git a/17/umbraco-engage/developers/personalization/custom-scoring.md b/17/umbraco-engage/developers/personalization/custom-scoring.md index 53df238009b..0b61ec59d75 100644 --- a/17/umbraco-engage/developers/personalization/custom-scoring.md +++ b/17/umbraco-engage/developers/personalization/custom-scoring.md @@ -58,20 +58,31 @@ Since the user is no longer (shifting away) from that step of the Customer Journ Another, more advanced, example could be on how to reset the score of a persona for a given visitor. We can use the same approach as above to fetch the **persona** instead of the Customer Journey for the current visitor. We can get the visitor's current score based on the Persona ID, and subtract that exact score from said visitor. +{% hint style="info" %} +When scoring outside of a regular HttpContext request (e.g., in background jobs or external integrations), you must use the overload that includes `PersonalizationScoreType`. The `PersonalizationScoreType` enum specifies whether the score is `Implicit` (behavior-based) or `Explicit` (direct assignment). +{% endhint %} + ```csharp -public IActionResult ResetPersonaScoreToZero(long personaId) { - var visitorId = _visitorContext.GetVisitorExternalId(); - - if (visitorId.HasValue) { - var personaGroups = _personaGroupRepository.GetPersonaScoresByVisitor(visitorId.Value); - var personaGroup = personaGroups.FirstOrDefault(x => x.Personas.Any(y => y.Id == personaId)); - var persona = personaGroup?.Personas.FirstOrDefault(x => x.Id == personaId); - if (persona != null) { - _personaService.ScorePersona(visitorId.Value, personaId, persona.Score * -1); - return Ok($"Subtracted {persona.Score} from visitor {visitorId}"); +public IActionResult ResetPersonaScoreToZero(long personaId) +{ + var visitorId = _visitorContext.GetVisitorExternalId(); + + if (visitorId.HasValue) + { + var personaGroups = _personaGroupRepository.GetPersonaScoresByVisitor(visitorId.Value); + var personaGroup = personaGroups.FirstOrDefault(x => x.Personas.Any(y => y.Id == personaId)); + var persona = personaGroup?.Personas.FirstOrDefault(x => x.Id == personaId); + if (persona != null) + { + _personaService.ScorePersona(visitorId.Value, personaId, persona.Score * -1, PersonalizationScoreType.Explicit); + return Ok($"Subtracted {persona.Score} from visitor {visitorId}"); + } } - } - - return Ok("OK"); + + return Ok("OK"); } ``` + +{% hint style="info" %} +The simpler overloads `ScorePersona(long personaId, int score)` and `ScoreCustomerJourneyStep(long customerJourneyStepId, int score)` should only be used within the context of a regular HttpContext request, as they automatically resolve the current visitor. +{% endhint %} diff --git a/17/umbraco-engage/developers/personalization/implement-your-own-segment-parameters.md b/17/umbraco-engage/developers/personalization/implement-your-own-segment-parameters.md index 5225839addb..c5f9cbb5340 100644 --- a/17/umbraco-engage/developers/personalization/implement-your-own-segment-parameters.md +++ b/17/umbraco-engage/developers/personalization/implement-your-own-segment-parameters.md @@ -94,7 +94,7 @@ First, follow the [Vite Package Setup](/umbraco-cms/customizing/development-flow 1. Install `@umbraco-engage/backoffice` package, replacing `x.x.x` with your Engage version: ```text -npm install @umbaco-engage/backoffice@x.x.x +npm install @umbraco-engage/backoffice@x.x.x ``` 2. Ensure your `vite.config.ts` looks like the example below: diff --git a/17/umbraco-engage/developers/personalization/segment-information.md b/17/umbraco-engage/developers/personalization/segment-information.md index beba827a557..7ae973585a4 100644 --- a/17/umbraco-engage/developers/personalization/segment-information.md +++ b/17/umbraco-engage/developers/personalization/segment-information.md @@ -12,14 +12,21 @@ This service provides access to all analytics-related information for the curren To get started you need an instance of an`IAnalyticsStateProvider`, which can be resolved through Dependency Injection. For example consider the following case, where we use [route hijacking](https://docs.umbraco.com/umbraco-cms/v/13.latest-lts/reference/routing/custom-controllers) to execute custom code for our content type called "`Home`": ```csharp -using System.Web.Mvc; -using Umbraco.Engage.Business.Analytics.State; -using Umbraco.Web.Mvc; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Web.Common.Controllers; +using Umbraco.Engage.Infrastructure.Analytics.State; -public class HomeController : SurfaceController, IRenderController +public class HomeController : RenderController { private readonly IAnalyticsStateProvider _analyticsStateProvider; - public HomeController(IAnalyticsStateProvider analyticsStateProvider) + + public HomeController( + ILogger logger, + ICompositeViewEngine compositeViewEngine, + IUmbracoContextAccessor umbracoContextAccessor, + IAnalyticsStateProvider analyticsStateProvider) + : base(logger, compositeViewEngine, umbracoContextAccessor) { _analyticsStateProvider = analyticsStateProvider; } @@ -35,7 +42,7 @@ Consider the following example (continued from above) where the content of conte {% code overflow="wrap" %} ```csharp -public ActionResult HomeTemplate() +public IActionResult HomeTemplate() { var analyticsState = _analyticsStateProvider.GetState(); foreach (var pageviewSegment in analyticsState.Pageview.PageviewSegments) diff --git a/17/umbraco-engage/developers/settings/configuration.md b/17/umbraco-engage/developers/settings/configuration.md index e4f88f88386..7a1415d992f 100644 --- a/17/umbraco-engage/developers/settings/configuration.md +++ b/17/umbraco-engage/developers/settings/configuration.md @@ -16,12 +16,14 @@ The default configuration will look like this: "Engage": { "Settings": { "DatabaseConnectionStringName": "umbracoDbDSN", - "Enabled": true + "Enabled": true, + "UseLegacySegmentNames": false }, "Analytics": { "VisitorCookie": { "ExpirationInDays": 365, "CookieName": "umbracoEngageAnalyticsVisitorId", + "LegacyCookieName": "uMarketingSuiteAnalyticsVisitorId", "IncludeSubdomains": false }, "DataCollection": { @@ -31,7 +33,7 @@ The default configuration will look like this: "InternalSiteSearch": { "AutomaticSearchTracking": true, "SearchTermParameters": "q", - "SearchBoxParameters": "", + "SearchBoxParameters": "a,b,c", "CategoryParameters": "" } }, @@ -72,13 +74,18 @@ The default configuration will look like this: }, "Identification": { "Name": "{{name}}", - "Abbreviation": "{{name[0]}}", - "ImagePropertyAlias": "avatar" + "Abbreviation": "{{name[0]}}" } }, "Reporting": { "DataGenerationEnabled": true, "DataGenerationTime": "04:00:00" + }, + "Cockpit": { + "EnableInjection": true + }, + "Segmentation": { + "ExcludedPropertyAliases": [] } } } diff --git a/17/umbraco-engage/getting-started/for-developers/system-requirements.md b/17/umbraco-engage/getting-started/for-developers/system-requirements.md index 8ab2174a7eb..25e70a0174c 100644 --- a/17/umbraco-engage/getting-started/for-developers/system-requirements.md +++ b/17/umbraco-engage/getting-started/for-developers/system-requirements.md @@ -6,12 +6,13 @@ description: Learn about the system requirements before installing Umbraco Engag Umbraco Engage has the following requirements: -* Umbraco version 16 +* Umbraco version 17 +* .NET 10.0 * SQL Server 2014+, LocalDB, or Azure SQL. * **SQL CE & SQLite are not supported.** {% hint style="info" %} -It is recommended to upgrade your Umbraco installation to the latest version of Umbraco 16. +It is recommended to upgrade your Umbraco installation to the latest version of Umbraco 17. {% endhint %} See the [Troubleshooting](../../installation/troubleshooting-installs.md) section if you need to upgrade from SQL CE to SQL Server. diff --git a/17/umbraco-engage/marketers-and-editors/personalization/cockpit-insights.md b/17/umbraco-engage/marketers-and-editors/personalization/cockpit-insights.md index ed6b1ccc574..c89909cb6e2 100644 --- a/17/umbraco-engage/marketers-and-editors/personalization/cockpit-insights.md +++ b/17/umbraco-engage/marketers-and-editors/personalization/cockpit-insights.md @@ -19,11 +19,11 @@ Clicking the Open button provides detailed information: To add the cockpit to your website: 1. Render the HTML partial provided by Umbraco Engage. -2. The partial view is located at `/Views/Partials/uMarketings/Cockpit.cshtml`. +2. The partial view is located at `/Views/Partials/Umbraco.Engage/Cockpit.cshtml`. 3. Insert the following code before the closing `` tag: ```cs - @Html.Partial("uMarketingSuite/Cockpit") + @Html.Partial("Umbraco.Engage/Cockpit") ``` The cockpit will only be rendered if the user is logged into Umbraco. From 61c9894c8e254ba42a45e6c3859d56f3dd1ea7de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corn=C3=A9=20Hoskam?= Date: Fri, 28 Nov 2025 11:01:48 +0100 Subject: [PATCH 2/5] Update SQL requirements & Code overloads --- .../personalization/custom-scoring.md | 57 +++++++++++++++++-- .../settings/custom-goals-scoring.md | 30 +++++++++- .../for-developers/infrastructure-sizing.md | 8 ++- .../for-developers/system-requirements.md | 29 +++++++++- .../troubleshooting-installations.md | 10 +++- 5 files changed, 121 insertions(+), 13 deletions(-) diff --git a/17/umbraco-engage/developers/personalization/custom-scoring.md b/17/umbraco-engage/developers/personalization/custom-scoring.md index 0b61ec59d75..ec2f0078ba5 100644 --- a/17/umbraco-engage/developers/personalization/custom-scoring.md +++ b/17/umbraco-engage/developers/personalization/custom-scoring.md @@ -14,7 +14,11 @@ This might be difficult to accomplish through the Content Scoring UI in Umbraco, To manage scoring for personas, we need to get a reference to `IPersonaService`. For the customer journey, we will need the `ICustomerJourneyService`. Both services can be found under the namespace `Umbraco.Engage.Infrastructure.Personalization.Services`. -To implement our example above, we will be using the `ICustomerJourneyService`. To modify the customer journey step scoring, we need to know the ID of the step we are trying to score. For your implementation you could hardcode the IDs (since they are unlikely to change), we can also fetch them by name through the `ICustomerJourneyGroupRepository`. +Both services support two ways to identify entities: +- **Numeric IDs** (e.g., `personaId`, `customerJourneyStepId`) - Legacy approach using database IDs +- **GUID Keys** (e.g., `personaKey`, `stepKey`) - Preferred approach using Umbraco's GUID-based identifiers + +To implement our example above, we will be using the `ICustomerJourneyService`. To modify the customer journey step scoring, we need to know the ID or Key of the step we are trying to score. For your implementation you could hardcode the IDs/Keys (since they are unlikely to change), we can also fetch them by name through the `ICustomerJourneyGroupRepository`. To resolve the required services, we will use Dependency Injection: @@ -46,23 +50,28 @@ var stepDo = customerJourneyGroup.Steps.FirstOrDefault(step => step.Title == "Do ``` {% endcode %} -We can now inspect the step **Do** variable and find its `ID`. To score the step, we provide the `ID` and the score to the `CustomerJourneyService`: +We can now inspect the step **Do** variable and find its `Id` or `Key`. To score the step, we provide either the numeric ID or GUID Key and the score to the `CustomerJourneyService`: ```csharp +// Using numeric ID (legacy approach) _customerJourneyService.ScoreCustomerJourneyStep(stepDo.Id, 100); + +// Using GUID Key (preferred approach) +_customerJourneyService.ScoreCustomerJourneyStep(stepDo.Key, 100); ``` We have now added a **score of 100** to the Customer Journey step "**Do**". It is also possible to add negative scores. In our example, we can decrease the scores for "**See**" and "**Think**". Since the user is no longer (shifting away) from that step of the Customer Journey the implementation strategy is the same for personas. -Another, more advanced, example could be on how to reset the score of a persona for a given visitor. We can use the same approach as above to fetch the **persona** instead of the Customer Journey for the current visitor. We can get the visitor's current score based on the Persona ID, and subtract that exact score from said visitor. +Another, more advanced, example could be on how to reset the score of a persona for a given visitor. We can use the same approach as above to fetch the **persona** instead of the Customer Journey for the current visitor. We can get the visitor's current score based on the Persona ID or Key, and subtract that exact score from said visitor. {% hint style="info" %} When scoring outside of a regular HttpContext request (e.g., in background jobs or external integrations), you must use the overload that includes `PersonalizationScoreType`. The `PersonalizationScoreType` enum specifies whether the score is `Implicit` (behavior-based) or `Explicit` (direct assignment). {% endhint %} ```csharp +// Using numeric ID public IActionResult ResetPersonaScoreToZero(long personaId) { var visitorId = _visitorContext.GetVisitorExternalId(); @@ -81,8 +90,48 @@ public IActionResult ResetPersonaScoreToZero(long personaId) return Ok("OK"); } + +// Using GUID Key (preferred approach) +public IActionResult ResetPersonaScoreToZero(Guid personaKey) +{ + var visitorId = _visitorContext.GetVisitorExternalId(); + + if (visitorId.HasValue) + { + var personaGroups = _personaGroupRepository.GetPersonaScoresByVisitor(visitorId.Value); + var personaGroup = personaGroups.FirstOrDefault(x => x.Personas.Any(y => y.Key == personaKey)); + var persona = personaGroup?.Personas.FirstOrDefault(x => x.Key == personaKey); + if (persona != null) + { + _personaService.ScorePersona(visitorId.Value, personaKey, persona.Score * -1, PersonalizationScoreType.Explicit); + return Ok($"Subtracted {persona.Score} from visitor {visitorId}"); + } + } + + return Ok("OK"); +} ``` {% hint style="info" %} -The simpler overloads `ScorePersona(long personaId, int score)` and `ScoreCustomerJourneyStep(long customerJourneyStepId, int score)` should only be used within the context of a regular HttpContext request, as they automatically resolve the current visitor. +The simpler overloads `ScorePersona(long personaId, int score)`, `ScorePersona(Guid personaKey, int score)`, `ScoreCustomerJourneyStep(long customerJourneyStepId, int score)`, and `ScoreCustomerJourneyStep(Guid stepKey, int score)` should only be used within the context of a regular HttpContext request, as they automatically resolve the current visitor. {% endhint %} + +## Available Method Overloads + +### IPersonaService + +| Method | Parameters | Use Case | +|--------|------------|----------| +| `ScorePersona` | `(long personaId, int score)` | Within HttpContext, using numeric ID | +| `ScorePersona` | `(Guid personaKey, int score)` | Within HttpContext, using GUID key (preferred) | +| `ScorePersona` | `(Guid visitorExternalId, long personaId, int score, PersonalizationScoreType scoreType)` | Outside HttpContext, using numeric ID | +| `ScorePersona` | `(Guid visitorExternalId, Guid personaKey, int score, PersonalizationScoreType scoreType)` | Outside HttpContext, using GUID key (preferred) | + +### ICustomerJourneyService + +| Method | Parameters | Use Case | +|--------|------------|----------| +| `ScoreCustomerJourneyStep` | `(long customerJourneyStepId, int score)` | Within HttpContext, using numeric ID | +| `ScoreCustomerJourneyStep` | `(Guid stepKey, int score)` | Within HttpContext, using GUID key (preferred) | +| `ScoreCustomerJourneyStep` | `(Guid visitorExternalId, long customerJourneyStepId, int score, PersonalizationScoreType scoreType)` | Outside HttpContext, using numeric ID | +| `ScoreCustomerJourneyStep` | `(Guid visitorExternalId, Guid stepKey, int score, PersonalizationScoreType scoreType)` | Outside HttpContext, using GUID key (preferred) | diff --git a/17/umbraco-engage/developers/settings/custom-goals-scoring.md b/17/umbraco-engage/developers/settings/custom-goals-scoring.md index 85956b3766b..24ff3aa2a1e 100644 --- a/17/umbraco-engage/developers/settings/custom-goals-scoring.md +++ b/17/umbraco-engage/developers/settings/custom-goals-scoring.md @@ -20,7 +20,12 @@ Creating the goal is similar to creating a page view or page event goal. The **g ## Trigger goal in C\# -To trigger the goal, execute C# code during the visitor's pageview. Inject `Umbraco.Engage.Infrastructure.Analytics.Goals.IGoalService`, which has a `TriggerGoal(long goalId, int value)` method. An implementation looks like: +To trigger the goal, execute C# code during the visitor's pageview. Inject `Umbraco.Engage.Infrastructure.Analytics.Goals.IGoalService`, which provides multiple overloads to trigger goals: + +- `TriggerGoal(long goalId, int value)` - Using numeric ID +- `TriggerGoal(Guid goalKey, int value)` - Using GUID key (preferred) + +An implementation looks like: ```cs using Umbraco.Engage.Infrastructure.Analytics.Goals; @@ -31,11 +36,17 @@ public class YourService public YourService(IGoalService goalService) => _goalService = goalService; - public void TriggerGoal() + public void TriggerGoalById() { - // Use the goalId from the code snippet above + // Using numeric ID (legacy approach) _goalService.TriggerGoal(goalId: 37, value: 42); } + + public void TriggerGoalByKey() + { + // Using GUID key (preferred approach) + _goalService.TriggerGoal(goalKey: new Guid("a1b2c3d4-e5f6-7890-abcd-ef1234567890"), value: 42); + } } ``` @@ -48,7 +59,20 @@ To trigger a goal outside of an HTTP request or a valid pageview, use the overlo Retrieve the pageview GUID in the original request using `Umbraco.Engage.Infrastructure.Analytics.Common.IPageviewGuidManager.GetPageviewGuid()`. You will need to store this pageview GUID for later use when invoking: ```cs +// Using numeric goal ID _goalService.TriggerGoal(pageviewGuid, goalId, value); + +// Using GUID goal key (preferred) +_goalService.TriggerGoal(pageviewGuid, goalKey, value); ``` This custom goal can now be used like other goals and will show up in any statistics related to goals. + +## Available Method Overloads + +| Method | Parameters | Use Case | +|--------|------------|----------| +| `TriggerGoal` | `(long goalId, int value = 0)` | Within HttpContext/pageview, using numeric ID | +| `TriggerGoal` | `(Guid goalKey, int value = 0)` | Within HttpContext/pageview, using GUID key (preferred) | +| `TriggerGoal` | `(Guid pageviewGuid, long goalId, int value = 0)` | Outside HttpContext, using numeric ID | +| `TriggerGoal` | `(Guid pageviewGuid, Guid goalKey, int value = 0)` | Outside HttpContext, using GUID key (preferred) | diff --git a/17/umbraco-engage/getting-started/for-developers/infrastructure-sizing.md b/17/umbraco-engage/getting-started/for-developers/infrastructure-sizing.md index ae8d00aecd5..f4e53686ba1 100644 --- a/17/umbraco-engage/getting-started/for-developers/infrastructure-sizing.md +++ b/17/umbraco-engage/getting-started/for-developers/infrastructure-sizing.md @@ -24,9 +24,13 @@ Due to the wide variety of cloud providers, we recommend using the appropriate s ### **Microsoft Azure** -For Azure SQL, use at least a S3 instance with 100 Data Transport Utility (DTU). +For Azure SQL, use at least a **S3 tier (100 DTUs)** or higher. -Umbraco Engage depends on features that aren’t available in the lower tiers and will fail to boot if they are used. +{% hint style="warning" %} +Umbraco Engage requires **columnstore index support** for optimal performance. Azure SQL tiers lower than S3 (such as S0, S1, S2) do not support **creating** columnstore indexes. The initial installation will fail on these lower tiers. + +**Workaround:** You can temporarily scale up to S3 for the initial installation, then scale back down. Lower tiers can still **query** columnstore indexes once created. However, this configuration is not recommended for production due to potential performance issues. See [Troubleshooting Installations](troubleshooting-installations.md) for details. +{% endhint %} ## Non-cloud diff --git a/17/umbraco-engage/getting-started/for-developers/system-requirements.md b/17/umbraco-engage/getting-started/for-developers/system-requirements.md index 25e70a0174c..4db7ba09bd0 100644 --- a/17/umbraco-engage/getting-started/for-developers/system-requirements.md +++ b/17/umbraco-engage/getting-started/for-developers/system-requirements.md @@ -8,16 +8,41 @@ Umbraco Engage has the following requirements: * Umbraco version 17 * .NET 10.0 -* SQL Server 2014+, LocalDB, or Azure SQL. +* SQL Server 2014+, LocalDB, or Azure SQL * **SQL CE & SQLite are not supported.** {% hint style="info" %} It is recommended to upgrade your Umbraco installation to the latest version of Umbraco 17. {% endhint %} +## Database Requirements + +Umbraco Engage uses **columnstore indexes** for optimal query performance on analytics data. This has implications for your database choice: + +### SQL Server (On-Premises / Self-Hosted) + +* **SQL Server 2014 or higher** is required +* Columnstore index support varies by edition - Enterprise Edition is recommended for older SQL Server versions + +### Azure SQL + +* **S3 tier (100 DTUs) or higher** is required to **create** columnstore indexes during installation +* Lower tiers (S0, S1, S2) can **query** existing columnstore indexes but cannot create them +* See [Infrastructure Sizing](infrastructure-sizing.md) for detailed Azure SQL recommendations + +{% hint style="warning" %} +If you attempt to install Umbraco Engage on an Azure SQL tier lower than S3, the initial migration will fail. See [Troubleshooting Installations](troubleshooting-installations.md) for workarounds. +{% endhint %} + +### LocalDB + +LocalDB supports columnstore indexes and can be used for local development. + See the [Troubleshooting](../../installation/troubleshooting-installs.md) section if you need to upgrade from SQL CE to SQL Server. -Umbraco Engage is compatible with Umbraco Cloud (Standard, Professional and Enterprise plan). +## Umbraco Cloud Compatibility + +Umbraco Engage is compatible with Umbraco Cloud (Standard, Professional and Enterprise plan). {% hint style="info" %} If you want to run an Umbraco Cloud site locally, point the connection string to a (local) SQL Server database. SQLite is not supported. diff --git a/17/umbraco-engage/getting-started/for-developers/troubleshooting-installations.md b/17/umbraco-engage/getting-started/for-developers/troubleshooting-installations.md index 238abe4da31..17636ac340e 100644 --- a/17/umbraco-engage/getting-started/for-developers/troubleshooting-installations.md +++ b/17/umbraco-engage/getting-started/for-developers/troubleshooting-installations.md @@ -15,8 +15,8 @@ After installing Umbraco Engage and booting for the first time, an SQL exception The most common reasons for this are: * Database connectivity issues. -* Incompatible SQL Server version. -* No columnstore index support on Azure SQL lower than S3. +* Incompatible SQL Server version or edition (columnstore index support required). +* No columnstore index support on Azure SQL tiers lower than S3 (S0, S1, S2). ### Exception @@ -58,3 +58,9 @@ Azure SQL lower than S3 doesn't support creating columnstore indexes. To work ar 3. Scale back to your initial Azure SQL tier. The columnstore indexes are created and can be used in a lower tier. + +#### When running on an incompatible SQL Server version or edition + +SQL Server 2014 or higher is required. Columnstore index support varies by SQL Server version and edition. If you encounter issues, consider upgrading to a newer SQL Server version or using Enterprise Edition. + +See [System Requirements](system-requirements.md) for the full list of supported database configurations. From c2c603d5fb764001796985a840449b4246f5f8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corn=C3=A9=20Hoskam?= Date: Fri, 28 Nov 2025 11:09:17 +0100 Subject: [PATCH 3/5] Some more minor tweaks --- .../developers/headless/using-the-marketing-api.md | 2 +- .../implement-your-own-segment-parameters.md | 8 +++++--- .../for-developers/system-requirements.md | 9 +++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/17/umbraco-engage/developers/headless/using-the-marketing-api.md b/17/umbraco-engage/developers/headless/using-the-marketing-api.md index 4b20ac14d1c..84649930e0c 100644 --- a/17/umbraco-engage/developers/headless/using-the-marketing-api.md +++ b/17/umbraco-engage/developers/headless/using-the-marketing-api.md @@ -62,7 +62,7 @@ To track a page view, send a POST request to: * `/umbraco/engage/api/v1/analytics/pageview/trackpageview/client` * Required: `url` property of the page that a user has visited in the site - * Optional: `reffererUrl` can be set to inform Umbraco Engage where the user came from. + * Optional: `referrerUrl` can be set to inform Umbraco Engage where the user came from. * `/umbraco/engage/api/v1/analytics/pageview/trackpageview/server` diff --git a/17/umbraco-engage/developers/personalization/implement-your-own-segment-parameters.md b/17/umbraco-engage/developers/personalization/implement-your-own-segment-parameters.md index c5f9cbb5340..485cd04b5fe 100644 --- a/17/umbraco-engage/developers/personalization/implement-your-own-segment-parameters.md +++ b/17/umbraco-engage/developers/personalization/implement-your-own-segment-parameters.md @@ -31,11 +31,13 @@ A segment rule is not much more than this: You will have to implement the following interfaces for a new custom parameter: -- `Umbraco.Engage.Infrastructure.Personalization.Segments.ISegmentRule` +- `Umbraco.Engage.Infrastructure.Personalization.Segments.Rules.ISegmentRule` - You can extend the existing `BaseSegmentRule` to simplify the implementation. - The most important part to implement is the `bool IsSatisfied(IPersonalizationProfile context)` method. -- `Umbraco.Engage.Infrastructure.Personalization.Segments.Rules.ISegmentRuleFactory` \* Register your implementation of the segment rule factory with `Lifetime.Transient` in a composer. - For the "Day of week" example, the code looks like this: +- `Umbraco.Engage.Infrastructure.Personalization.Segments.Rules.ISegmentRuleFactory` + - Register your implementation of the segment rule factory with `Lifetime.Transient` in a composer. + +For the "Day of week" example, the code looks like this: ```c# public class DayOfWeekSegmentRule : BaseSegmentRule diff --git a/17/umbraco-engage/getting-started/for-developers/system-requirements.md b/17/umbraco-engage/getting-started/for-developers/system-requirements.md index 4db7ba09bd0..37cfe5e9e76 100644 --- a/17/umbraco-engage/getting-started/for-developers/system-requirements.md +++ b/17/umbraco-engage/getting-started/for-developers/system-requirements.md @@ -49,3 +49,12 @@ If you want to run an Umbraco Cloud site locally, point the connection string to {% endhint %} Umbraco Deploy is currently not supported for the Umbraco Engage features. + +## Frontend Development Requirements + +If you are developing custom extensions for Umbraco Engage (such as custom segment parameters or external profile data components), the following additional requirements apply: + +* **Node.js 22+** +* **npm 10.9+** + +These are only required for developers building custom frontend components, not for standard Umbraco Engage usage. From a4c36753ed9865f7fe4ab2bf2b3e4e5e6807d1be Mon Sep 17 00:00:00 2001 From: Esha Noronha <82437098+eshanrnh@users.noreply.github.com> Date: Fri, 28 Nov 2025 11:52:34 +0100 Subject: [PATCH 4/5] Apply suggestions --- .../personalization/custom-scoring.md | 17 ++++++++++++----- .../for-developers/system-requirements.md | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/17/umbraco-engage/developers/personalization/custom-scoring.md b/17/umbraco-engage/developers/personalization/custom-scoring.md index ec2f0078ba5..e40abdb88d9 100644 --- a/17/umbraco-engage/developers/personalization/custom-scoring.md +++ b/17/umbraco-engage/developers/personalization/custom-scoring.md @@ -18,7 +18,7 @@ Both services support two ways to identify entities: - **Numeric IDs** (e.g., `personaId`, `customerJourneyStepId`) - Legacy approach using database IDs - **GUID Keys** (e.g., `personaKey`, `stepKey`) - Preferred approach using Umbraco's GUID-based identifiers -To implement our example above, we will be using the `ICustomerJourneyService`. To modify the customer journey step scoring, we need to know the ID or Key of the step we are trying to score. For your implementation you could hardcode the IDs/Keys (since they are unlikely to change), we can also fetch them by name through the `ICustomerJourneyGroupRepository`. +To implement the example above, the `ICustomerJourneyService` will be used. To modify the customer journey step scoring, the ID or Key of the step being updated must be known. For an implementation, the IDs/Keys can be hardcoded (since they are unlikely to change), or they can be fetched by name through the `ICustomerJourneyGroupRepository`. To resolve the required services, we will use Dependency Injection: @@ -50,7 +50,7 @@ var stepDo = customerJourneyGroup.Steps.FirstOrDefault(step => step.Title == "Do ``` {% endcode %} -We can now inspect the step **Do** variable and find its `Id` or `Key`. To score the step, we provide either the numeric ID or GUID Key and the score to the `CustomerJourneyService`: +Inspect the step **Do** variable and find its `Id` or `Key`. To score the step, provide either the numeric ID or the GUID Key and the score to the `CustomerJourneyService`: ```csharp // Using numeric ID (legacy approach) @@ -64,10 +64,11 @@ We have now added a **score of 100** to the Customer Journey step "**Do**". It i Since the user is no longer (shifting away) from that step of the Customer Journey the implementation strategy is the same for personas. -Another, more advanced, example could be on how to reset the score of a persona for a given visitor. We can use the same approach as above to fetch the **persona** instead of the Customer Journey for the current visitor. We can get the visitor's current score based on the Persona ID or Key, and subtract that exact score from said visitor. +Another, more advanced, example could be on how to reset the score of a persona for a given visitor. Use the same approach as above to fetch the **persona** instead of the Customer Journey for the current visitor. Get the visitor's current score based on the Persona ID or Key, and subtract that exact score from said visitor. {% hint style="info" %} -When scoring outside of a regular HttpContext request (e.g., in background jobs or external integrations), you must use the overload that includes `PersonalizationScoreType`. The `PersonalizationScoreType` enum specifies whether the score is `Implicit` (behavior-based) or `Explicit` (direct assignment). + +When scoring outside of a regular HttpContext request (for example, in background jobs or external integrations), use the overload with `PersonalizationScoreType`. The `PersonalizationScoreType` enum specifies whether the score is `Implicit` (behavior-based) or `Explicit` (direct assignment). {% endhint %} ```csharp @@ -113,7 +114,13 @@ public IActionResult ResetPersonaScoreToZero(Guid personaKey) ``` {% hint style="info" %} -The simpler overloads `ScorePersona(long personaId, int score)`, `ScorePersona(Guid personaKey, int score)`, `ScoreCustomerJourneyStep(long customerJourneyStepId, int score)`, and `ScoreCustomerJourneyStep(Guid stepKey, int score)` should only be used within the context of a regular HttpContext request, as they automatically resolve the current visitor. +The following overloads should only be used within the context of a regular HttpContext request, as they automatically resolve the current visitor. + +- `ScorePersona(long personaId, int score)`, +- `ScorePersona(Guid personaKey, int score)`, +- `ScoreCustomerJourneyStep(long customerJourneyStepId, int score)`, and +- `ScoreCustomerJourneyStep(Guid stepKey, int score)` + {% endhint %} ## Available Method Overloads diff --git a/17/umbraco-engage/getting-started/for-developers/system-requirements.md b/17/umbraco-engage/getting-started/for-developers/system-requirements.md index 37cfe5e9e76..ec55972514a 100644 --- a/17/umbraco-engage/getting-started/for-developers/system-requirements.md +++ b/17/umbraco-engage/getting-started/for-developers/system-requirements.md @@ -42,7 +42,7 @@ See the [Troubleshooting](../../installation/troubleshooting-installs.md) sectio ## Umbraco Cloud Compatibility -Umbraco Engage is compatible with Umbraco Cloud (Standard, Professional and Enterprise plan). +Umbraco Engage is compatible with Umbraco Cloud (Standard, Professional, and Enterprise plans). {% hint style="info" %} If you want to run an Umbraco Cloud site locally, point the connection string to a (local) SQL Server database. SQLite is not supported. @@ -54,7 +54,7 @@ Umbraco Deploy is currently not supported for the Umbraco Engage features. If you are developing custom extensions for Umbraco Engage (such as custom segment parameters or external profile data components), the following additional requirements apply: -* **Node.js 22+** -* **npm 10.9+** +* `Node.js 22+` +* `npm 10.9+` These are only required for developers building custom frontend components, not for standard Umbraco Engage usage. From 8a91a2e163c26723334edbe1de2f35c392289309 Mon Sep 17 00:00:00 2001 From: Esha Noronha <82437098+eshanrnh@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:45:04 +0100 Subject: [PATCH 5/5] Apply suggestions --- 17/umbraco-engage/developers/headless/README.md | 6 +++--- .../getting-started/for-developers/system-requirements.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/17/umbraco-engage/developers/headless/README.md b/17/umbraco-engage/developers/headless/README.md index 8d3c5242a13..a5d638e7c9b 100644 --- a/17/umbraco-engage/developers/headless/README.md +++ b/17/umbraco-engage/developers/headless/README.md @@ -1,12 +1,12 @@ --- description: >- - Discover how to integrate Umbraco.Engage.Headless package with Umbraco 17 + Discover how to integrate `Umbraco.Engage.Headless` package with Umbraco. for a Content Delivery API. --- # Headless -Umbraco Engage offers the **Umbraco.Engage.Headless** package for seamless integration with Umbraco 17. This package enables access to the Headless Content Delivery API, enabling personalized content, A/B tests, and segmentation. +Umbraco Engage offers the **Umbraco.Engage.Headless** package for seamless integration with Umbraco. This package enables access to the Headless Content Delivery API, enabling personalized content, A/B tests, and segmentation. {% hint style="info" %} All Engage features are supported except: @@ -28,7 +28,7 @@ All Engage features are supported except: To install Umbraco.Engage.Headless, ensure the following prerequisites: -* Umbraco v17 is required to integrate with the [Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api). +* The latest version of Umbraco is required to integrate with the [Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api). * Enable the [Umbraco Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api#enable-the-content-delivery-api) by adding the following configuration setting in the `appsettings.json` file: ```json diff --git a/17/umbraco-engage/getting-started/for-developers/system-requirements.md b/17/umbraco-engage/getting-started/for-developers/system-requirements.md index ec55972514a..a238c84631e 100644 --- a/17/umbraco-engage/getting-started/for-developers/system-requirements.md +++ b/17/umbraco-engage/getting-started/for-developers/system-requirements.md @@ -6,13 +6,13 @@ description: Learn about the system requirements before installing Umbraco Engag Umbraco Engage has the following requirements: -* Umbraco version 17 +* Latest Umbraco version * .NET 10.0 * SQL Server 2014+, LocalDB, or Azure SQL * **SQL CE & SQLite are not supported.** {% hint style="info" %} -It is recommended to upgrade your Umbraco installation to the latest version of Umbraco 17. +It is recommended to upgrade your Umbraco installation to the latest version of Umbraco. {% endhint %} ## Database Requirements