Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at

  • Joe Harvey 34 posts 174 karma points
    Oct 07, 2022 @ 16:58
    Joe Harvey

    How Does NLS Manage 'Opens' and 'Link Click' Tracking?

    I am testing the campaign analytics/reporting features of NLS and seem to be getting inaccurate (or at best, delayed) statistics reported for email opens and link clicks.

    I'd like to better understand how NLS records these stats as I am concerned that it is perhaps incompatible (or at least sub-optimal) with my load balanced site set up.

    For some context: I have a single back-office node which is used for all operations which manipulate Umbraco data/the database (e.g. content mgmt. via Umbraco Back Office and any custom API endpoints which allow my end users to add/edit content, like comments). This node is explicitly set to be the 'Master' application. Then I have a 1+, load balanced, frontend node(s) which are what my end users view and can perform any read-only style operations against the application and/or it's DB (e.g. present Umbraco content or API endpoints which just lookup data from the DB). These node(s) are explicitly set to be 'Replica' applications.

    My site is also an extranet and therefore all requests sit behind a Microsoft based login wall (via a customised RenderMvcController).

    Tracking 'Opens'

    My assumption is that this is managed via some sort of hidden image request in the body/footer of all NLS emails which once the email is 'opened' and the HTTP request made to request the image, tracks an 'Open' along with some query params identifying the email address of the opener and some details of the campaign etc.

    I have however, seen mixed behaviour here. Sometimes viewing the email in the 'Viewing' panel of desktop Outlook triggers an 'Open', other times I have had to actually double click the email and open it in a new standalone Outlook window before the 'Open' is recorded. Similarly, sometimes a second 'Open' is tracked with little intentional effort (maybe just jumping between this email and another) whereas on other occasions, even quitting Outlook entirely, restarting it and manually re-opening the email again doesn't seem to trigger a second 'Open' statistic.

    I suspect some of this might be to do with if/when the email client decides to make a subsequent HTTP request for the image rather than just serving it from cache, but is there any other logic at play here, like a time window set on the NLS side which needs to have passed before a subsequent 'Open' is tracked for the same recipient using the same email client or anything?

    Link Clicks

    I currently have my base URL set up using the public (replica nodes) URL of as below:

    enter image description here

    This is because I don't really want to expose details of my 'staff only' back-office node URL to any end users.

    Presumably because of this setting, the links in my emails take the format:[SOME_LONG_ID]

    It is the logic under the /__ns/t/link/ endpoint (and possibly a similar /__ns/t/open/ endpoint) that I want to understand as I am concerned that these endpoints are undertaking data manipulation tasks that my frontend nodes shouldn't be doing (as Replicas) and this is the cause for the inaccurate or delayed statistics in NLS.

    Next Steps

    If my above assumptions are accurate, the recommendation might be to set my Base URL for 'tracking links and images' to however my two concerns with that are:

    • I don't really want to expose this URL to my end users in anyway if possible and it will show up on link hover in emails, in alt. text for missing or blocked images and temporarily in their address bar before being redirected to (hopefully)
    • My login wall (which is obviously node/domain specific) will likely mean that sending my end users browser to[ABC] will presumably redirect them to the Microsoft login process which will both make the whole operation take longer and will see their browser flicker/redirect lots and be a rather unpleasant user experience


    If someone could explain how the opens and clicks analytics are being recorded under the hood and advise as to what pitfalls I might run into with a multi-node set up like this it would be much appreciated.

    Off Topic

    I can see in the campaign report 'Overview' tab that there is a table of links clicked by URL plus stats for unique clicks, total clicks, CTR and COTR. I also see under campaign report 'Recipients' tab there is a table of total 'Opens' and 'Clicks'.

    Is there any interface which shows for each link/URL which recipients make up the unique or total clicks tallies? e.g. Article A was clicked by John Smith, Jane Doe and Joe Harvey etc

    I appreciate there is a history of actions for each recipient on their individual details page, but obviously clicking through 1000 recipients in turn to see which of them clicked 'Article A' is not really an option.

  • Markus Johansson 1924 posts 5831 karma points MVP 2x c-trib
    Oct 10, 2022 @ 10:27
    Markus Johansson

    Hi Joey!

    Thanks for looking into the package and thanks for a lot of interesting questions.

    I'll do my best to answer them all as they appear in your post.

    Inaccurate (or at best, delayed) statistics

    Depending on how you are testing this you might be affected by our "spam bot ignore"-feature. The thing is that many email servers have SPAM features that will open an email and click on all links to see if links are pointing to "spammy" websites. This happens when the email arrives at the receiving email server so we have a built-in delay of 45 seconds before we record any interactions. This is sort of a "trade of" where we make the assumption that most recipients will not open the email within 45 seconds, however, if they do they will most likely not click a link within 45 seconds.

    This can be configured using a static setting during startup, e.g:

    NewsletterStudioConstants.Tracking.TrackOnlyWhenSendingWasSecondsAgo = 45

    Tracking opens

    Yes, we're using a pixel image that is rendered in the email and used to determine if the email is opened or not. This is sort of an industry standard but it's not a silver bullet, some email clients will proxy the images to prevent tracking. The "mixed behavior" that you're seeing is most likely due to the timing issue that I describe above.

    Tracking clicks

    We do track clicks in the way that you describe as well. The "id" is a token that we use to store information about the campaign/transactional email and to know where to redirect.

    One thing to note here is that we do check for open-tracking when we get a click. If we have not recorded the "open" (due to any of the different problems described above) we will assume that the email was opened 30 seconds before the click and record an "Open"-event). The idea is that it's impossible to click if you haven't opened =D


    The links for the "front end" is generated using the "Base URL"-setting, this URL does not have to be the URL of the backoffice as long as our code runs on these nodes (the controllers to handle "/__ns/link, open etc.".

    I'm not really sure what kind of setup you would prefer but you need to allow the writes from some URL, maybe you could use some other domain like where you allow the routes used for tracking and media.

    Off topic

    You should be able to to to the "Recipients"-tab in the report an choose "Clicked" in the dropdown, then look at the URL that you want to know more about.

    enter image description here

  • Joe Harvey 34 posts 174 karma points
    Oct 18, 2022 @ 13:44
    Joe Harvey

    Thanks for the useful feedback Markus, all sounds positive and as expected.

    Regarding the TrackOnlyWhenSendingWasSecondsAgo property you mention:

    This can be configured using a static setting during startup

    Where exactly would I set this in order to reduce or remove it during the Umbraco startup process?

    One benefit of my use case being an extranet, is that all recipients will be staff and therefore the servers i question are (relatively) under the control of the client in terms of things like automated link crawling.

    Also, just to save me trawling through the rather verbose HTML email body searching for it, do you know the URL path for the email open image endpoint e.g. something like /__ns/open as i'd like to monitor requests to this endpoint into my server(s) during some testing just to better understand when the email client(s) we will be using are sending this request (vs when they re-serve the image from cache or proxy it as you mention above)

    Thanks in advance,


  • Joe Harvey 34 posts 174 karma points
    Oct 18, 2022 @ 15:23
    Joe Harvey

    Don't worry about the last part, I can see that it's /__ns/t/image/

  • Markus Johansson 1924 posts 5831 karma points MVP 2x c-trib
    Oct 18, 2022 @ 15:44
    Markus Johansson


    Glad to hear that my answers brought some light to your questions!

    Reg. the setting, depending on what version of .NET and Umbraco you're running you could do this in a couple of places, Startup.cs or in a custom Composer. You should be able to just execute this line:

    = 0

    Great that you also found the URL for the image!

    Please feel free to get back with more questions or feedback!

    All the best!

  • Joe Harvey 34 posts 174 karma points
    Oct 25, 2022 @ 12:33
    Joe Harvey

    Hi Markus,

    I'm just looking at updating the TrackOnlyWhenSendingWasSecondsAgo property you mentioned. I am attempting to do this in a pre-existing composer class of mine:

    enter image description here

    However, this property seems to be a const and therefore cannot be altered?

        public static class Tracking
            public const int MinutesBetweenValidInteractions = 5;
            public const int TrackOnlyWhenSendingWasSecondsAgo = 45;
            // ...

    Is this something that has since become editable in a newer version of NLS? We are using v3 for Umbraco 8.

  • Markus Johansson 1924 posts 5831 karma points MVP 2x c-trib
    Oct 26, 2022 @ 12:12
    Markus Johansson

    Hi Joe!

    Ohh, sorry! I did not notice that they were constants.

    I'll look into this and either change them to statics or find another way to accomplish the same thing and make sure to release a patch with these changes included.

    This will be applied to all versions so v3, v9 and v10.


  • Markus Johansson 1924 posts 5831 karma points MVP 2x c-trib
    Oct 30, 2022 @ 14:59
    Markus Johansson

    Hi again!

    Just wanted to let you know that I've pushed a new release (3.0.6) where these properties are now static so that you can change them during startup.

    Please let me know if you have any issues!

    All the best!

Please Sign in or register to post replies

Write your reply to: