Nasal Pathway Melodrama


    0.0.3 • Public • Published

    Pxl for Emails

    Open and click tracking for html emails – hosted by any Express-based node.js app

    Build Status Coverage Status Dependency Status Known Vulnerabilities

    What for?

    Are you sending html emails with your node.js app?

    let emailMarkup = generateHtmlEmail() // E.g. using Foundation for Emails
    sendEmail(addressTo, subject, emailMarkup) // E.g. using nodemailer

    And do you want to track for each recipient if they open the email and on which links they click?

      let emailMarkup = generateHtmlEmail()
    + emailMarkup = pxlForEmails.addTracking(emailMarkup, { recipient: addressTo })
      sendEmail(addressTo, subject, emailMarkup)


    NPM Stats

    This is a module for node.js and is installed via npm:

    npm install pxl-for-emails --save

    pxl-for-emails uses the pxl library to manage the tracking and has to be installed separately. Please check its installation instructions for details.


    The pxl library manages the tracking and needs to be initialized first. Let's assume you use mongoDB in your app and thus we use the pxl-mongodb library that extends pxl and stores all information in mongoDB.

    let Pxl = require('pxl-mongodb') // Or use a different pxl variant for your preferred database
    let pxl = new Pxl()

    pxl-for-emails will extend all urls by a ?pxl=trackingCode query. You need to mount a middleware that "logs" all requests to these urls:

    let app = express()

    Links to external resources need to be shortened and served by your Express app so that the requests pass through the pxl.trackPxl middleware. pxl-for-emails does the shortening for you. You only have to mount the middleware that redirects these shortened links to the external resources:

    app.get('/shortly/:linkId', pxl.redirect)

    pxl is now fully initialized. Now you can initialize pxl-for-emails:

    let PxlForEmails = require('pxl-for-emails')
    let pxlForEmails = new PxlForEmails({
        getFullShortenedLink(linkId) {
            return `https://localhost:3000/shortly/${ linkId }`

    Now you can execute the line in the introduction above:

    emailMarkup = pxlForEmails.addTracking(emailMarkup, { recipient: addressTo })

    pxlForEmails.addTracking(...) will create:

    • 1 tracking code that counts how often the recipient opens the email
    • 1 tracking code for each link in the email that counts how often the recipient clicks on that link

    These tracking codes get stored in the database. For mongoDB it looks like this:

        "pxl": "somecode",
        "type": "click",
        "link": "",
        "count": 0

    The second parameter you pass to pxlForEmails.addTracking(...) is metadata that is stored with it:

    +     "recipient": "",
          "pxl": "somecode",
          "type": "click",
          "link": "",
          "count": 0

    The metadata is important for the analysis of the tracked data. Besides the recipient I usually also store which email was sent – e.g. "weekly update", "special offer" – and the date on which is was sent.

    Additional Options

    pxl and pxl-mongodb provide additional options for initialization. Check out their READMEs for details.

    pxl-for-emails has the following default behavior if you initialize it as described in the Usage section above:

    • The url of the first image in the email is used for open tracking
    • If the email does not contain any images the email is marked as being opened once the user clicks on any link
    • All links are extended for click tracking
    • The image url and all links are categorized as external resources and thus are shortened

    Use the additional options to change the default behavior.

    Select a specific or even multiple images for open tracking

    Description forthcoming.

    Btw, either shorten the image urls (default) or otherwise make sure you disable caching when serving the images that are used for open tracking. You may use nocache to achieve this.

    Improve the open tracking if the email has no images

    Just add a 1x1 transparent pixel image to your email (<img src="...url..." alt=""> somewhere in its body) and let pxl-for-emails add open tracking to this image.

    Btw, either shorten the image url (default) or otherwise make sure you disable caching when serving the image that is used for open tracking. You may use nocache to achieve this.

    Add click tracking not to all but specific links

    Description forthcoming.

    Do not shorten internal image urls / links

    Requests to images and webpages which you host with your own Express app will pass through the pxl.trackPxl middleware. Thus it is not necessary to shorten them. All you need to do is to tell pxl-for-emails which urls to shorten and which not.

      let pxlForEmails = new PxlForEmails({
    +     openTracking: {
    +         shouldApply(link) {
    +             return {
    +                 shorten: !link.startsWith('http://localhost:3000/')
    +             }
    +         }
    +     }
    +     clickTracking: {
    +         shouldApply(link) {
    +             return {
    +                 shorten: !link.startsWith('http://localhost:3000/')
    +             }
    +         }
    +     }
          getFullShortenedLink(linkId) {
              return `http://localhost:3000/shortly/${ linkId }`

    Btw, if you don't shorten the image urls make sure you disable caching when serving the images that are used for open tracking. You may use nocache to achieve this.

    Add categories to all links for easier data analysis

    Your email may contain multiple sign up buttons or multiple links to your blog articles. All those links are tracked separately by default. However, you may want to analyze your data and answer "Did the recipient click on any sign up button?" or "Did the recipient visit our blog?". While you still want to be able to answer "Which sign up botton?" or "Which blog article?" – so separate tracking is important – the solution is to add categories like "sign up button" or "blog article" as additional metadata to the tracking records in the database. Then you can easily answer your questions by grouping the tracking records by their category.

    Description forthcoming.


    To set up your development environment for pxl-for-emails:

    1. Clone this repo to your desktop,
    2. in the shell cd to the main folder,
    3. hit npm install,
    4. hit npm install gulp -g if you haven't installed gulp globally yet, and
    5. run gulp dev. (Or run node ./node_modules/.bin/gulp dev if you don't want to install gulp globally.)

    gulp dev watches all source files and if you save some changes it will lint the code and execute all tests. The test coverage report can be viewed from ./coverage/lcov-report/index.html.

    If you want to debug a test you should use gulp test-without-coverage to run all tests without obscuring the code by the test coverage instrumentation.

    Change History

    • v0.0.3 (2016-10-08)
      • Fix for adding tracking to urls with hashes
    • v0.0.2 (2016-10-08)
      • By default, only the first image is used for open tracking
      • shorten attribute returned by shouldApply may be truthy or falsy instead of true or false
    • v0.0.1 (2016-10-07)
      • Initial version

    License (ISC)

    In case you never heard about the ISC license it is functionally equivalent to the MIT license.

    See the LICENSE file for details.


    npm i pxl-for-emails

    DownloadsWeekly Downloads






    Last publish


    • analog-nico