Implement Adobe Target Server Side - Part 3

A step by step implementation of Adobe Target server side as per the Adobe Target Node Client documentation.


So the Adobe Target Node Client NPM package is what we’re going to use to implement this server side. Like I mentioned previously, it essentially does a lot if the heavy lifting for us. Although the documentation says that it’s super simple to use (which it is), it gets a little bit confusing because it starts with a simple example of a Target only implementation then adds the Marketing Cloud ID integration, the customer ID integration, the analytics integration, and then it gives you the whole shebang at the end, including the hybrid testing snippet which allows server side testing to speak to client testing and create a unified visitor. But what I thought would be easiest is, just to copy the most complex example of this, set up a simple app and work it through (not necessarily top to bottom but in a logical manner in terms of how this would run on a route when a request is made to the server).

So, I’m going to quickly copy this into Atom which is my text editor of choice. I’ve created a folder on my desktop called Target Server 2 (the reason it’s Target Server 2 is I already have a “1” which is what I used to learn this originally) so I’ll just create a new file called “target-server.js”. This is just my main file, the equivalent of an app.js that you’d normally have. We’ll just copy that in and save it – it won’t work yet because it doesn’t have any of it’s dependencies installed (express, cookie passer or the Adobe Target node client) so let’s do that. So let’s use the Terminal quickly - copy the full path, use the Terminal, navigate to that path and install the dependencies. So that will give us a package.json which is here. First thing we need to add to this package.json file is a script which allows us to run our server when we come to do it. It’s pretty simple to do, you can do it in many ways but the way I’m going to do it is just set up a simple script (then I just use node and then just the name of the file that’s the main js file).

Now this still won’t work as we have dependencies here which is express, cookie passer and node client for Target which we haven’t installed so let’s quickly install those. So it will be just npm install express. Now this is relying on you guys having some knowledge of express and node js and back end languages. Everything I cover here is cross transferable to more or less every language providing you know that language thoroughly and if you are a Marketing Manager who is just trying to get an understanding of what is server side, how does it work, what are the advantages and disadvantages and to be able to have a top level conversation with a developer, then this should still be fine.

So now we’ve got our run script and all of our dependencies installed so at this point you’d think this would work (and it should work if we hit npm run and then the script). Now what you see here is a SyntaxError and it says it’s on line 87 – this SyntaxError is an error in the npm documentation so they need to change it so don’t be caught out by it! So on line 87 you have a closing brace which you don’t need so just end it there and save it. At this point again you’d think it would run, but it doesn’t! It errors and says “organisation ID is not defined”, now the reason this happens is because with newer JavaScript Syntax template literals and interpolation use this syntax, this is also the syntax Target use to put in variables and because of that it errors. So don’t be caught out by this like I was for a long time, just delete all the dollar signs because what it’s doing is, in this template it’s trying to replace the values of these interpolated organisation IDs, visitor state and content and it can’t do that as when it tries to look for them in this template.replace it doesn’t work so just get rid of those.

In theory now, once you’ve got those glitches out the way, your server will run. So if we just look at localhost300, you’ll notice here that the actual route is /abtest so if we just go to the route it won’t bring anything back, so if we go to /abtest you’ll get this response. Now this response doesn’t mean anything but if you look in the Terminal you’ll notice it starts to print something out which is an object which we can start to look at. The object is a request object down here (if you see this console.log “request”). Now at this point it’s probably worth doing a run down of what’s happening here – the top of the file is pretty self explanatory, it’s importing express which is the node framework we’re using to setup this simple server and is letting us host it. Then the cookie passer is letting us read the cookies that are set and do things to them. Then you’ve got the Target node client which is the npm package which is doing most of the heavy lifting. This config here needs to be adjusted to have your client and org ID in there, I’m going to quickly paste mine in. I’ve already shown earlier on how you get the client ID, the organisation ID can be retrieved pretty easily if you just go to your main marketing.adobe it will have it in there at the bottom. So it’s just a simple case of pasting these in.

So that’s the config and it’s used by the Target node client later on. This is just a basic template which is just a couple of scripts and a little bit of html. Then express is called, then client is set to a TargetNodeClient.create and then it’s using the config to create an instance of the Target node client. Cookie passer is called, then we setup the app.use express.static so this is where the static files live. So if I just create a new folder called public (for demonstration purposes) so this is now where for example where we’ve got at.js and we’ve got AppMeasurement.js, this is where it will look for those files – they’re currently not in there but we’ll paste them in there later on. It is worth noting that you’re probably going to be using Launch or DTM to implement at least some of these so how you do this in a real time app is marginally different and I’ll demonstrate that later. Then there’s a couple of functions – there’s a function here which is a save cookie so basically it takes in the response and the cookie and if the cookie doesn’t exist it returns, if the cookie does exist it creates a cookie which is the cookie which Target uses to assign an experience and to be able to identify a visitor. Then there’s this const result which takes the template up here and replaces three things – orgID, visitor state and content. Then we’ve got the save cookie function and these all live inside this sendSuccessResponse so later on we’ll see this send success response but again, takes in response, res and response, it sets headers, it replaces the content in the template with the three variables we need here. It saves the cookies that Target needs then it basically sends a 200 which is an ok response to the server and then just shows the response. Again, this is not how you’d do it in a real world situation but it works well for this demo. And then you’ve got an error function so if anything goes wrong, it’s passed off to this error function that sends a 500 response from the server.

