Corresponding with the release of the new 5.0 SDKs, we are requiring the Hashed Advertising Identifier (IDFA) for iOS versions 6 and up. For iOS versions prior to 6, we are requiring the hashed WiFi MAC address.

Please note that either the WiFi MAC Address or IDFA should be passed as the HDID parameter.

For more information, please contact your Account Manager or contact us to reach one of our trained support professionals.

iOS Required Fields

Apple devices such as iPhone, iPad or iPod Touch are assigned Identifiers for Advertisers (IDFAs) starting with iOS version 6.0. We require either the hashed IDFA for iOS Versions 6+ or and the WiFi MAC address for older iOS versions.

Passing the HDID

When using iOS Server-to-Server conversion tracking, you may pass any of the four IDs in the HDID parameter:

  • Hashed WiFi MAC Address using SHA-1.
  • Hashed WiFi MAC Address using MD-5.
  • IDFA hashed using SHA-1.
  • IDFA hashed using MD-5.

Please note that ONLY ONE of the four IDs listed above should be passed in the HDID parameter. If you have any questions, please contact your Account Manager or contact us.

WiFi MAC Address (Device Versions before 6)

Some users may not have iOS version 6+. Our preferred method for receiving the iOS ID from these users is by hashing the WiFi MAC Address.

The WiFi MAC Address is 12 alphanumeric characters that are specific to that device and cannot be changed.

Correct Formatting of the WifI MAC Address

Please remember the Wifi MAC Address should be all upper-case letters with colon separators before hashing. Please see the example below.

04:0C:CE:E2:4F:16
Incorrect Formatting of the WiFi MAC Address

Below are examples of incorrect formatting, either because the addresses are in lower-case letters or invalid seperators are used.

04:0c:ce:e2:4f:16 – INCORRECT - lower-case letters
04-0C-CE-E2-4F-16 – INCORRECT - invalid separators
04-0c-ce-e2-4f-16 – INCORRECT - lower-case letters and invalid separators

Hash the WiFi MAC Address

The following iOS code when implemented, will return the WiFi MAC address for the device. The first argument is the buffer for the returned MAC address and the second argument should be set to “en0”.

...
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <net/if_dl.h>
#include <ifaddrs.h>


#define IFT_ETHER 0x6 
#pragma mark -
static char* getMacAddress(char* macAddress, char* ifName) {
    
    int  success;
    struct ifaddrs * addrs;
    struct ifaddrs * cursor;
    const struct sockaddr_dl * dlAddr;
    const unsigned char* base;
    int i;
    
    success = getifaddrs(&addrs) == 0;
    if (success) {
        cursor = addrs;
        while (cursor != 0) {
            if ( (cursor->ifa_addr->sa_family == AF_LINK)
                && (((const struct sockaddr_dl *) cursor->ifa_addr)->sdl_type == IFT_ETHER) && strcmp(ifName,  cursor->ifa_name)==0 ) {
                dlAddr = (const struct sockaddr_dl *) cursor->ifa_addr;
                base = (const unsigned char*) &dlAddr->sdl_data[dlAddr->sdl_nlen];
                strcpy(macAddress, ""); 
                for (i = 0; i < dlAddr->sdl_alen; i++) {
                    if (i != 0) {
                        strcat(macAddress, ":");
                    }
                    char partialAddr[3];
                    sprintf(partialAddr, "%02X", base[i]);
                    strcat(macAddress, partialAddr);
                    
                }
            }
            cursor = cursor->ifa_next;
        }
        
        freeifaddrs(addrs);
    }    
    return macAddress;
}
...

Find the IDFA (device versions 6 and above).

The IDFA is an available parameter for advertisers that can be changed by the user.

The following iOS code, when implemented, will return a hashed version of the IDFA value for the device.

...
+ (NSString *)haid:(BOOL)hash {
#ifndef PRE_6    
    Class asIDManagerClass = NSClassFromString(@"ASIdentifierManager");
    if (asIDManagerClass) {
        NSString *adId = nil;
        
        SEL sharedManagerSel = NSSelectorFromString(@"sharedManager");
        if ([asIDManagerClass respondsToSelector:sharedManagerSel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            id adManager = [asIDManagerClass performSelector:sharedManagerSel];
            if (adManager) {
                SEL advertisingIdentifierSelector = NSSelectorFromString(@"advertisingIdentifier");
                
                if ([adManager respondsToSelector:advertisingIdentifierSelector]) {
                    
                    id uuid = [adManager performSelector:advertisingIdentifierSelector];
                    
                    if (!uuid) {
                        return nil;
                    }
                    
                    SEL uuidStringSelector = NSSelectorFromString(@"UUIDString");
                    if ([uuid respondsToSelector:uuidStringSelector]) {
                        adId = [uuid performSelector:uuidStringSelector];
#pragma clang diagnostic pop
                    }
                }
            }
        }
        
        if (!adId) {
            return nil;
        }
        
        if (hash) {
            //MD5
            const char *cStr = [adId UTF8String];
            unsigned char result[16];
            CC_MD5(cStr, strlen(cStr), result);
            NSString *md5 = [NSString stringWithFormat: @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                             result[0], result[1], result[2], result[3],
                             result[4], result[5], result[6], result[7],
                             result[8], result[9], result[10], result[11],
                             result[12], result[13], result[14], result[15]];
            
            
            //SHA1
            NSData *sha1_data = [adId dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
            uint8_t digest[CC_SHA1_DIGEST_LENGTH];
            CC_SHA1(sha1_data.bytes, sha1_data.length, digest);
            NSMutableString* sha1 = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
            
            for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
                [sha1 appendFormat:@"%02x", digest[i]];
            
            adId = [NSString stringWithFormat:@"mmh_%@_%@",[md5 lowercaseString],sha1];
            //mmh_MD5_SHA1
        }
        return adId;
    }
#endif
    
    return nil;
}
...

Importing the HAID

Only one import will be needed for the HAID.

...
#import <CommonCrypto/CommonDigest.h>
...

Get the User IP Address (UIP)

Obtain the remote IP address of the HTTP request to your server using the server-side programming language of your choice.

The code “ip_addr” may be changed to whichever variable your prefer.

ASP
Dim ip_addr
ip_addr = Server.URLEncode( Request.ServerVariables( "REMOTE_ADDR" ) )
JSP5
String ip_addr = request.getRemoteAddr();
ip_addr = URLEncoder.encode( ip_addr, "UTF-8" );
PERL
my $ip_addr = URI::URL->new($ENV{'REMOTE_ADDR'})
PHP
@$ip_addr = $_SERVER['REMOTE_ADDR']
Ruby on Rails
ip_addr = request.env['REMOTE_ADDR']
VB.net
Dim ip_addr as String = Server.URLEncode( Request.ServerVariables( "REMOTE_ADDR" )