diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go index 2e361fa56f7..dc1ee9d0dc4 100644 --- a/adapters/pubmatic/pubmatic.go +++ b/adapters/pubmatic/pubmatic.go @@ -66,6 +66,10 @@ const ( INVALID_HEIGHT = "Invalid Height" INVALID_MEDIATYPE = "Invalid MediaType" INVALID_ADSLOT = "Invalid AdSlot" + + dctrKeyName = "key_val" + pmZoneIDKeyName = "pmZoneId" + pmZoneIDKeyNameOld = "pmZoneID" ) func PrepareLogMessage(tID, pubId, adUnitId, bidID, details string, args ...interface{}) string { @@ -485,30 +489,43 @@ func parseImpressionObject(imp *openrtb2.Imp, wrapExt *string, pubID *string) er imp.Banner = bannerCopy } + extMap := make(map[string]interface{}, 0) if pubmaticExt.Keywords != nil && len(pubmaticExt.Keywords) != 0 { - kvstr := makeKeywordStr(pubmaticExt.Keywords) - imp.Ext = json.RawMessage([]byte(kvstr)) - } else { - imp.Ext = nil + addKeywordsToExt(pubmaticExt.Keywords, extMap) + } + //Give preference to direct values of 'dctr' & 'pmZoneId' params in extension + if pubmaticExt.Dctr != "" { + extMap[dctrKeyName] = pubmaticExt.Dctr + } + if pubmaticExt.PmZoneID != "" { + extMap[pmZoneIDKeyName] = pubmaticExt.PmZoneID + } + + imp.Ext = nil + if len(extMap) > 0 { + ext, err := json.Marshal(extMap) + if err == nil { + imp.Ext = ext + } } return nil } -func makeKeywordStr(keywords []*openrtb_ext.ExtImpPubmaticKeyVal) string { - eachKv := make([]string, 0, len(keywords)) +func addKeywordsToExt(keywords []*openrtb_ext.ExtImpPubmaticKeyVal, extMap map[string]interface{}) { for _, keyVal := range keywords { if len(keyVal.Values) == 0 { logf("No values present for key = %s", keyVal.Key) continue } else { - eachKv = append(eachKv, fmt.Sprintf("\"%s\":\"%s\"", keyVal.Key, strings.Join(keyVal.Values[:], ","))) + key := keyVal.Key + if keyVal.Key == pmZoneIDKeyNameOld { + key = pmZoneIDKeyName + } + extMap[key] = strings.Join(keyVal.Values[:], ",") } } - - kvStr := "{" + strings.Join(eachKv, ",") + "}" - return kvStr } func prepareImpressionExt(keywords map[string]string) string { diff --git a/adapters/pubmatic/pubmatictest/exemplary/banner.json b/adapters/pubmatic/pubmatictest/exemplary/banner.json index 1eb8a212bff..f525673c02e 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/banner.json +++ b/adapters/pubmatic/pubmatictest/exemplary/banner.json @@ -61,7 +61,7 @@ "w": 300 }, "ext": { - "pmZoneID": "Zone1,Zone2", + "pmZoneId": "Zone1,Zone2", "preference": "sports,movies" } } diff --git a/adapters/pubmatic/pubmatictest/exemplary/video.json b/adapters/pubmatic/pubmatictest/exemplary/video.json index 4c874535a35..1715e4772c8 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/video.json +++ b/adapters/pubmatic/pubmatictest/exemplary/video.json @@ -73,7 +73,7 @@ "maxbitrate": 10 }, "ext": { - "pmZoneID": "Zone1,Zone2" + "pmZoneId": "Zone1,Zone2" } } ], diff --git a/adapters/pubmatic/pubmatictest/params/race/banner.json b/adapters/pubmatic/pubmatictest/params/race/banner.json index 86ddc70b729..ab88871edf4 100644 --- a/adapters/pubmatic/pubmatictest/params/race/banner.json +++ b/adapters/pubmatic/pubmatictest/params/race/banner.json @@ -1,6 +1,8 @@ { "publisherId": "156209", "adSlot": "pubmatic_test2@300x250", + "pmzoneid": "drama,sport", + "dctr": "abBucket=4|adType=page|entity=|paidByCategory=|sku=|userLevel=free|platform=android|majorVersion=3.54|version=3.54.0|mobileApplication=true|showId=20166|show=Kisah Untuk Geri|genre=Drama|contentUrl=https://www.iflix.com/title/show/20166|rating=TV-MA|contentLanguage=id", "keywords": { "pmZoneID": "Zone1,Zone2", "preference": "sports,movies" diff --git a/adapters/pubmatic/pubmatictest/params/race/video.json b/adapters/pubmatic/pubmatictest/params/race/video.json index 86ddc70b729..ab88871edf4 100644 --- a/adapters/pubmatic/pubmatictest/params/race/video.json +++ b/adapters/pubmatic/pubmatictest/params/race/video.json @@ -1,6 +1,8 @@ { "publisherId": "156209", "adSlot": "pubmatic_test2@300x250", + "pmzoneid": "drama,sport", + "dctr": "abBucket=4|adType=page|entity=|paidByCategory=|sku=|userLevel=free|platform=android|majorVersion=3.54|version=3.54.0|mobileApplication=true|showId=20166|show=Kisah Untuk Geri|genre=Drama|contentUrl=https://www.iflix.com/title/show/20166|rating=TV-MA|contentLanguage=id", "keywords": { "pmZoneID": "Zone1,Zone2", "preference": "sports,movies" diff --git a/adapters/pubmatic/pubmatictest/supplemental/app.json b/adapters/pubmatic/pubmatictest/supplemental/app.json index 636433ca1f5..e9f1048e855 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/app.json +++ b/adapters/pubmatic/pubmatictest/supplemental/app.json @@ -61,7 +61,7 @@ "w": 300 }, "ext": { - "pmZoneID": "Zone1,Zone2", + "pmZoneId": "Zone1,Zone2", "preference": "sports,movies" } } diff --git a/adapters/pubmatic/pubmatictest/supplemental/dctrAndPmZoneID.json b/adapters/pubmatic/pubmatictest/supplemental/dctrAndPmZoneID.json new file mode 100644 index 00000000000..d68517de560 --- /dev/null +++ b/adapters/pubmatic/pubmatictest/supplemental/dctrAndPmZoneID.json @@ -0,0 +1,162 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "adSlot": "AdTag_Div1@300x250", + "publisherId": " 999 ", + "pmzoneid": "drama,sport", + "dctr": "abBucket=4|adType=page|entity=|paidByCategory=|sku=|userLevel=free|platform=android|majorVersion=3.54|version=3.54.0|mobileApplication=true|showId=20166|show=Kisah Untuk Geri|genre=Drama|contentUrl=https://www.iflix.com/title/show/20166|rating=TV-MA|contentLanguage=id", + "keywords": [ + { + "key": "pmZoneID", + "value": [ + "Zone1", + "Zone2" + ] + }, + { + "key": "preference", + "value": [ + "sports", + "movies" + ] + } + ], + "wrapper": { + "version": 1, + "profile": 5123 + } + } + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "1234" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://hbopenbid.pubmatic.com/translator?source=prebid-server", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "AdTag_Div1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "h": 250, + "w": 300 + }, + "ext": { + "key_val": "abBucket=4|adType=page|entity=|paidByCategory=|sku=|userLevel=free|platform=android|majorVersion=3.54|version=3.54.0|mobileApplication=true|showId=20166|show=Kisah Untuk Geri|genre=Drama|contentUrl=https://www.iflix.com/title/show/20166|rating=TV-MA|contentLanguage=id", + "pmZoneId": "drama,sport", + "preference": "sports,movies" + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "999" + } + }, + "ext": { + "wrapper": { + "profile": 5123, + "version": 1 + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "958", + "bid": [ + { + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "pubmatic.com" + ], + "crid": "29681110", + "h": 250, + "w": 300, + "dealid": "test deal", + "ext": { + "dspid": 6, + "deal_channel": 1 + } + } + ] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.5, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "pubmatic.com" + ], + "crid": "29681110", + "w": 300, + "h": 250, + "dealid": "test deal", + "ext": { + "dspid": 6, + "deal_channel": 1 + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/pubmatic/pubmatictest/supplemental/noAdSlot.json b/adapters/pubmatic/pubmatictest/supplemental/noAdSlot.json index c66a71895ea..a277ef530e4 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/noAdSlot.json +++ b/adapters/pubmatic/pubmatictest/supplemental/noAdSlot.json @@ -55,7 +55,7 @@ "h": 250 }, "ext": { - "pmZoneID": "Zone1,Zone2", + "pmZoneId": "Zone1,Zone2", "preference": "sports,movies" } }], diff --git a/adapters/pubmatic/pubmatictest/supplemental/pmZoneIDInKeywords.json b/adapters/pubmatic/pubmatictest/supplemental/pmZoneIDInKeywords.json new file mode 100644 index 00000000000..c9c335e8646 --- /dev/null +++ b/adapters/pubmatic/pubmatictest/supplemental/pmZoneIDInKeywords.json @@ -0,0 +1,161 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "adSlot": "AdTag_Div1@300x250", + "publisherId": " 999 ", + "dctr": "key1=V1,V2,V3|key2=v1|key3=v3,v5", + "keywords": [ + { + "key": "pmZoneID", + "value": [ + "Zone1", + "Zone2" + ] + }, + { + "key": "preference", + "value": [ + "sports", + "movies" + ] + } + ], + "wrapper": { + "version": 1, + "profile": 5123 + } + } + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "1234" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://hbopenbid.pubmatic.com/translator?source=prebid-server", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "AdTag_Div1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "h": 250, + "w": 300 + }, + "ext": { + "key_val": "key1=V1,V2,V3|key2=v1|key3=v3,v5", + "pmZoneId": "Zone1,Zone2", + "preference": "sports,movies" + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "999" + } + }, + "ext": { + "wrapper": { + "profile": 5123, + "version": 1 + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "958", + "bid": [ + { + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "pubmatic.com" + ], + "crid": "29681110", + "h": 250, + "w": 300, + "dealid": "test deal", + "ext": { + "dspid": 6, + "deal_channel": 1 + } + } + ] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.5, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "pubmatic.com" + ], + "crid": "29681110", + "w": 300, + "h": 250, + "dealid": "test deal", + "ext": { + "dspid": 6, + "deal_channel": 1 + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/pubmatic/pubmatictest/supplemental/trimPublisherID.json b/adapters/pubmatic/pubmatictest/supplemental/trimPublisherID.json index 6a344ee091a..d207542a525 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/trimPublisherID.json +++ b/adapters/pubmatic/pubmatictest/supplemental/trimPublisherID.json @@ -71,7 +71,7 @@ "w": 300 }, "ext": { - "pmZoneID": "Zone1,Zone2", + "pmZoneId": "Zone1,Zone2", "preference": "sports,movies" } } diff --git a/openrtb_ext/imp_pubmatic.go b/openrtb_ext/imp_pubmatic.go index fd97836dd32..cf5093a21e2 100644 --- a/openrtb_ext/imp_pubmatic.go +++ b/openrtb_ext/imp_pubmatic.go @@ -11,6 +11,8 @@ import "encoding/json" type ExtImpPubmatic struct { PublisherId string `json:"publisherId"` AdSlot string `json:"adSlot"` + Dctr string `json:"dctr"` + PmZoneID string `json:"pmzoneid"` WrapExt json.RawMessage `json:"wrapper,omitempty"` Keywords []*ExtImpPubmaticKeyVal `json:"keywords,omitempty"` } diff --git a/static/bidder-params/pubmatic.json b/static/bidder-params/pubmatic.json index 1b6a2f03512..5d41b9fc68a 100644 --- a/static/bidder-params/pubmatic.json +++ b/static/bidder-params/pubmatic.json @@ -12,6 +12,14 @@ "type": "string", "description": "An ID which identifies the ad slot" }, + "pmzoneid": { + "type": "string", + "description": "Comma separated zone id. Used im deal targeting & site section targeting. e.g drama,sport" + }, + "dctr": { + "type": "string", + "description": "Deals Custom Targeting, pipe separated key-value pairs e.g key1=V1,V2,V3|key2=v1|key3=v3,v5" + }, "wrapper": { "type": "object", "description": "Specifies pubmatic openwrap configuration for a publisher",