Now this app.get here – so when we go to the server, we go to this route which is /abtest. This initiates the whole thing so it uses the Target node client to set the name of the visitor cookie then the actual visitor cookie itself, then the Target cookie name and then the Target cookie (so this is just it building up the cookies it needs). Then it creates this variable which is the payload – the payload needs at least one mbox and as you’ve seen earlier, my mbox is called servertest1 which is what I created over here originally in my Target interface. Now it is an index so you can identify it later on, you could put many in here and it would return several bits of content but for the context of this, we’ll just do one. Then it goes off and creates a request – the request is just an object that has the payload which is this, it has the Target cookie which it’s been creating up here, the visitor cookie and it has this Target location hint cookie. Now forget about this for now as we’ll cover it off later but it’s what’s used for hybrid testing to show Target client side that there is a server side test running. Then it logs a request, then it has a promise here that once this function is initiated which is part of this nodesdk, it initiates this sendSuccessResponse which is what we talked through earlier on (it sets headers, replaces the content and then shows the content to the page), or if there’s an error, it sends the error function. The final thing here is just the app.listen which is just the server that is set up on port 3000 on my local machine.

And that’s how it works top to bottom. The first time you run through this it doesn’t make much sense because it’s very complicated and there’s things which go on here which I think unless you actually work for Adobe and created this npm package, then you won’t fully understand! But as long as you have enough of an understanding of what’s going on it allows you to manipulate and get to where you need to be.

I’m going to save this now – I’ve put in this servertest1 here and my client code, I’m going to go to my Terminal and end the server and restart it. Then I’m going to reload it and what you’ll see when it returns is an object. Forget about this object for now but if we inspect this, you’ll see that in the head and in the first script, this visitor.getInstance has now fired and it’s fired with the orgID which I’ve set in my config and it’s populated server state with an SDID (supplementary data ID). This is important because it’s what is used to create a single visitor server side to client side which inevitably without this, you’d have no reporting so it’s very important. But what we can see here is that this is initiated up here and this visitor.getInstance has been called and these things here have been replaced with orgID (from here) and the server state which is actually from inside the object (so you’ll see here that it populates it with JSON.stringify so it’s turning a JSON into a string response.visitor state).

So if we just take a look at the response, things become a bit clearer. Now in the Terminal, you’ll see the object that’s a response which is being returned from the Adobe Target server. So you’ll see this visitor state is an object and this is the object that is being inserted into this server state object here so it’s replacing it. Also what you’ll see here is that you’ve got visitor state, Target cookie, mbox etc but you’ve also got these mbox responses. These mbox responses are important because this is where your content lives. To save time, I’m not going to jump into mbox content and responses, I’m going to jump right into the final output of this.

If you drill down into this object a bit more, eventually you’ll come to an array and that array contains the content from the mbox, and rather than it be response.content because that at the moment is an object, if we do response.content.mboxResponses and then earlier on we set an ID which was indexID: 0 which sits in the 0 position in the array. So now we’ve set content to response.content.mboxResponses[0].content which is just drilling down into this – inside mbox responses you’ve got content, mbox responses, an array and the first item in the array is our first mbox and inside that is another object called content. But if we now save this and restart the server again, what you’ll see now is London based Adobe Target conversion optimisation agency so this has now returned content from the server. So it’s now connected to the Target server, and the Target server has returned the content from this and then that content has been rendered on the page which is perfect!

So that’s the top and bottom of getting content back – this at the moment will not fire any requests because it doesn’t actually have the app measurement code or the Target code or the Audience Manager code so what I’m going to do is quickly put them in here. So they have to go in this public folder (depending on how you’ve set up your Express application) so I already have these downloaded from earlier on (you can get them from inside your Adobe account or Google it if you don’t know where to find them) so I’m just going to paste these in here. So now I’ve put in app measurement, at.js and the visitorAPI service because there is no Launch or DTM on here so there’s nothing to fire. So now, everything should fire.

So now you’ll see that you’ve got requests – so now Analytics is firing, Target is firing and the Experience Cloud ID service is firing because we’ve got the visitor API. But what is key to look at here is the supplementary data ID so this value here, in order to confirm you’ve set this up right, needs to be consistent across Target, Analytics and then inside here when we look at our getInstance, you’ll see that the supplementary data ID is the same. Now what that means is that what’s happening here is if you look in the app measurement, I’ve added this in here which basically sets the account which in my case is my dev environment for my agency website and it sets as s_gr which is basically just a new instance. So what the getvisitor.getInstance does is one of two things – it either picks up the visitor object that’s already been created or it creates a new one. So in this case, what we’re wanting it do to is not create a new one as one already exists server side so it reads the cookie that we’ve set down here and it then connects that visitor server side to that visitor client side. That means that everything they go on to do now is one visit so if you have A4T setup for example and the end goal is a conversion 5 pages away from here, you’ll be able to track it through and you don’t create two visitors as ultimately you’d have no data (essentially one server side, one client side which would not be ideal).

That’s it for how it works in this example – as I say, real world scenario it doesn’t necessarily work like this, a lot of the concepts are the same but you have things such as Launch, and you don’t have a template just sitting in a template literal like this so I’m going to end this video and then I’m going to jump into an actual real world example.