Code snippets

Code snippets allow you to change the behaviour of the tracker through code that is executed real-time for each event.

Updated over a week ago

As the requirements of affiliate networks are diverse and fast changing, trackers should also be highly customisable to respond to these requirements.

Swaarm's tracker runs independently, in complete isolation for each client. This not only ensures better performance and failure isolation but also allows for customer-specific code to be loaded and executed safely.

Concept

This is possible through the concept of code snippets. Every event (impression / click / smart-link) is passed through the defined code-snippets before being processed by our evaluation pipeline.

Each code snippet is a Java class (Java 7 + a subset of Java 8, details here) that implements the following interface. For brevity, the definition of the tracking event class you will find at the end of this article.

public interface TrackingEventOperationInstance {

boolean apply(TrackingEvent trackingEvent);
}

The method can safely mutate the tracking event in any way it sees fit to modify the event's properties or create new data. The result of this method will be considered in the evaluation of the event; false will stop the redirection of the event, true will allow the event to be evaluated in the standard way.

Furthermore, the class itself is allowed to maintain a state in its class attributes. All the class attributes need to be thread-safe, it's best to use containers from the java.util.concurrent package.

Examples

Here are some simple examples to give a better idea of what's possible.

Say we want to check the HTTP referer header together with the user's language and based on its contents we want to signal to our advertiser the type of traffic that was used.

class HttpAcceptHeaderMarker implements TrackingEventOperationInstance {

@Override
public void apply(TrackingEvent trackingEvent) {
if (
trackingEvent.getHttp().getLanguage().contains("en") &&
(trackingEvent.getHttp().getReferrer().contains("news") ||
trackingEvent.getHttp().getReferrer().contains("wpost") ||
trackingEvent.getHttp().getReferrer().contains("cnn") ||
trackingEvent.getHttp().getReferrer().contains("nytimes")
)
) {
trackingEvent.getPublisher().setSubSubId("US News");
}
else if (
trackingEvent.getHttp().getReferrer().contains("poker") ||
trackingEvent.getHttp().getReferrer().contains("roulette")
){
trackingEvent.getPublisher().setSubSubId("Gambling");
}
else{
trackingEvent.getPublisher().setSubSubId("Unknown");
}
return true;
}
}

The following example will show-case the use of state that can be used to share information throughout subsequent executions. Say we want to categorize unique users based on how often they arrive onto the tracker from the same app into 4 different categories: Suspicious,Persistent, Motivated, Interested. Users from the Suspicious category we would also like to block.

import com.weq.tracker.scutum.tracking.domain.TrackingEvent;
import com.weq.tracker.scutum.tracking.domain.TrackingEventOperationInstance;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;

class HttpAcceptHeaderMarker implements TrackingEventOperationInstance {

private Map<String, Long> users = new ConcurrentHashMap<>();

@Override
public boolean apply(TrackingEvent trackingEvent) {
String fingerprint =
trackingEvent.getUser().getConnection().getIp() +
trackingEvent.getUser().getDevice().getUa() +
trackingEvent.getPublisher().getApp();
Long visits = users.compute(fingerprint, new BiFunction<String, Long, Long>() {
@Override
public Long apply(String key, Long visits) {
if (visits == null) {
return 1L;
}
return visits + 1;
}
});

if(visits > 20){
trackingEvent.getPublisher().setUnique1("Suspicious");
return false;
}

if(visits > 7){
trackingEvent.getPublisher().setUnique1("Persistent");
}
else if(visits > 3){
trackingEvent.getPublisher().setUnique1("Motivated");
}
else {
trackingEvent.getPublisher().setUnique1("Interested");
}
return true;
}
}

Deployment

To deploy your code snippet, please contact us through the regular support channels and we will test your snippet and deploy it onto our tracker. In the future we plan to support this directly through the UI.

Annex

The Tracking Event data structure:

public class TrackingEvent {
private TrackingEventType type;
private String id;
private LocalDateTime time;
private TrackingPublisher publisher;
private Offer offer;
private Advertiser advertiser;
private TrackingHttp http;
private UserData user;
private String recommendationLinkId;
}

public enum TrackingEventType {
IMPRESSION,
CLICK,
RECOMMENDATION_LINK,
RECOMMENDATION_CLICK
}

public class TrackingPublisher {
private Publisher publisher;
private String groupId;
private String subId;
private String subSubId;
private String site;
private String placement;
private String creative;
private String app;
private String appStoreId;
private String clickId;
private String unique1;
private String unique2;
private String unique3;
private String originalSubId;
}

public class Publisher {
private String id;
private String company;
private String status;
private String accountManagerId;
private String salesManagerId;
private String accountType;
private String address;
private String country;
private String taxNumber;
private String phone;
private Boolean isApiPublisher;
private String pdId;
private String updatedAt;
private String createdAt;
private String createdBy;
private String internalNote;
private String additionalInformation;
}

public class Offer {
private String id;
private String name;
private String description;
private String advertiserId;
private String advertiserOfferId;
private String appStoreId;
private String previewUrl;
private String advertiserTrackingUrl;
private Targeting targeting;
private String status;
private Boolean isPrivate;
private Boolean isApprovalRequired;
private List<Long> categories;
private String leadflow;
private String kpi;
private List<String> restrictions;
private Long conversionTrackingType;
private String customRestrictions;
private String additionalInformation;
private String creativesURL;
private LocalDateTime createdAt;
private String createdBy;
private LocalDateTime updatedAt;
private String updatedBy;
private String importedOfferId;
private String sourceOfferId;
private String internalNote;
}

public class Advertiser {
private String id;
private String company;
private String status;
private String accountManagerId;
private String salesManagerId;
private String pdId;
private String accountType;
private String address;
private String country;
private String taxNumber;
private String phone;
private String updatedAt;
private String createdAt;
private String createdBy;
private String internalNote;
}

public class TrackingHttp {
private String ua;
private String ip;
private String acceptHeader;
private String referrer;
private String language;
}

public class UserData {
private Device device;
private Geo geo;
private Ids ids;
private Connection connection;
}

public class Device {
private String ua;
private String os;
private String osv;
private String make;
private String model;
private String language;
}

public class Geo {
private String country;
private String region;
private String city;
private String zip;
private Long utcoffset;
}

public class Ids {
private String idfa;
private String gaid;
}

public class Connection {
private String ip;
private String isp;
private ConnectionType type;
}

Did this answer your question?