Sitecore 9.x
When you call the API, you must remember to include security so that the cookies go with the request. Mainly the analytics cookie.
In the code below the GetPageForApi()
, if requested, will get the page before the Api call. This is since the API is a page request. Without using previous page, the goal would be on the API call itself.
The Api
[HttpGet]
[SkipAnalyticsTrackingApi]
public ActionResult TriggerIAmWithoutEmailGoal()
{
var response = new BaseResponseDTO<TriggerGoalResponseModel>();
try
{
this.eventRepository.TriggerGoalOnce(PageContent.Constants.Goals.IamWithoutEmail, true);
response.Data = new TriggerGoalResponseModel()
{
Result = true,
};
return new JsonNet(response);
}
catch (System.Exception ex)
{
// log your error
response.Error = ex.Message;
return new JsonNet(response);
}
}
The attribute
public class SkipAnalyticsTrackingApiAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Tracker.Current?.CurrentPage?.Cancel();
}
}
The repo
private readonly IDefinitionManager<IGoalDefinition> goalDefinitionManager;
// The goalDefinitionManager is injected by DI
public EventRepository(IDefinitionManager<IGoalDefinition> goalDefinitionManager)
{
this.goalDefinitionManager = goalDefinitionManager;
}
public void TriggerGoal(ID goalId, bool fromApi = false, int engagementValue = 0)
{
var goalDefinition = this.goalDefinitionManager.Get(goalId.Guid, CultureInfo.InvariantCulture);
if (goalDefinition == null)
{
Log.Warn($"Cannot find goal: {goalId}", this);
return;
}
Log.Info($"Goal Triggered: Contact: {Tracker.Current.Contact.ContactId} : {goalId}", this);
var page = fromApi ? GetPageForApi() : Tracker.Current.CurrentPage;
page.RegisterGoal(goalDefinition);
}
public void TriggerGoalOnce(ID goalId,bool fromApi = false)
{
if (IfGoalAlreadyExists(goalId)) return;
TriggerGoal(goalId, fromApi);
}
public bool IfGoalAlreadyExists(ID goalId)
{
if (Tracker.Current?.Session == null) return false;
var goalsTriggered = Tracker.Current?.Session?.Interaction?.Pages?.SelectMany(x => x.PageEvents).Where(x => x.IsGoal).ToList();
var behaviorCache = Tracker.Current.Session.Contact.KeyBehaviorCache.Goals.Any(x => x.Id == goalId.ToGuid());
var pages = goalsTriggered?.Any(x => x.PageEventDefinitionId == goalId.ToGuid()) ?? false;
return behaviorCache || pages;
}
private IPageContext GetPageForApi()
{
if (Tracker.Current.Session.Interaction.PreviousPage == null)
return Tracker.Current.CurrentPage;
return Tracker.Current.Session.Interaction.PreviousPage;
}
Sitecore 8.2
The API and Attribute are the same as above. But the way to trigger the goal is on the tracker in 8.2.
The repo
public void TriggerGoal(ID goalPath, bool fromApi = false)
{
if (Tracker.IsActive && Tracker.Current?.CurrentPage != null)
{
// Trigger a goal
var goalItem = Sitecore.Context.Database.GetItem(goalPath); // Goal item
if (goalItem != null)
{
var goal = new PageEventItem(goalItem); // Wrapper for goal
var page = fromApi ? Tracker.Current.Session.Interaction.PreviousPage : Tracker.Current.CurrentPage;
if (page == null)
{
errorService.LogError(new Exception($"Page is null. Cannnot fire goal. Goal ID {goalPath.Guid}, fromApi = {fromApi}"), this);
return;
}
var pageEventsRow = page.Register(goal); // Goal rtecord to be stored
pageEventsRow.Data = goalItem["Description"];
Tracker.Current.Interaction.AcceptModifications();
Log.Info($"Goal Triggered: Contact: {Tracker.Current.Contact.ContactId} : {goalPath} / {goalItem.Name}", this);
return;
}
}
}
public void TriggerGoalOnce(ID goalId, bool fromApi)
{
if (IfGoalAlreadyExists(goalId)) return;
TriggerGoal(goalId, fromApi);
}
public bool IfGoalAlreadyExists(ID goalId)
{
var goalsTriggered = Tracker.Current.Session.Interaction.Pages.SelectMany(x => x.PageEvents).Where(x => x.IsGoal).ToList();
return goalsTriggered.Any(x => x.PageEventDefinitionId == goalId.ToGuid());
}
var goalDefinition = Sitecore.Analytics.Tracker.MarketingDefinitions.Goals[goalId]; Sitecore.Analytics.Tracker.Current.CurrentPage.RegisterGoal(goalDefinition);