diff --git a/adapters/thetradedesk/thetradedesk.go b/adapters/thetradedesk/thetradedesk.go
index 2fdf227d15d..f22744ffdc2 100644
--- a/adapters/thetradedesk/thetradedesk.go
+++ b/adapters/thetradedesk/thetradedesk.go
@@ -6,6 +6,8 @@ import (
"fmt"
"net/http"
"regexp"
+ "strconv"
+ "strings"
"text/template"
"github.com/prebid/prebid-server/v3/adapters"
@@ -176,6 +178,7 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest
for _, bid := range seatBid.Bid {
bid := bid
+ resolveAuctionPriceMacros(&bid)
bidType, err := getBidType(bid.MType)
if err != nil {
@@ -232,3 +235,12 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co
templateEndpoint: template,
}, nil
}
+
+func resolveAuctionPriceMacros(bid *openrtb2.Bid) {
+ if bid == nil {
+ return
+ }
+ price := strconv.FormatFloat(bid.Price, 'f', -1, 64)
+ bid.NURL = strings.Replace(bid.NURL, "${AUCTION_PRICE}", price, -1)
+ bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1)
+}
diff --git a/adapters/thetradedesk/thetradedesk_test.go b/adapters/thetradedesk/thetradedesk_test.go
index 22fdcebeec4..11ffda30d9f 100644
--- a/adapters/thetradedesk/thetradedesk_test.go
+++ b/adapters/thetradedesk/thetradedesk_test.go
@@ -451,3 +451,147 @@ func TestTheTradeDeskAdapter_BuildEndpoint(t *testing.T) {
})
}
}
+
+func TestResolveAuctionPriceMacros(t *testing.T) {
+ tests := []struct {
+ name string
+ bid *openrtb2.Bid
+ expectedNURL string
+ expectedAdM string
+ }{
+ {
+ name: "nil_bid",
+ bid: nil,
+ },
+ {
+ name: "no_macros",
+ bid: &openrtb2.Bid{
+ Price: 1.23,
+ NURL: "http://example.com/nurl",
+ AdM: "
Ad content
",
+ },
+ expectedNURL: "http://example.com/nurl",
+ expectedAdM: "Ad content
",
+ },
+ {
+ name: "macros_in_both_nurl_and_adm",
+ bid: &openrtb2.Bid{
+ Price: 1.50,
+ NURL: "http://example.com/nurl?price=${AUCTION_PRICE}",
+ AdM: "Ad content with price ${AUCTION_PRICE}
",
+ },
+ expectedNURL: "http://example.com/nurl?price=1.5",
+ expectedAdM: "Ad content with price 1.5
",
+ },
+ {
+ name: "macro_only_in_nurl",
+ bid: &openrtb2.Bid{
+ Price: 2.75,
+ NURL: "http://example.com/nurl?price=${AUCTION_PRICE}",
+ AdM: "Ad content
",
+ },
+ expectedNURL: "http://example.com/nurl?price=2.75",
+ expectedAdM: "Ad content
",
+ },
+ {
+ name: "macro_only_in_adm",
+ bid: &openrtb2.Bid{
+ Price: 0.99,
+ NURL: "http://example.com/nurl",
+ AdM: "Price: ${AUCTION_PRICE}
",
+ },
+ expectedNURL: "http://example.com/nurl",
+ expectedAdM: "Price: 0.99
",
+ },
+ {
+ name: "multiple_macros_in_same_field",
+ bid: &openrtb2.Bid{
+ Price: 3.14,
+ NURL: "http://example.com/nurl?price=${AUCTION_PRICE}&backup_price=${AUCTION_PRICE}",
+ AdM: "Price: ${AUCTION_PRICE}, Backup: ${AUCTION_PRICE}
",
+ },
+ expectedNURL: "http://example.com/nurl?price=3.14&backup_price=3.14",
+ expectedAdM: "Price: 3.14, Backup: 3.14
",
+ },
+ {
+ name: "zero_price",
+ bid: &openrtb2.Bid{
+ Price: 0.0,
+ NURL: "http://example.com/nurl?price=${AUCTION_PRICE}",
+ AdM: "Price: ${AUCTION_PRICE}
",
+ },
+ expectedNURL: "http://example.com/nurl?price=0",
+ expectedAdM: "Price: 0
",
+ },
+ {
+ name: "very_small_price",
+ bid: &openrtb2.Bid{
+ Price: 0.001,
+ NURL: "http://example.com/nurl?price=${AUCTION_PRICE}",
+ AdM: "Price: ${AUCTION_PRICE}
",
+ },
+ expectedNURL: "http://example.com/nurl?price=0.001",
+ expectedAdM: "Price: 0.001
",
+ },
+ {
+ name: "large_price",
+ bid: &openrtb2.Bid{
+ Price: 999.999,
+ NURL: "http://example.com/nurl?price=${AUCTION_PRICE}",
+ AdM: "Price: ${AUCTION_PRICE}
",
+ },
+ expectedNURL: "http://example.com/nurl?price=999.999",
+ expectedAdM: "Price: 999.999
",
+ },
+ {
+ name: "integer_price",
+ bid: &openrtb2.Bid{
+ Price: 5.0,
+ NURL: "http://example.com/nurl?price=${AUCTION_PRICE}",
+ AdM: "Price: ${AUCTION_PRICE}
",
+ },
+ expectedNURL: "http://example.com/nurl?price=5",
+ expectedAdM: "Price: 5
",
+ },
+ {
+ name: "empty_nurl_and_adm",
+ bid: &openrtb2.Bid{
+ Price: 1.23,
+ NURL: "",
+ AdM: "",
+ },
+ expectedNURL: "",
+ expectedAdM: "",
+ },
+ {
+ name: "case_sensitive_macro_not_replaced",
+ bid: &openrtb2.Bid{
+ Price: 1.50,
+ NURL: "http://example.com/nurl?price=${auction_price}",
+ AdM: "Price: ${Auction_Price}
",
+ },
+ expectedNURL: "http://example.com/nurl?price=${auction_price}",
+ expectedAdM: "Price: ${Auction_Price}
",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ var testBid *openrtb2.Bid
+ if tt.bid != nil {
+ bidCopy := *tt.bid
+ testBid = &bidCopy
+ }
+
+ resolveAuctionPriceMacros(testBid)
+
+ if tt.bid == nil {
+ assert.Nil(t, testBid)
+ return
+ }
+
+ assert.Equal(t, tt.expectedNURL, testBid.NURL, "NURL should match expected value")
+ assert.Equal(t, tt.expectedAdM, testBid.AdM, "AdM should match expected value")
+ })
+ }
+}
diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json b/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json
new file mode 100644
index 00000000000..2629242b010
--- /dev/null
+++ b/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json
@@ -0,0 +1,142 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "site": {
+ "id": "site-id",
+ "page": "ttd.com",
+ "publisher": {
+ "id": "123456"
+ }
+ },
+ "device": {
+ "os": "android",
+ "ip": "91.199.242.236",
+ "ua": "random user agent"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "w": 100,
+ "h": 150
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "123456"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://direct.adsrvr.org/bid/bidder/ttd",
+ "headers": {
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "site": {
+ "id": "site-id",
+ "page": "ttd.com",
+ "publisher": {
+ "id": "123456"
+ }
+ },
+ "device": {
+ "os": "android",
+ "ip": "91.199.242.236",
+ "ua": "random user agent"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "123456"
+ }
+ }
+ }
+ ]
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "currency": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "test-slot-id",
+ "impid": "test-imp-id",
+ "price": 1.50,
+ "crid": "creative-123",
+ "adm": "",
+ "nurl": "http://win-notification.ttd.com?wp=${AUCTION_PRICE}&id=test-slot-id",
+ "w": 300,
+ "h": 250,
+ "ext": {
+ "prebid": {
+ "type": "banner"
+ }
+ },
+ "mtype": 1
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "test-slot-id",
+ "impid": "test-imp-id",
+ "price": 1.50,
+ "crid": "creative-123",
+ "adm": "",
+ "nurl": "http://win-notification.ttd.com?wp=1.5&id=test-slot-id",
+ "w": 300,
+ "h": 250,
+ "ext": {
+ "prebid": {
+ "type": "banner"
+ }
+ },
+ "mtype": 1
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file