Repository: prebid/prebid-server
Pull request #1566 (2020-11-05 05:53:24)

Add account CCPA enabled and per-request-type enabled flags
Similar to what we are doing for GDPR, as described in issue #1323 and PR #1564, this adds account-level CCPA configuration.

The order of precedence for determining whether CCPA is enabled is the same as for GDPR:

1. Use account-level request type setting if specified
2. Use account-level general setting if specified
3. Use host-level general setting


bsardo: Manually verified for web, app and amp

Patch:
diff --git a/adapters/adform/adform.go b/adapters/adform/adform.go
index 5881f4ab..d7e5deda 100644
--- a/adapters/adform/adform.go
+++ b/adapters/adform/adform.go
@@ -79,6 +79,7 @@ type adformBid struct {
 	Height       uint64  `json:"height,omitempty"`
 	DealId       string  `json:"deal_id,omitempty"`
 	CreativeId   string  `json:"win_crid,omitempty"`
+	VastContent  string  `json:"vast_content,omitempty"`
 }
 
 const priceTypeGross = "gross"
@@ -241,7 +242,8 @@ func toPBSBidSlice(adformBids []*adformBid, r *adformRequest) pbs.PBSBidSlice {
 	bids := make(pbs.PBSBidSlice, 0)
 
 	for i, bid := range adformBids {
-		if bid.Banner == "" || bid.ResponseType != "banner" {
+		adm, bidType := getAdAndType(bid)
+		if adm == "" {
 			continue
 		}
 		pbsBid := pbs.PBSBid{
@@ -249,12 +251,12 @@ func toPBSBidSlice(adformBids []*adformBid, r *adformRequest) pbs.PBSBidSlice {
 			AdUnitCode:        r.adUnits[i].adUnitCode,
 			BidderCode:        r.bidderCode,
 			Price:             bid.Price,
-			Adm:               bid.Banner,
+			Adm:               adm,
 			Width:             bid.Width,
 			Height:            bid.Height,
 			DealId:            bid.DealId,
 			Creative_id:       bid.CreativeId,
-			CreativeMediaType: string(openrtb_ext.BidTypeBanner),
+			CreativeMediaType: string(bidType),
 		}
 
 		bids = append(bids, &pbsBid)
@@ -632,21 +634,23 @@ func toOpenRtbBidResponse(adformBids []*adformBid, r *openrtb.BidRequest) *adapt
 	}
 
 	for i, bid := range adformBids {
-		if bid.Banner == "" || bid.ResponseType != "banner" {
+		adm, bidType := getAdAndType(bid)
+		if adm == "" {
 			continue
 		}
+
 		openRtbBid := openrtb.Bid{
 			ID:     r.Imp[i].ID,
 			ImpID:  r.Imp[i].ID,
 			Price:  bid.Price,
-			AdM:    bid.Banner,
+			AdM:    adm,
 			W:      bid.Width,
 			H:      bid.Height,
 			DealID: bid.DealId,
 			CrID:   bid.CreativeId,
 		}
 
-		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{Bid: &openRtbBid, BidType: openrtb_ext.BidTypeBanner})
+		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{Bid: &openRtbBid, BidType: bidType})
 		currency = bid.Currency
 	}
 
@@ -654,3 +658,12 @@ func toOpenRtbBidResponse(adformBids []*adformBid, r *openrtb.BidRequest) *adapt
 
 	return bidResponse
 }
+
+func getAdAndType(bid *adformBid) (string, openrtb_ext.BidType) {
+	if bid.ResponseType == "banner" {
+		return bid.Banner, openrtb_ext.BidTypeBanner
+	} else if bid.ResponseType == "vast_content" {
+		return bid.VastContent, openrtb_ext.BidTypeVideo
+	}
+	return "", ""
+}
diff --git a/adapters/dmx/dmx.go b/adapters/dmx/dmx.go
index dfb97f33..6da7823a 100644
--- a/adapters/dmx/dmx.go
+++ b/adapters/dmx/dmx.go
@@ -168,6 +168,7 @@ func (adapter *DmxAdapter) MakeRequests(request *openrtb.BidRequest, req *adapte
 		Body:    oJson,
 		Headers: headers,
 	}
+
 	reqsBidder = append(reqsBidder, reqBidder)
 	return
 }
@@ -221,35 +222,29 @@ func (adapter *DmxAdapter) MakeBids(request *openrtb.BidRequest, externalRequest
 }
 
 func fetchParams(params dmxExt, inst openrtb.Imp, ins openrtb.Imp, imps []openrtb.Imp, banner *openrtb.Banner, video *openrtb.Video, intVal int8) []openrtb.Imp {
+	var tempimp openrtb.Imp
+	tempimp = inst
 	if params.Bidder.TagId != "" {
-		ins = openrtb.Imp{
-			ID:     inst.ID,
-			TagID:  params.Bidder.TagId,
-			Ext:    inst.Ext,
-			Secure: &intVal,
-		}
+		tempimp.TagID = params.Bidder.TagId
+		tempimp.Secure = &intVal
 	}
 
 	if params.Bidder.DmxId != "" {
-		ins = openrtb.Imp{
-			ID:     inst.ID,
-			TagID:  params.Bidder.DmxId,
-			Ext:    inst.Ext,
-			Secure: &intVal,
-		}
+		tempimp.TagID = params.Bidder.DmxId
+		tempimp.Secure = &intVal
 	}
 	if banner != nil {
-		ins.Banner = banner
+		tempimp.Banner = banner
 	}
 
 	if video != nil {
-		ins.Video = video
+		tempimp.Video = video
 	}
 
-	if ins.TagID == "" {
+	if tempimp.TagID == "" {
 		return imps
 	}
-	imps = append(imps, ins)
+	imps = append(imps, tempimp)
 	return imps
 }
 
diff --git a/config/accounts.go b/config/accounts.go
index 5ec818b8..0faf5f5f 100644
--- a/config/accounts.go
+++ b/config/accounts.go
@@ -17,45 +17,63 @@ type Account struct {
 	Disabled      bool        `mapstructure:"disabled" json:"disabled"`
 	CacheTTL      DefaultTTLs `mapstructure:"cache_ttl" json:"cache_ttl"`
 	EventsEnabled bool        `mapstructure:"events_enabled" json:"events_enabled"`
+	CCPA          AccountCCPA `mapstructure:"ccpa" json:"ccpa"`
 	GDPR          AccountGDPR `mapstructure:"gdpr" json:"gdpr"`
 }
 
+// AccountCCPA represents account-specific CCPA configuration
+type AccountCCPA struct {
+	Enabled            *bool              `mapstructure:"enabled" json:"enabled,omitempty"`
+	IntegrationEnabled AccountIntegration `mapstructure:"integration_enabled" json:"integration_enabled"`
+}
+
+// EnabledForIntegrationType indicates whether CCPA is turned on at the account level for the specified integration type
+// by using the integration type setting if defined or the general CCPA setting if defined; otherwise it returns nil
+func (a *AccountCCPA) EnabledForIntegrationType(integrationType IntegrationType) *bool {
+	if integrationEnabled := a.IntegrationEnabled.GetByIntegrationType(integrationType); integrationEnabled != nil {
+		return integrationEnabled
+	}
+	return a.Enabled
+}
+
 // AccountGDPR represents account-specific GDPR configuration
 type AccountGDPR struct {
-	Enabled            *bool                  `mapstructure:"enabled" json:"enabled,omitempty"`
-	IntegrationEnabled AccountGDPRIntegration `mapstructure:"integration_enabled" json:"integration_enabled"`
+	Enabled            *bool              `mapstructure:"enabled" json:"enabled,omitempty"`
+	IntegrationEnabled AccountIntegration `mapstructure:"integration_enabled" json:"integration_enabled"`
 }
 
 // EnabledForIntegrationType indicates whether GDPR is turned on at the account level for the specified integration type
 // by using the integration type setting if defined or the general GDPR setting if defined; otherwise it returns nil
 func (a *AccountGDPR) EnabledForIntegrationType(integrationType IntegrationType) *bool {
-	var integrationEnabled *bool
-
-	switch integrationType {
-	case IntegrationTypeAMP:
-		integrationEnabled = a.IntegrationEnabled.AMP
-	case IntegrationTypeApp:
-		integrationEnabled = a.IntegrationEnabled.App
-	case IntegrationTypeVideo:
-		integrationEnabled = a.IntegrationEnabled.Video
-	case IntegrationTypeWeb:
-		integrationEnabled = a.IntegrationEnabled.Web
-	}
 
-	if integrationEnabled != nil {
+	if integrationEnabled := a.IntegrationEnabled.GetByIntegrationType(integrationType); integrationEnabled != nil {
 		return integrationEnabled
 	}
-	if a.Enabled != nil {
-		return a.Enabled
-	}
-
-	return nil
+	return a.Enabled
 }
 
-// AccountGDPRIntegration indicates whether GDPR is enabled for each integration type
-type AccountGDPRIntegration struct {
+// AccountIntegration indicates whether a particular privacy policy (GDPR, CCPA) is enabled for each integration type
+type AccountIntegration struct {
 	AMP   *bool `mapstructure:"amp" json:"amp,omitempty"`
 	App   *bool `mapstructure:"app" json:"app,omitempty"`
 	Video *bool `mapstructure:"video" json:"video,omitempty"`
 	Web   *bool `mapstructure:"web" json:"web,omitempty"`
 }
+
+// GetByIntegrationType looks up the account integration enabled setting for the specified integration type
+func (a *AccountIntegration) GetByIntegrationType(integrationType IntegrationType) *bool {
+	var integrationEnabled *bool
+
+	switch integrationType {
+	case IntegrationTypeAMP:
+		integrationEnabled = a.AMP
+	case IntegrationTypeApp:
+		integrationEnabled = a.App
+	case IntegrationTypeVideo:
+		integrationEnabled = a.Video
+	case IntegrationTypeWeb:
+		integrationEnabled = a.Web
+	}
+
+	return integrationEnabled
+}
diff --git a/exchange/utils.go b/exchange/utils.go
index f6fcc711..6ae18a27 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -83,7 +83,7 @@ func cleanOpenRTBRequests(ctx context.Context,
 	consent := extractConsent(orig)
 	ampGDPRException := (labels.RType == pbsmetrics.ReqTypeAMP) && gDPR.AMPException()
 
-	ccpaEnforcer, err := extractCCPA(orig, privacyConfig, aliases)
+	ccpaEnforcer, err := extractCCPA(orig, privacyConfig, account, aliases, integrationTypeMap[labels.RType])
 	if err != nil {
 		errs = append(errs, err)
 		return
@@ -144,7 +144,14 @@ func gdprEnabled(account *config.Account, privacyConfig config.Privacy, integrat
 	return privacyConfig.GDPR.Enabled
 }
 
-func extractCCPA(orig *openrtb.BidRequest, privacyConfig config.Privacy, aliases map[string]string) (privacy.PolicyEnforcer, error) {
+func ccpaEnabled(account *config.Account, privacyConfig config.Privacy, requestType config.IntegrationType) bool {
+	if accountEnabled := account.CCPA.EnabledForIntegrationType(requestType); accountEnabled != nil {
+		return *accountEnabled
+	}
+	return privacyConfig.CCPA.Enforce
+}
+
+func extractCCPA(orig *openrtb.BidRequest, privacyConfig config.Privacy, account *config.Account, aliases map[string]string, requestType config.IntegrationType) (privacy.PolicyEnforcer, error) {
 	ccpaPolicy, err := ccpa.ReadFromRequest(orig)
 	if err != nil {
 		return privacy.NilPolicyEnforcer{}, err
@@ -157,7 +164,7 @@ func extractCCPA(orig *openrtb.BidRequest, privacyConfig config.Privacy, aliases
 	}
 
 	ccpaEnforcer := privacy.EnabledPolicyEnforcer{
-		Enabled:        privacyConfig.CCPA.Enforce,
+		Enabled:        ccpaEnabled(account, privacyConfig, requestType),
 		PolicyEnforcer: ccpaParsedPolicy,
 	}
 	return ccpaEnforcer, nil
diff --git a/static/bidder-info/adform.yaml b/static/bidder-info/adform.yaml
index 8aafd9f6..4dce10b9 100644
--- a/static/bidder-info/adform.yaml
+++ b/static/bidder-info/adform.yaml
@@ -4,6 +4,8 @@ capabilities:
   app:
     mediaTypes:
       - banner
+      - video
   site:
     mediaTypes:
       - banner
+      - video


Test patch:
diff --git a/adapters/adform/adform_test.go b/adapters/adform/adform_test.go
index f2277762..0bfb95b6 100644
--- a/adapters/adform/adform_test.go
+++ b/adapters/adform/adform_test.go
@@ -107,6 +107,16 @@ func createAdformServerResponse(testData aBidInfo) ([]byte, error) {
 			DealId:       testData.tags[2].dealId,
 			CreativeId:   testData.tags[2].creativeId,
 		},
+		{
+			ResponseType: "vast_content",
+			VastContent:  testData.tags[3].content,
+			Price:        testData.tags[3].price,
+			Currency:     "EUR",
+			Width:        testData.width,
+			Height:       testData.height,
+			DealId:       testData.tags[3].dealId,
+			CreativeId:   testData.tags[3].creativeId,
+		},
 	}
 	adformServerResponse, err := json.Marshal(bids)
 	return adformServerResponse, err
@@ -123,10 +133,21 @@ func TestAdformBasicResponse(t *testing.T) {
 	if err != nil {
 		t.Fatalf("Should not have gotten adapter error: %v", err)
 	}
-	if len(bids) != 2 {
-		t.Fatalf("Received %d bids instead of 2", len(bids))
+	if len(bids) != 3 {
+		t.Fatalf("Received %d bids instead of 3", len(bids))
+	}
+	expectedTypes := []openrtb_ext.BidType{
+		openrtb_ext.BidTypeBanner,
+		openrtb_ext.BidTypeBanner,
+		openrtb_ext.BidTypeVideo,
 	}
-	for _, bid := range bids {
+
+	for i, bid := range bids {
+
+		if bid.CreativeMediaType != string(expectedTypes[i]) {
+			t.Errorf("Expected a %s bid. Got: %s", expectedTypes[i], bid.CreativeMediaType)
+		}
+
 		matched := false
 		for _, tag := range adformTestData.tags {
 			if bid.AdUnitCode == tag.code {
@@ -224,7 +245,7 @@ func preparePrebidRequest(serverUrl string, t *testing.T) *pbs.PBSRequest {
 
 func preparePrebidRequestBody(requestData aBidInfo, t *testing.T) *bytes.Buffer {
 	prebidRequest := pbs.PBSRequest{
-		AdUnits: make([]pbs.AdUnit, 3),
+		AdUnits: make([]pbs.AdUnit, 4),
 		Device: &openrtb.Device{
 			UA:  requestData.deviceUA,
 			IP:  requestData.deviceIP,
@@ -326,6 +347,7 @@ func createTestData(secure bool) aBidInfo {
 			{mid: 32344, keyValues: "color:red,age:30-40", keyWords: "red,blue", cdims: "300x300,400x200", priceType: "gross", code: "code1", price: 1.23, content: "banner-content1", dealId: "dealId1", creativeId: "creativeId1"},
 			{mid: 32345, priceType: "net", code: "code2", minp: 23.1, cdims: "300x200"}, // no bid for ad unit
 			{mid: 32346, code: "code3", price: 1.24, content: "banner-content2", dealId: "dealId2", url: "https://adform.com?a=b"},
+			{mid: 32347, code: "code4", content: "vast-xml"},
 		},
 		secure:   secure,
 		currency: "EUR",
@@ -379,6 +401,11 @@ func createOpenRtbRequest(testData *aBidInfo) *openrtb.BidRequest {
 func TestOpenRTBStandardResponse(t *testing.T) {
 	testData := createTestData(true)
 	request := createOpenRtbRequest(&testData)
+	expectedTypes := []openrtb_ext.BidType{
+		openrtb_ext.BidTypeBanner,
+		openrtb_ext.BidTypeBanner,
+		openrtb_ext.BidTypeVideo,
+	}
 
 	responseBody, err := createAdformServerResponse(testData)
 	if err != nil {
@@ -390,16 +417,17 @@ func TestOpenRTBStandardResponse(t *testing.T) {
 	bidder := new(AdformAdapter)
 	bidResponse, errs := bidder.MakeBids(request, nil, httpResponse)
 
-	if len(bidResponse.Bids) != 2 {
-		t.Fatalf("Expected 2 bids. Got %d", len(bidResponse.Bids))
+	if len(bidResponse.Bids) != 3 {
+		t.Fatalf("Expected 3 bids. Got %d", len(bidResponse.Bids))
 	}
 	if len(errs) != 0 {
 		t.Errorf("Expected 0 errors. Got %d", len(errs))
 	}
 
-	for _, typeBid := range bidResponse.Bids {
-		if typeBid.BidType != openrtb_ext.BidTypeBanner {
-			t.Errorf("Expected a banner bid. Got: %s", bidResponse.Bids[0].BidType)
+	for i, typeBid := range bidResponse.Bids {
+
+		if typeBid.BidType != expectedTypes[i] {
+			t.Errorf("Expected a %s bid. Got: %s", expectedTypes[i], typeBid.BidType)
 		}
 		bid := typeBid.Bid
 		matched := false
@@ -561,10 +589,10 @@ func assertAdformServerRequest(testData aBidInfo, r *http.Request, isOpenRtb boo
 	var midsWithCurrency = ""
 	var queryString = ""
 	if isOpenRtb {
-		midsWithCurrency = "bWlkPTMyMzQ0JnJjdXI9RVVSJm1rdj1jb2xvcjpyZWQsYWdlOjMwLTQwJm1rdz1yZWQsYmx1ZSZjZGltcz0zMDB4MzAwLDQwMHgyMDA&bWlkPTMyMzQ1JnJjdXI9RVVSJmNkaW1zPTMwMHgyMDAmbWlucD0yMy4xMA&bWlkPTMyMzQ2JnJjdXI9RVVS"
+		midsWithCurrency = "bWlkPTMyMzQ0JnJjdXI9RVVSJm1rdj1jb2xvcjpyZWQsYWdlOjMwLTQwJm1rdz1yZWQsYmx1ZSZjZGltcz0zMDB4MzAwLDQwMHgyMDA&bWlkPTMyMzQ1JnJjdXI9RVVSJmNkaW1zPTMwMHgyMDAmbWlucD0yMy4xMA&bWlkPTMyMzQ2JnJjdXI9RVVS&bWlkPTMyMzQ3JnJjdXI9RVVS"
 		queryString = "CC=1&adid=6D92078A-8246-4BA4-AE5B-76104861E7DC&eids=eyJ0ZXN0LmNvbSI6eyJvdGhlcl91c2VyX2lkIjpbMF0sInNvbWVfdXNlcl9pZCI6WzFdfSwidGVzdDIub3JnIjp7Im90aGVyX3VzZXJfaWQiOlsyXX19&fd=1&gdpr=1&gdpr_consent=abc&ip=111.111.111.111&pt=gross&rp=4&stid=transaction-id&url=https%3A%2F%2Fadform.com%3Fa%3Db&" + midsWithCurrency
 	} else {
-		midsWithCurrency = "bWlkPTMyMzQ0JnJjdXI9VVNEJm1rdj1jb2xvcjpyZWQsYWdlOjMwLTQwJm1rdz1yZWQsYmx1ZSZjZGltcz0zMDB4MzAwLDQwMHgyMDA&bWlkPTMyMzQ1JnJjdXI9VVNEJmNkaW1zPTMwMHgyMDAmbWlucD0yMy4xMA&bWlkPTMyMzQ2JnJjdXI9VVNE" // no way to pass currency in legacy adapter
+		midsWithCurrency = "bWlkPTMyMzQ0JnJjdXI9VVNEJm1rdj1jb2xvcjpyZWQsYWdlOjMwLTQwJm1rdz1yZWQsYmx1ZSZjZGltcz0zMDB4MzAwLDQwMHgyMDA&bWlkPTMyMzQ1JnJjdXI9VVNEJmNkaW1zPTMwMHgyMDAmbWlucD0yMy4xMA&bWlkPTMyMzQ2JnJjdXI9VVNE&bWlkPTMyMzQ3JnJjdXI9VVNE" // no way to pass currency in legacy adapter
 		queryString = "CC=1&adid=6D92078A-8246-4BA4-AE5B-76104861E7DC&fd=1&gdpr=1&gdpr_consent=abc&ip=111.111.111.111&pt=gross&rp=4&stid=transaction-id&" + midsWithCurrency
 	}
 
@@ -646,7 +674,7 @@ func TestPriceTypeUrlParameterCreation(t *testing.T) {
 // Asserts that toOpenRtbBidResponse() creates a *adapters.BidderResponse with
 // the currency of the last valid []*adformBid element and the expected number of bids
 func TestToOpenRtbBidResponse(t *testing.T) {
-	expectedBids := 3
+	expectedBids := 4
 	lastCurrency, anotherCurrency, emptyCurrency := "EUR", "USD", ""
 
 	request := &openrtb.BidRequest{
@@ -672,6 +700,11 @@ func TestToOpenRtbBidResponse(t *testing.T) {
 				Ext:    json.RawMessage(`{"bidder1": { "mid": "32344" }}`),
 				Banner: &openrtb.Banner{},
 			},
+			{
+				ID:     "video-imp-no4",
+				Ext:    json.RawMessage(`{"bidder1": { "mid": "32345" }}`),
+				Banner: &openrtb.Banner{},
+			},
 		},
 		Device: &openrtb.Device{UA: "ua", IP: "ip"},
 		User:   &openrtb.User{BuyerUID: "buyerUID"},
@@ -703,6 +736,16 @@ func TestToOpenRtbBidResponse(t *testing.T) {
 			ResponseType: "banner",
 			Banner:       "banner-content4",
 			Price:        1.25,
+			Currency:     emptyCurrency,
+			Width:        300,
+			Height:       200,
+			DealId:       "dealId4",
+			CreativeId:   "creativeId4",
+		},
+		{
+			ResponseType: "vast_content",
+			VastContent:  "vast-content",
+			Price:        1.25,
 			Currency:     lastCurrency,
 			Width:        300,
 			Height:       200,
diff --git a/adapters/adform/adformtest/exemplary/multiformat-impression.json b/adapters/adform/adformtest/exemplary/multiformat-impression.json
new file mode 100644
index 00000000..efd4aca6
--- /dev/null
+++ b/adapters/adform/adformtest/exemplary/multiformat-impression.json
@@ -0,0 +1,99 @@
+{
+    "mockBidRequest": {
+      "id": "test-request-id",
+      "imp": [
+        {
+          "id": "banner-imp-id",
+          "banner": {
+            "format": [
+              {
+                "w": 300,
+                "h": 250
+              }
+            ]
+          },
+          "ext": {
+            "bidder": {
+              "mid": 12345
+            }
+          }
+        },
+        {
+            "id": "video-imp-id",
+            "video": {
+              "w": 640,
+              "h": 480
+            },
+            "ext": {
+              "bidder": {
+                "mid": 54321
+              }
+            }
+          }
+      ]
+    },
+    "httpCalls": [
+      {
+        "expectedRequest": {
+          "uri": "http://adx.adform.net/adx?CC=1&fd=1&gdpr=&gdpr_consent=&ip=&rp=4&stid=&bWlkPTEyMzQ1JnJjdXI9VVNE&bWlkPTU0MzIxJnJjdXI9VVNE"
+        },
+        "mockResponse": {
+          "status": 200,
+          "body": [
+            {
+              "response": "banner",
+              "banner": "<adm>",
+              "win_bid": 0.5,
+              "win_cur": "USD",
+              "width": 300,
+              "height": 250,
+              "deal_id": null,
+              "win_crid": "20078830"
+            },
+            {
+                "response": "vast_content",
+                "vast_content": "<vast>",
+                "win_bid": 0.7,
+                "win_cur": "USD",
+                "width": 640,
+                "height": 480,
+                "deal_id": "DID-123-22",
+                "win_crid": "20078831"
+              }
+          ]
+        }
+      }
+    ],
+    "expectedBidResponses": [
+      {
+        "currency": "USD",
+        "bids": [
+          {
+            "bid": {
+              "id": "banner-imp-id",
+              "impid": "banner-imp-id",
+              "price": 0.5,
+              "adm": "<adm>",
+              "crid": "20078830",
+              "w": 300,
+              "h": 250
+            },
+            "type": "banner"
+          },
+          {
+            "bid": {
+              "id": "video-imp-id",
+              "impid": "video-imp-id",
+              "price": 0.7,
+              "adm": "<vast>",
+              "crid": "20078831",
+              "dealid": "DID-123-22",
+              "w": 640,
+              "h": 480
+            },
+            "type": "video"
+          }
+        ]
+      }
+    ]
+  }
diff --git a/adapters/adform/adformtest/exemplary/single-banner-impression.json b/adapters/adform/adformtest/exemplary/single-banner-impression.json
new file mode 100644
index 00000000..fd7f3cde
--- /dev/null
+++ b/adapters/adform/adformtest/exemplary/single-banner-impression.json
@@ -0,0 +1,64 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "mid": 12345
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://adx.adform.net/adx?CC=1&fd=1&gdpr=&gdpr_consent=&ip=&rp=4&stid=&bWlkPTEyMzQ1JnJjdXI9VVNE"
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": [
+          {
+            "response": "banner",
+            "banner": "<adm>",
+            "win_bid": 0.5,
+            "win_cur": "USD",
+            "width": 300,
+            "height": 250,
+            "deal_id": null,
+            "win_crid": "20078830"
+          }
+        ]
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-imp-id",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "<adm>",
+            "crid": "20078830",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adform/adformtest/exemplary/single-video-impression.json b/adapters/adform/adformtest/exemplary/single-video-impression.json
new file mode 100644
index 00000000..e22977e6
--- /dev/null
+++ b/adapters/adform/adformtest/exemplary/single-video-impression.json
@@ -0,0 +1,60 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "w": 640,
+          "h": 480
+        },
+        "ext": {
+          "bidder": {
+            "mid": 54321
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://adx.adform.net/adx?CC=1&fd=1&gdpr=&gdpr_consent=&ip=&rp=4&stid=&bWlkPTU0MzIxJnJjdXI9VVNE"
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": [
+          {
+            "response": "vast_content",
+            "vast_content": "<vast>",
+            "win_bid": 0.5,
+            "win_cur": "USD",
+            "width": 640,
+            "height": 480,
+            "deal_id": null,
+            "win_crid": "20078830"
+          }
+        ]
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-imp-id",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "<vast>",
+            "crid": "20078830",
+            "w": 640,
+            "h": 480
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adform/adformtest/params/race/video.json b/adapters/adform/adformtest/params/race/video.json
new file mode 100644
index 00000000..51f8f1b9
--- /dev/null
+++ b/adapters/adform/adformtest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+    "mid": "858300"
+}
diff --git a/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json b/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json
index 51ce4e92..6672e2af 100644
--- a/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json
+++ b/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json
@@ -24,7 +24,6 @@
       }
     ]
   },
-
   "httpCalls": [
     {
       "expectedRequest": {
@@ -57,38 +56,40 @@
           "ua": "",
           "adapterName": "BF_PREBID_S2S",
           "adapterVersion": "0.9.0",
-          "user": {
-          }
+          "user": {}
         }
       },
       "mockResponse": {
         "status": 200,
         "body": [
           {
-            "crid":"crid_1",
-            "price":2.942808,
-            "w":300,
-            "h":250,
-            "slot":"div-gpt-ad-1460505748561-0",
-            "adm":"<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
+            "crid": "crid_1",
+            "price": 2.942808,
+            "w": 300,
+            "h": 250,
+            "slot": "div-gpt-ad-1460505748561-0",
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
           }
         ]
       }
     }
   ],
-
-  "expectedBids": [
+  "expectedBidResponses": [
     {
-      "bid": {
-        "id": "12345678",
-        "impid": "test-slot",
-        "price": 2,
-        "adm": "\u003cdiv id=\"12345678\" style=\"width:300;height:250;background-color:black;color:white;\"\u003e300x250\u003c\\div\u003e",
-        "crid": "crid_1",
-        "w": 300,
-        "h": 250
-      },
-      "type": "banner"
+      "bids": [
+        {
+          "bid": {
+            "id": "div-gpt-ad-1460505748561-0Banner",
+            "impid": "div-gpt-ad-1460505748561-0",
+            "price": 2.942808,
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
+            "crid": "crid_1",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
     }
   ]
 }
diff --git a/adapters/beachfront/beachfronttest/exemplary/simple-adm-video.json b/adapters/beachfront/beachfronttest/exemplary/simple-adm-video.json
index 0ff7790b..cb1f4c20 100644
--- a/adapters/beachfront/beachfronttest/exemplary/simple-adm-video.json
+++ b/adapters/beachfront/beachfronttest/exemplary/simple-adm-video.json
@@ -1,34 +1,33 @@
 {
-  "mockBidRequest":
-  {
-    "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-    "tmax":1000,
-    "source":{
-      "tid":"61b87329-8790-47b7-90dd-c53ae7ce1723"
+  "mockBidRequest": {
+    "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+    "tmax": 1000,
+    "source": {
+      "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
     },
-    "imp":[
+    "imp": [
       {
-        "id":"video1",
-        "ext":{
-          "bidder":{
-            "videoResponseType" : "adm",
-            "bidfloor":0.01,
-            "appId":"11bc5dd5-7421-4dd8-c926-40fa653bec76"
+        "id": "video1",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "adm",
+            "bidfloor": 0.01,
+            "appId": "11bc5dd5-7421-4dd8-c926-40fa653bec76"
           }
         },
-        "video":{
-          "mimes":[
+        "video": {
+          "mimes": [
             "video/mp4"
           ],
-          "context":"instream",
-          "w":300,
-          "h":250
+          "context": "instream",
+          "w": 300,
+          "h": 250
         }
       }
     ],
-    "site":{
-      "publisher":{
-        "id":"publisher1"
+    "site": {
+      "publisher": {
+        "id": "publisher1"
       },
       "page": "http://example.com/whatever/something.html"
     },
@@ -42,7 +41,6 @@
       "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16"
     }
   },
-
   "httpCalls": [
     {
       "expectedRequest": {
@@ -63,8 +61,8 @@
             }
           ],
           "site": {
-            "publisher":{
-              "id":"publisher1"
+            "publisher": {
+              "id": "publisher1"
             },
             "page": "http://example.com/whatever/something.html",
             "domain": "example.com"
@@ -75,10 +73,9 @@
             "ip": "192.168.255.255"
           },
           "source": {
-           "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
+            "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
           },
           "tmax": 1000,
-
           "cur": [
             "USD"
           ],
@@ -87,12 +84,12 @@
             "buyeruid": "some-buyer"
           }
         }
-        },
+      },
       "mockResponse": {
-        "status" : 200,
+        "status": 200,
         "body": {
-          "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatBid":[
+          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "seatBid": [
             {
               "bid": [
                 {
@@ -122,31 +119,32 @@
       }
     }
   ],
-
-  "expectedBids": [
+  "expectedBidResponses": [
     {
-
-      "bid":[
+      "bids": [
         {
-          "id": "video1AdmVideo",
-          "impid": "video1",
-          "price": 20,
-          "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d8393417cbc8e5aa4fe2202,0.01\",\"inventory_id\":\"bid:95d219a2-6025-44ba-bff8-1dca987beaae:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
-          "adid": "1088",
-          "adomain": [
-            "beachfront.io"
-          ],
-          "cid": "277",
-          "crid": "532",
-          "w": 300,
-          "h": 250,
-          "ext": {
-            "prebid": {
-              "type": "video"
+          "bid": {
+            "id": "video1AdmVideo",
+            "impid": "video1",
+            "price": 20,
+            "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d8393417cbc8e5aa4fe2202,0.01\",\"inventory_id\":\"bid:95d219a2-6025-44ba-bff8-1dca987beaae:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
+            "adid": "1088",
+            "adomain": [
+              "beachfront.io"
+            ],
+            "cid": "277",
+            "crid": "532",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
             }
-          }
+          },
+          "type": "video"
         }
       ]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/adapters/beachfront/beachfronttest/exemplary/simple-mix.json b/adapters/beachfront/beachfronttest/exemplary/simple-mix.json
index eb5d9b07..cc2b4158 100644
--- a/adapters/beachfront/beachfronttest/exemplary/simple-mix.json
+++ b/adapters/beachfront/beachfronttest/exemplary/simple-mix.json
@@ -1,25 +1,23 @@
 {
-  "mockBidRequest":
-  {
-    "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-    "tmax":1000,
-    "source":{
-      "tid":"61b87329-8790-47b7-90dd-c53ae7ce1723"
+  "mockBidRequest": {
+    "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+    "tmax": 1000,
+    "source": {
+      "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
     },
-    "imp":[
+    "imp": [
       {
-        "id":"mix1",
-        "ext":{
-          "bidder":{
-            "videoResponseType" : "adm",
-            "bidfloor":0.41,
+        "id": "mix1",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "adm",
+            "bidfloor": 0.41,
             "appIds": {
               "banner": "487cf244-5e95-43cb-e7b9-bb540873ca7e",
               "video": "11bc5dd5-7421-4dd8-c926-40fa653bec76"
             }
           }
         },
-
         "banner": {
           "format": [
             {
@@ -28,18 +26,17 @@
             }
           ]
         },
-
-        "video":{
-          "mimes":[
+        "video": {
+          "mimes": [
             "video/mp4"
           ],
-          "context":"instream",
-          "w":300,
-          "h":250
+          "context": "instream",
+          "w": 300,
+          "h": 250
         }
       }
     ],
-    "site":{
+    "site": {
       "page": "http://example.com/somepage.html"
     },
     "user": {
@@ -51,7 +48,6 @@
       "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16"
     }
   },
-
   "httpCalls": [
     {
       "expectedRequest": {
@@ -89,24 +85,22 @@
           "ip": "192.168.255.255",
           "requestId": "61b87329-8790-47b7-90dd-c53ae7ce1723"
         }
-      } ,
+      },
       "mockResponse": {
-        "status" : 200,
-        "body" :
-          [
-            {
-              "crid":"crid_1",
-              "price":9.5019655,
-              "w":300,
-              "h":250,
-              "slot":"mix1",
-              "adm":"<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
-            }
-          ]
+        "status": 200,
+        "body": [
+          {
+            "crid": "crid_1",
+            "price": 9.5019655,
+            "w": 300,
+            "h": 250,
+            "slot": "mix1",
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
+          }
+        ]
       }
-
-
-    }, {
+    },
+    {
       "expectedRequest": {
         "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76",
         "body": {
@@ -119,7 +113,6 @@
                 "mimes": [
                   "video/mp4"
                 ]
-
               },
               "bidfloor": 0.41,
               "secure": 0,
@@ -149,7 +142,7 @@
         }
       },
       "mockResponse": {
-        "status" : 200,
+        "status": 200,
         "body": {
           "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
           "seatbid": [
@@ -179,40 +172,41 @@
       }
     }
   ],
-
-  "expectedBids": [
+  "expectedBidResponses": [
     {
-
-      "bid":[
+      "bids": [
         {
-          "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "impid":"video1",
-          "price":9.605201,
-          "nurl":"https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
-          "crid":"0d32aea6-d199-4803-a188-bd7cf7be1e12",
-          "w":1500,
-          "h":1280,
-          "ext":{
-            "prebid":{
-              "type":"video"
-            },
-            "bidder":{
-
-            }
-          }
-        }, {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "impid": "mix1",
-          "price": 9.5019655,
-          "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
-          "crid": "crid_1",
-          "w": 300,
-          "h": 250,
-          "ext": {
-            "prebid": {
-              "type": "banner"
-            }
-          }
+          "bid": {
+            "id": "mix1Banner",
+            "impid": "mix1",
+            "price": 9.5019655,
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
+            "crid": "crid_1",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    },
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "mix1AdmVideo",
+            "impid": "mix1",
+            "price": 20,
+            "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d839458f73decdc1572b7f6,0.41\",\"inventory_id\":\"bid:26826cf7-f8bb-4e47-a636-769d83dd9b4f:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
+            "adid": "1088",
+            "adomain": [
+              "beachfront.io"
+            ],
+            "cid": "277",
+            "crid": "532",
+            "w": 300,
+            "h": 250
+          },
+          "type": "video"
         }
       ]
     }
diff --git a/adapters/beachfront/beachfronttest/exemplary/simple-nurl-video.json b/adapters/beachfront/beachfronttest/exemplary/simple-nurl-video.json
index cc3bfe34..0f96d9f2 100644
--- a/adapters/beachfront/beachfronttest/exemplary/simple-nurl-video.json
+++ b/adapters/beachfront/beachfronttest/exemplary/simple-nurl-video.json
@@ -1,33 +1,32 @@
 {
-  "mockBidRequest":
-  {
-    "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-    "tmax":1000,
-    "source":{
-      "tid":"61b87329-8790-47b7-90dd-c53ae7ce1723"
+  "mockBidRequest": {
+    "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+    "tmax": 1000,
+    "source": {
+      "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
     },
-    "imp":[
+    "imp": [
       {
-        "id":"video1",
-        "ext":{
-          "bidder":{
-            "bidfloor":0.01,
-            "appId":"11bc5dd5-7421-4dd8-c926-40fa653bec76"
+        "id": "video1",
+        "ext": {
+          "bidder": {
+            "bidfloor": 0.01,
+            "appId": "11bc5dd5-7421-4dd8-c926-40fa653bec76"
           }
         },
-        "video":{
-          "mimes":[
+        "video": {
+          "mimes": [
             "video/mp4"
           ],
-          "context":"instream",
-          "w":300,
-          "h":250
+          "context": "instream",
+          "w": 300,
+          "h": 250
         }
       }
     ],
-    "site":{
-      "publisher":{
-        "id":"publisher1"
+    "site": {
+      "publisher": {
+        "id": "publisher1"
       },
       "page": "http://example.com/whatever/something.html"
     },
@@ -41,7 +40,6 @@
       "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16"
     }
   },
-
   "httpCalls": [
     {
       "expectedRequest": {
@@ -63,8 +61,8 @@
             }
           ],
           "site": {
-            "publisher":{
-              "id":"publisher1"
+            "publisher": {
+              "id": "publisher1"
             },
             "page": "http://example.com/whatever/something.html",
             "domain": "example.com"
@@ -75,10 +73,9 @@
             "ip": "192.168.255.255"
           },
           "source": {
-           "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
+            "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
           },
           "tmax": 1000,
-
           "cur": [
             "USD"
           ],
@@ -89,58 +86,57 @@
         }
       },
       "mockResponse": {
-        "status" : 200,
+        "status": 200,
         "body": {
-          "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatBid":[
-              {
-                "bid": [
-                  {
-                    "id": "video1NurlVideo",
-                    "impid": "video1",
-                    "price": 20,
-                    "nurl": "https://useast.bfmio.com/getBids?aid=bid:70b99087-1b92-4e81-bc42-05c940fd6014:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8391a85f35945a70c9ddf0,0.01&i_type=pre",
-                    "crid": "70b99087-1b92-4e81-bc42-05c940fd6014",
-                    "w": 300,
-                    "h": 250,
-                    "ext": {
-                      "prebid": {
-                        "type": "video"
-                      },
-                      "bidder": {}
-                    }
+          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "seatBid": [
+            {
+              "bid": [
+                {
+                  "id": "video1NurlVideo",
+                  "impid": "video1",
+                  "price": 20,
+                  "nurl": "https://useast.bfmio.com/getBids?aid=bid:70b99087-1b92-4e81-bc42-05c940fd6014:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8391a85f35945a70c9ddf0,0.01&i_type=pre",
+                  "crid": "70b99087-1b92-4e81-bc42-05c940fd6014",
+                  "w": 300,
+                  "h": 250,
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    },
+                    "bidder": {}
                   }
-                ],
-                "seat": "beachfront"
-              }
-            ]
+                }
+              ],
+              "seat": "beachfront"
+            }
+          ]
         }
       }
     }
   ],
-
-  "expectedBids": [
+  "expectedBidResponses": [
     {
-
-      "bid":[
+      "bids": [
         {
-          "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "impid":"video1",
-          "price":9.605201,
-          "nurl":"https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
-          "crid":"0d32aea6-d199-4803-a188-bd7cf7be1e12",
-          "w":1500,
-          "h":1280,
-          "ext":{
-            "prebid":{
-              "type":"video"
-            },
-            "bidder":{
-
+          "bid": {
+            "id": "video1NurlVideo",
+            "impid": "video1",
+            "price": 20,
+            "nurl": "https://useast.bfmio.com/getBids?aid=bid:70b99087-1b92-4e81-bc42-05c940fd6014:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8391a85f35945a70c9ddf0,0.01&i_type=pre",
+            "crid": "70b99087-1b92-4e81-bc42-05c940fd6014",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "prebid": {
+                "type": "video"
+              },
+              "bidder": {}
             }
-          }
+          },
+          "type": "video"
         }
       ]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json b/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json
index 7bdbc73c..01207f22 100644
--- a/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json
+++ b/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json
@@ -68,5 +68,5 @@
     }
   ],
 
-  "expectedBids": []
+  "expectedBidResponses": []
 }
diff --git a/adapters/beachfront/beachfronttest/supplemental/minimal-mobile-video.json b/adapters/beachfront/beachfronttest/supplemental/minimal-mobile-video.json
index af8b1885..5556f6e7 100644
--- a/adapters/beachfront/beachfronttest/supplemental/minimal-mobile-video.json
+++ b/adapters/beachfront/beachfronttest/supplemental/minimal-mobile-video.json
@@ -2,34 +2,33 @@
   "mockBidRequest": {
     "id": "some_test_ad",
     "app": {
-      "bundle":"_org.prebid.mobile.demoapp",
+      "bundle": "_org.prebid.mobile.demoapp",
       "id": "some-mobile-app"
     },
     "imp": [
       {
-        "id":"video1",
-        "ext":{
-          "bidder":{
-            "bidfloor":0.01,
-            "appId":"11bc5dd5-7421-4dd8-c926-40fa653bec76",
-            "videoResponseType" : "nurl"
+        "id": "video1",
+        "ext": {
+          "bidder": {
+            "bidfloor": 0.01,
+            "appId": "11bc5dd5-7421-4dd8-c926-40fa653bec76",
+            "videoResponseType": "nurl"
           }
         },
-        "video":{
-          "mimes":[
+        "video": {
+          "mimes": [
             "video/mp4"
           ],
-          "w":300,
-          "h":250
+          "w": 300,
+          "h": 250
         }
       }
     ],
-    "device":{
+    "device": {
       "devicetype": 1,
-      "ifa":"bb956625-df13-4568-b60b-eb5cbf76e986"
+      "ifa": "bb956625-df13-4568-b60b-eb5cbf76e986"
     }
   },
-
   "httpCalls": [
     {
       "expectedRequest": {
@@ -48,7 +47,7 @@
               "id": "video1",
               "secure": 0,
               "video": {
-                "mimes":[
+                "mimes": [
                   "video/mp4"
                 ],
                 "h": 250,
@@ -67,71 +66,54 @@
       "mockResponse": {
         "status": 200,
         "body": {
-          "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatBid":[
+          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "seatBid": [
             {
-              "bid":[
+              "bid": [
                 {
-                  "w":0,
-                  "h":0,
+                  "w": 0,
+                  "h": 0,
                   "id": "0",
-                  "impid":"",
-                  "price":0.01,
-                  "adid":"",
-                  "nurl":"https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
-                  "adm":"",
-                  "adomain":[
-
-                  ],
-                  "iurl":"",
-                  "cid":"",
-                  "crid":"",
-                  "attr":[
-
-                  ],
-                  "ext":{
-
-                  },
-                  "cat":[
-
-                  ]
+                  "impid": "",
+                  "price": 0.01,
+                  "adid": "",
+                  "nurl": "https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
+                  "adm": "",
+                  "adomain": [],
+                  "iurl": "",
+                  "cid": "",
+                  "crid": "",
+                  "attr": [],
+                  "ext": {},
+                  "cat": []
                 }
               ],
-              "seat":"",
-              "group":0,
-              "ext":{
-
-              }
+              "seat": "",
+              "group": 0,
+              "ext": {}
             }
           ]
         }
       }
     }
   ],
-
-  "expectedBids": [
+  "expectedBidResponses": [
     {
-
-      "bid":[
+      "bids": [
         {
-          "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "impid":"video1",
-          "price":9.605201,
-          "nurl":"https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
-          "crid":"0d32aea6-d199-4803-a188-bd7cf7be1e12",
-          "w":1500,
-          "h":1280,
-          "ext":{
-            "prebid":{
-              "type":"video"
-            },
-            "bidder":{
-
-            }
-          }
+          "bid": {
+            "id": "video1NurlVideo",
+            "impid": "video1",
+            "price": 0.01,
+            "nurl": "https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
+            "crid": "0d32aea6-d199-4803-a188-bd7cf7be1e12",
+            "w": 300,
+            "h": 250,
+            "ext":{}
+          },
+          "type": "video"
         }
       ]
     }
   ]
-
 }
diff --git a/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json b/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json
index 27b24357..a12f7fd9 100644
--- a/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json
+++ b/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json
@@ -1,94 +1,95 @@
 {
-    "mockBidRequest": {
-      "id": "some_test_ad",
-      "site": {
-        "page": "test.opposingviews.com"
-      },
-      "imp": [
-        {
-          "bidfloor": 0.02,
-          "banner": {
-            "format": [
-              {
-                "w": 300,
-                "h": 250
-              }
-            ]
-          },
-          "ext": {
-            "bidder": {
-              "bidfloor": 0.02,
-              "appId": "3b16770b-17af-4d22-daff-9606bdf2c9c3"
-            }
-          }
-        }
-      ]
+  "mockBidRequest": {
+    "id": "some_test_ad",
+    "site": {
+      "page": "test.opposingviews.com"
     },
-  
-    "httpCalls": [
+    "imp": [
       {
-        "expectedRequest": {
-          "uri": "https://display.bfmio.com/prebid_display",
-          "body": {
-            "slots": [
-              {
-                "slot": "",
-                "id": "3b16770b-17af-4d22-daff-9606bdf2c9c3",
-                "bidfloor": 0.02,
-                "sizes": [
-                  {
-                    "w": 300,
-                    "h": 250
-                  }
-                ]
-              }
-            ],
-            "domain": "test.opposingviews.com",
-            "page": "test.opposingviews.com",
-            "requestId": "some_test_ad",
-            "referrer": "",
-            "search": "",
-            "secure": 0,
-            "isMobile": 0,
-            "ip": "",
-            "deviceModel": "",
-            "deviceOs": "",
-            "dnt": 0,
-            "ua": "",
-            "adapterName": "BF_PREBID_S2S",
-            "adapterVersion": "0.9.0",
-            "user": {
-            }
-          }
-        },
-        "mockResponse": {
-          "status": 200,
-          "body": [
+        "bidfloor": 0.02,
+        "banner": {
+          "format": [
             {
-              "crid":"crid_1",
-              "price":2.942808,
-              "w":300,
-              "h":250,
-              "slot":"div-gpt-ad-1460505748561-0",
-              "adm":"<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
+              "w": 300,
+              "h": 250
             }
           ]
-        }
-      }
-    ],
-  
-    "expectedBids": [
-      {
-        "bid": {
-          "id": "12345678",
-          "impid": "test-slot",
-          "price": 2,
-          "adm": "\u003cdiv id=\"12345678\" style=\"width:300;height:250;background-color:black;color:white;\"\u003e300x250\u003c\\div\u003e",
-          "crid": "crid_1",
-          "w": 300,
-          "h": 250
         },
-        "type": "banner"
+        "ext": {
+          "bidder": {
+            "bidfloor": 0.02,
+            "appId": "3b16770b-17af-4d22-daff-9606bdf2c9c3"
+          }
+        }
       }
     ]
-  }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://display.bfmio.com/prebid_display",
+        "body": {
+          "slots": [
+            {
+              "slot": "",
+              "id": "3b16770b-17af-4d22-daff-9606bdf2c9c3",
+              "bidfloor": 0.02,
+              "sizes": [
+                {
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "domain": "test.opposingviews.com",
+          "page": "test.opposingviews.com",
+          "requestId": "some_test_ad",
+          "referrer": "",
+          "search": "",
+          "secure": 0,
+          "isMobile": 0,
+          "ip": "",
+          "deviceModel": "",
+          "deviceOs": "",
+          "dnt": 0,
+          "ua": "",
+          "adapterName": "BF_PREBID_S2S",
+          "adapterVersion": "0.9.0",
+          "user": {}
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": [
+          {
+            "crid": "crid_1",
+            "price": 2.942808,
+            "w": 300,
+            "h": 250,
+            "slot": "div-gpt-ad-1460505748561-0",
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
+          }
+        ]
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "div-gpt-ad-1460505748561-0Banner",
+            "impid": "div-gpt-ad-1460505748561-0",
+            "price": 2.942808,
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
+            "crid": "crid_1",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json b/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json
index ea38d7ad..17cc7d32 100644
--- a/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json
+++ b/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json
@@ -109,22 +109,20 @@
     }
   ],
 
-  "expectedBids": [
+  "expectedBidResponses": [
     {
-      "Bid": {
-        "id": "763e3312-19d5-4b07-a61d-890147e863a1",
-        "impid": "div-gpt-ad-1460505748561-0",
-        "price": 2.942808,
-        "adm": "\u003cdiv id=\"12345678\" style=\"width:300;height:250;background-color:black;color:white;\"\u003e300x250\u003c\\div\u003e",
-        "crid": "crid_1",
-        "w": 300,
-        "h": 250
-      },
-      "ext": {
-        "prebid": {
-          "type": "banner"
-        }
-      }
+      "bids": [{
+        "bid": {
+          "id": "div-gpt-ad-1460505748561-0Banner",
+          "impid": "div-gpt-ad-1460505748561-0",
+          "price": 2.942808,
+          "adm":"<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
+          "crid": "crid_1",
+          "w": 300,
+          "h": 250
+        },
+        "type": "banner"
+      }]
     }
   ]
 }
diff --git a/adapters/beachfront/beachfronttest/supplemental/multi-banner.json b/adapters/beachfront/beachfronttest/supplemental/multi-banner.json
index 46699511..1d355dba 100644
--- a/adapters/beachfront/beachfronttest/supplemental/multi-banner.json
+++ b/adapters/beachfront/beachfronttest/supplemental/multi-banner.json
@@ -119,18 +119,20 @@
     }
   ],
 
-  "expectedBids": [
+  "expectedBidResponses": [
     {
-      "Bid": {
-        "id": "12345678",
-        "impid": "test-slot",
-        "price": 2,
-        "adm": "\u003cdiv id=\"12345678\" style=\"width:300;height:250;background-color:black;color:white;\"\u003e300x250\u003c\\div\u003e",
-        "crid": "crid_1",
-        "w": 300,
-        "h": 250
-      },
-      "type": "banner"
+      "bids": [{
+        "bid": {
+          "id": "div-gpt-ad-1460505748561-0Banner",
+          "impid": "div-gpt-ad-1460505748561-0",
+          "price": 2.942808,
+          "adm":"<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
+          "crid": "crid_1",
+          "w": 300,
+          "h": 250
+        },
+        "type": "banner"
+      }]
     }
   ]
 }
diff --git a/adapters/beachfront/beachfronttest/supplemental/multi-video.json b/adapters/beachfront/beachfronttest/supplemental/multi-video.json
index 05f02a4d..8ccd0a8d 100644
--- a/adapters/beachfront/beachfronttest/supplemental/multi-video.json
+++ b/adapters/beachfront/beachfronttest/supplemental/multi-video.json
@@ -1,35 +1,34 @@
-{ "mockBidRequest":
-  {
-    "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-    "tmax":1000,
-    "source":{
-      "tid":"61b87329-8790-47b7-90dd-c53ae7ce1723"
+{
+  "mockBidRequest": {
+    "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+    "tmax": 1000,
+    "source": {
+      "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
     },
-    "imp":[
+    "imp": [
       {
-        "id":"multivideo",
-        "ext":{
-          "bidder":{
-            "bidfloor":3.01,
+        "id": "multivideo",
+        "ext": {
+          "bidder": {
+            "bidfloor": 3.01,
             "videoResponseType": "both",
-            "appId":"11bc5dd5-7421-4dd8-c926-40fa653bec76"
+            "appId": "11bc5dd5-7421-4dd8-c926-40fa653bec76"
           }
         },
-        "video":{
-          "mimes":[
-            "video/mp4", "video/webm"
+        "video": {
+          "mimes": [
+            "video/mp4",
+            "video/webm"
           ],
-          "context":"instream",
-          "w":600,
-          "h":450
+          "context": "instream",
+          "w": 600,
+          "h": 450
         }
       }
-
-
     ],
-    "site":{
-      "publisher":{
-        "id":"publisher1"
+    "site": {
+      "publisher": {
+        "id": "publisher1"
       },
       "page": "http://example.com/whatever"
     },
@@ -42,16 +41,15 @@
       "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16"
     }
   },
-
   "httpCalls": [
-      {
+    {
       "expectedRequest": {
         "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76",
         "body": {
           "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
           "imp": [
             {
-              "id":"multivideo",
+              "id": "multivideo",
               "secure": 0,
               "video": {
                 "mimes": [
@@ -118,132 +116,120 @@
           "cur": "USD"
         }
       }
-    }, {
-
+    },
+    {
       "expectedRequest": {
         "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76&prebidserver",
         "body": {
-          "isPrebid":true,
-          "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "imp":[
+          "isPrebid": true,
+          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "imp": [
             {
-              "id":"multivideo",
+              "id": "multivideo",
               "secure": 0,
-              "video":{
-                "mimes":[
+              "video": {
+                "mimes": [
                   "video/mp4",
                   "video/webm"
                 ],
-                "w":600,
-                "h":450
+                "w": 600,
+                "h": 450
               },
-              "bidfloor":3.01
+              "bidfloor": 3.01
             }
           ],
-          "site":{
-            "domain":"example.com",
-            "page":"http://example.com/whatever",
-            "publisher":{
-              "id":"publisher1"
+          "site": {
+            "domain": "example.com",
+            "page": "http://example.com/whatever",
+            "publisher": {
+              "id": "publisher1"
             }
           },
-          "device":{
-            "ua":"Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-            "ip":"192.168.255.255",
-            "devicetype":2
+          "device": {
+            "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
+            "ip": "192.168.255.255",
+            "devicetype": 2
           },
-          "user":{
-            "id":"some-user",
-            "buyeruid":"some-buyer"
+          "user": {
+            "id": "some-user",
+            "buyeruid": "some-buyer"
           },
-          "tmax":1000,
-          "cur":[
+          "tmax": 1000,
+          "cur": [
             "USD"
           ],
-          "source":{
-            "tid":"61b87329-8790-47b7-90dd-c53ae7ce1723"
+          "source": {
+            "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
           }
         }
       },
-
       "mockResponse": {
         "status": 200,
         "body": {
-          "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatBid":[
+          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "seatBid": [
             {
-              "bid":[
+              "bid": [
                 {
-                  "id":"multivideo",
-                  "price":20.0,
-                  "nurl":"https://useast.bfmio.com/getBids?aid=bid:b489a745-e577-4fcb-815d-0b6a1e052ec7:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8231a48d308d0a1f9b4526,0.61&i_type=pre",
-                  "adomain":[
-
-                  ],
-                  "cat":[
-
-                  ],
-                  "attr":[
-
-                  ],
-                  "w":0,
-                  "h":0,
-                  "ext":{
-
-                  }
+                  "id": "multivideo",
+                  "price": 20.0,
+                  "nurl": "https://useast.bfmio.com/getBids?aid=bid:b489a745-e577-4fcb-815d-0b6a1e052ec7:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8231a48d308d0a1f9b4526,0.61&i_type=pre",
+                  "adomain": [],
+                  "cat": [],
+                  "attr": [],
+                  "w": 0,
+                  "h": 0,
+                  "ext": {}
                 }
               ],
-              "group":0,
-              "ext":{
-
-              }
+              "group": 0,
+              "ext": {}
             }
           ]
         }
       }
     }
   ],
-
-  "expectedBids": [
+  "expectedBidResponses": [
     {
-
-      "bid": [
+      "bids": [
         {
-          "id": "multivideoNurlVideo",
-          "impid": "multivideo",
-          "price": 20,
-          "nurl": "https://useast.bfmio.com/getBids?aid=bid:6daefa55-0e8b-4366-b238-bb2de01b0a7c:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8395cb13fe4ef822af7293,3.01&i_type=pre",
-          "crid": "6daefa55-0e8b-4366-b238-bb2de01b0a7c",
-          "w": 600,
-          "h": 450,
-          "ext": {
-            "prebid": {
-              "type": "video"
-            },
-            "bidder": {}
-          }
-        },
+          "bid": {
+            "id": "multivideoAdmVideo",
+            "impid": "multivideo",
+            "price": 20,
+            "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d8231a4254b2eca804965a3,3.01\",\"inventory_id\":\"bid:1680831c-83a2-42a3-a790-a683d780749a:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
+            "adid": "1088",
+            "adomain": [
+              "beachfront.io"
+            ],
+            "cid": "277",
+            "crid": "532",
+            "w": 600,
+            "h": 450
+          },
+          "type": "video"
+        }
+      ],
+      "seat": "beachfront"
+    },
+    {
+      "bids": [
         {
-          "id": "multivideoAdmVideo",
-          "impid": "multivideo",
-          "price": 20,
-          "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d8395cb9107b5524e1fd6be,3.01\",\"inventory_id\":\"bid:f3ff87ed-7d92-48d5-8610-40023c318afc:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
-          "adid": "1088",
-          "adomain": [
-            "beachfront.io"
-          ],
-          "cid": "277",
-          "crid": "532",
-          "w": 600,
-          "h": 450,
-          "ext": {
-            "prebid": {
-              "type": "video"
-            }
-          }
+          "bid": {
+            "id": "multivideoNurlVideo",
+            "impid": "multivideo",
+            "price": 20,
+            "nurl": "https://useast.bfmio.com/getBids?aid=bid:b489a745-e577-4fcb-815d-0b6a1e052ec7:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8231a48d308d0a1f9b4526,0.61&i_type=pre",
+            "crid": "b489a745-e577-4fcb-815d-0b6a1e052ec7",
+            "w": 600,
+            "h": 450,
+            "ext": {}
+          },
+          "type": "video"
         }
       ],
       "seat": "beachfront"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-banner.json b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-banner.json
index 8a9e6b05..fc1bb910 100644
--- a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-banner.json
+++ b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-banner.json
@@ -32,4 +32,4 @@
       "comparison": "literal"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-but-another-good-video.json b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-but-another-good-video.json
index dec0b51b..963a2adc 100644
--- a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-but-another-good-video.json
+++ b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-but-another-good-video.json
@@ -169,4 +169,4 @@
       "comparison": "literal"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-video.json b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-video.json
index a2f028ec..3082ff20 100644
--- a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-video.json
+++ b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-video.json
@@ -38,4 +38,4 @@
       "comparison": "literal"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/adapters/dmx/dmxtest/exemplary/imp-populated-banner.json b/adapters/dmx/dmxtest/exemplary/imp-populated-banner.json
new file mode 100644
index 00000000..f2b30bb4
--- /dev/null
+++ b/adapters/dmx/dmxtest/exemplary/imp-populated-banner.json
@@ -0,0 +1,139 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "app":{
+      "bundle":"302324249",
+      "id":"ed6207cefff74c14878963566683c070",
+      "name":"Skout - iOS Match Buy",
+      "publisher":{
+        "id":"10400"
+      },
+      "storeurl":"https://itunes.apple.com/app/id302324249"
+    },
+    "imp": [
+      {
+        "bidfloor": 0.35,
+        "id": "test-imp-id",
+        "banner": {
+          "w": 300,
+          "h": 250,
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "dmxid": "123454",
+            "publisher_id": "10400"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "",
+        "body": {
+          "id": "test-request-id",
+          "app":{
+            "bundle":"302324249",
+            "id":"ed6207cefff74c14878963566683c070",
+            "name":"Skout - iOS Match Buy",
+            "publisher":{
+              "id":"10400"
+            },
+            "storeurl":"https://itunes.apple.com/app/id302324249"
+          },
+          "imp": [
+            {
+              "bidfloor": 0.35,
+              "id": "test-imp-id",
+              "tagid": "123454",
+              "secure": 1,
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ],
+                "w": 300,
+                "h": 250
+              },
+              "ext": {
+                "bidder": {
+                  "publisher_id": "10400",
+                  "dmxid": "123454"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "958",
+              "bid": [{
+                "id": "7706636740145184841",
+                "impid": "test-imp-id",
+                "price": 1.75,
+                "adid": "29681110",
+                "adm": "<div>banner-ads</div>",
+                "adomain": ["dmx.districtm.io"],
+                "iurl": "https://dmx.districtm.io/b/v2",
+                "cid": "958",
+                "crid": "29681110",
+                "h": 250,
+                "w": 300
+              }]
+            }
+          ],
+          "bidid": "5778926625248726496",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7706636740145184841",
+            "impid": "test-imp-id",
+            "price": 1.75,
+            "adm": "<div>banner-ads</div>",
+            "adid": "29681110",
+            "adomain": ["dmx.districtm.io"],
+            "iurl": "https://dmx.districtm.io/b/v2",
+            "cid": "958",
+            "crid": "29681110",
+            "w": 300,
+            "h": 250
+
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/config/accounts_test.go b/config/accounts_test.go
index ca7e8938..bfca27d8 100644
--- a/config/accounts_test.go
+++ b/config/accounts_test.go
@@ -10,36 +10,12 @@ func TestAccountGDPREnabledForIntegrationType(t *testing.T) {
 	trueValue, falseValue := true, false
 
 	tests := []struct {
-		description          string
-		giveIntegrationType  IntegrationType
-		giveGDPREnabled      *bool
-		giveAMPGDPREnabled   *bool
-		giveAppGDPREnabled   *bool
-		giveVideoGDPREnabled *bool
-		giveWebGDPREnabled   *bool
-		wantEnabled          *bool
+		description         string
+		giveIntegrationType IntegrationType
+		giveGDPREnabled     *bool
+		giveWebGDPREnabled  *bool
+		wantEnabled         *bool
 	}{
-		{
-			description:         "GDPR AMP integration enabled, general GDPR disabled",
-			giveIntegrationType: IntegrationTypeAMP,
-			giveGDPREnabled:     &falseValue,
-			giveAMPGDPREnabled:  &trueValue,
-			wantEnabled:         &trueValue,
-		},
-		{
-			description:         "GDPR App integration enabled, general GDPR disabled",
-			giveIntegrationType: IntegrationTypeApp,
-			giveGDPREnabled:     &falseValue,
-			giveAppGDPREnabled:  &trueValue,
-			wantEnabled:         &trueValue,
-		},
-		{
-			description:          "GDPR Video integration enabled, general GDPR disabled",
-			giveIntegrationType:  IntegrationTypeVideo,
-			giveGDPREnabled:      &falseValue,
-			giveVideoGDPREnabled: &trueValue,
-			wantEnabled:          &trueValue,
-		},
 		{
 			description:         "GDPR Web integration enabled, general GDPR disabled",
 			giveIntegrationType: IntegrationTypeWeb,
@@ -47,13 +23,6 @@ func TestAccountGDPREnabledForIntegrationType(t *testing.T) {
 			giveWebGDPREnabled:  &trueValue,
 			wantEnabled:         &trueValue,
 		},
-		{
-			description:         "Web integration enabled, general GDPR unspecified",
-			giveIntegrationType: IntegrationTypeWeb,
-			giveGDPREnabled:     nil,
-			giveWebGDPREnabled:  &trueValue,
-			wantEnabled:         &trueValue,
-		},
 		{
 			description:         "GDPR Web integration disabled, general GDPR enabled",
 			giveIntegrationType: IntegrationTypeWeb,
@@ -61,13 +30,6 @@ func TestAccountGDPREnabledForIntegrationType(t *testing.T) {
 			giveWebGDPREnabled:  &falseValue,
 			wantEnabled:         &falseValue,
 		},
-		{
-			description:         "GDPR Web integration disabled, general GDPR unspecified",
-			giveIntegrationType: IntegrationTypeWeb,
-			giveGDPREnabled:     nil,
-			giveWebGDPREnabled:  &falseValue,
-			wantEnabled:         &falseValue,
-		},
 		{
 			description:         "GDPR Web integration unspecified, general GDPR disabled",
 			giveIntegrationType: IntegrationTypeWeb,
@@ -95,11 +57,8 @@ func TestAccountGDPREnabledForIntegrationType(t *testing.T) {
 		account := Account{
 			GDPR: AccountGDPR{
 				Enabled: tt.giveGDPREnabled,
-				IntegrationEnabled: AccountGDPRIntegration{
-					AMP:   tt.giveAMPGDPREnabled,
-					App:   tt.giveAppGDPREnabled,
-					Video: tt.giveVideoGDPREnabled,
-					Web:   tt.giveWebGDPREnabled,
+				IntegrationEnabled: AccountIntegration{
+					Web: tt.giveWebGDPREnabled,
 				},
 			},
 		}
@@ -114,3 +73,171 @@ func TestAccountGDPREnabledForIntegrationType(t *testing.T) {
 		}
 	}
 }
+
+func TestAccountCCPAEnabledForIntegrationType(t *testing.T) {
+	trueValue, falseValue := true, false
+
+	tests := []struct {
+		description         string
+		giveIntegrationType IntegrationType
+		giveCCPAEnabled     *bool
+		giveWebCCPAEnabled  *bool
+		wantEnabled         *bool
+	}{
+		{
+			description:         "CCPA Web integration enabled, general CCPA disabled",
+			giveIntegrationType: IntegrationTypeWeb,
+			giveCCPAEnabled:     &falseValue,
+			giveWebCCPAEnabled:  &trueValue,
+			wantEnabled:         &trueValue,
+		},
+		{
+			description:         "CCPA Web integration disabled, general CCPA enabled",
+			giveIntegrationType: IntegrationTypeWeb,
+			giveCCPAEnabled:     &trueValue,
+			giveWebCCPAEnabled:  &falseValue,
+			wantEnabled:         &falseValue,
+		},
+		{
+			description:         "CCPA Web integration unspecified, general CCPA disabled",
+			giveIntegrationType: IntegrationTypeWeb,
+			giveCCPAEnabled:     &falseValue,
+			giveWebCCPAEnabled:  nil,
+			wantEnabled:         &falseValue,
+		},
+		{
+			description:         "CCPA Web integration unspecified, general CCPA enabled",
+			giveIntegrationType: IntegrationTypeWeb,
+			giveCCPAEnabled:     &trueValue,
+			giveWebCCPAEnabled:  nil,
+			wantEnabled:         &trueValue,
+		},
+		{
+			description:         "CCPA Web integration unspecified, general CCPA unspecified",
+			giveIntegrationType: IntegrationTypeWeb,
+			giveCCPAEnabled:     nil,
+			giveWebCCPAEnabled:  nil,
+			wantEnabled:         nil,
+		},
+	}
+
+	for _, tt := range tests {
+		account := Account{
+			CCPA: AccountCCPA{
+				Enabled: tt.giveCCPAEnabled,
+				IntegrationEnabled: AccountIntegration{
+					Web: tt.giveWebCCPAEnabled,
+				},
+			},
+		}
+
+		enabled := account.CCPA.EnabledForIntegrationType(tt.giveIntegrationType)
+
+		if tt.wantEnabled == nil {
+			assert.Nil(t, enabled, tt.description)
+		} else {
+			assert.NotNil(t, enabled, tt.description)
+			assert.Equal(t, *tt.wantEnabled, *enabled, tt.description)
+		}
+	}
+}
+
+func TestAccountIntegrationGetByIntegrationType(t *testing.T) {
+	trueValue, falseValue := true, false
+
+	tests := []struct {
+		description         string
+		giveAMPEnabled      *bool
+		giveAppEnabled      *bool
+		giveVideoEnabled    *bool
+		giveWebEnabled      *bool
+		giveIntegrationType IntegrationType
+		wantEnabled         *bool
+	}{
+		{
+			description:         "AMP integration setting unspecified, returns nil",
+			giveIntegrationType: IntegrationTypeAMP,
+			wantEnabled:         nil,
+		},
+		{
+			description:         "AMP integration disabled, returns false",
+			giveAMPEnabled:      &falseValue,
+			giveIntegrationType: IntegrationTypeAMP,
+			wantEnabled:         &falseValue,
+		},
+		{
+			description:         "AMP integration enabled, returns true",
+			giveAMPEnabled:      &trueValue,
+			giveIntegrationType: IntegrationTypeAMP,
+			wantEnabled:         &trueValue,
+		},
+		{
+			description:         "App integration setting unspecified, returns nil",
+			giveIntegrationType: IntegrationTypeApp,
+			wantEnabled:         nil,
+		},
+		{
+			description:         "App integration disabled, returns false",
+			giveAppEnabled:      &falseValue,
+			giveIntegrationType: IntegrationTypeApp,
+			wantEnabled:         &falseValue,
+		},
+		{
+			description:         "App integration enabled, returns true",
+			giveAppEnabled:      &trueValue,
+			giveIntegrationType: IntegrationTypeApp,
+			wantEnabled:         &trueValue,
+		},
+		{
+			description:         "Video integration setting unspecified, returns nil",
+			giveIntegrationType: IntegrationTypeVideo,
+			wantEnabled:         nil,
+		},
+		{
+			description:         "Video integration disabled, returns false",
+			giveVideoEnabled:    &falseValue,
+			giveIntegrationType: IntegrationTypeVideo,
+			wantEnabled:         &falseValue,
+		},
+		{
+			description:         "Video integration enabled, returns true",
+			giveVideoEnabled:    &trueValue,
+			giveIntegrationType: IntegrationTypeVideo,
+			wantEnabled:         &trueValue,
+		},
+		{
+			description:         "Web integration setting unspecified, returns nil",
+			giveIntegrationType: IntegrationTypeWeb,
+			wantEnabled:         nil,
+		},
+		{
+			description:         "Web integration disabled, returns false",
+			giveWebEnabled:      &falseValue,
+			giveIntegrationType: IntegrationTypeWeb,
+			wantEnabled:         &falseValue,
+		},
+		{
+			description:         "Web integration enabled, returns true",
+			giveWebEnabled:      &trueValue,
+			giveIntegrationType: IntegrationTypeWeb,
+			wantEnabled:         &trueValue,
+		},
+	}
+
+	for _, tt := range tests {
+		accountIntegration := AccountIntegration{
+			AMP:   tt.giveAMPEnabled,
+			App:   tt.giveAppEnabled,
+			Video: tt.giveVideoEnabled,
+			Web:   tt.giveWebEnabled,
+		}
+
+		result := accountIntegration.GetByIntegrationType(tt.giveIntegrationType)
+		if tt.wantEnabled == nil {
+			assert.Nil(t, result, tt.description)
+		} else {
+			assert.NotNil(t, result, tt.description)
+			assert.Equal(t, *tt.wantEnabled, *result, tt.description)
+		}
+	}
+}
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 14293ae2..e2aa72e0 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -93,72 +93,114 @@ func TestCleanOpenRTBRequests(t *testing.T) {
 }
 
 func TestCleanOpenRTBRequestsCCPA(t *testing.T) {
+	trueValue, falseValue := true, false
+
 	testCases := []struct {
 		description         string
 		reqExt              json.RawMessage
 		ccpaConsent         string
-		enforceCCPA         bool
+		ccpaHostEnabled     bool
+		ccpaAccountEnabled  *bool
 		expectDataScrub     bool
 		expectPrivacyLabels pbsmetrics.PrivacyLabels
 	}{
 		{
-			description:     "Feature Flag Enabled - Opt Out",
-			ccpaConsent:     "1-Y-",
-			enforceCCPA:     true,
-			expectDataScrub: true,
+			description:        "Feature Flags Enabled - Opt Out",
+			ccpaConsent:        "1-Y-",
+			ccpaHostEnabled:    true,
+			ccpaAccountEnabled: &trueValue,
+			expectDataScrub:    true,
 			expectPrivacyLabels: pbsmetrics.PrivacyLabels{
 				CCPAProvided: true,
 				CCPAEnforced: true,
 			},
 		},
 		{
-			description:     "Feature Flag Enabled - Opt In",
-			ccpaConsent:     "1-N-",
-			enforceCCPA:     true,
-			expectDataScrub: false,
+			description:        "Feature Flags Enabled - Opt In",
+			ccpaConsent:        "1-N-",
+			ccpaHostEnabled:    true,
+			ccpaAccountEnabled: &trueValue,
+			expectDataScrub:    false,
 			expectPrivacyLabels: pbsmetrics.PrivacyLabels{
 				CCPAProvided: true,
 				CCPAEnforced: false,
 			},
 		},
 		{
-			description:     "Feature Flag Enabled - No Sale Star - Doesn't Scrub",
-			reqExt:          json.RawMessage(`{"prebid":{"nosale":["*"]}}`),
-			ccpaConsent:     "1-Y-",
-			enforceCCPA:     true,
-			expectDataScrub: false,
+			description:        "Feature Flags Enabled - No Sale Star - Doesn't Scrub",
+			reqExt:             json.RawMessage(`{"prebid":{"nosale":["*"]}}`),
+			ccpaConsent:        "1-Y-",
+			ccpaHostEnabled:    true,
+			ccpaAccountEnabled: &trueValue,
+			expectDataScrub:    false,
 			expectPrivacyLabels: pbsmetrics.PrivacyLabels{
 				CCPAProvided: true,
 				CCPAEnforced: false,
 			},
 		},
 		{
-			description:     "Feature Flag Enabled - No Sale Specific Bidder - Doesn't Scrub",
-			reqExt:          json.RawMessage(`{"prebid":{"nosale":["appnexus"]}}`),
-			ccpaConsent:     "1-Y-",
-			enforceCCPA:     true,
-			expectDataScrub: false,
+			description:        "Feature Flags Enabled - No Sale Specific Bidder - Doesn't Scrub",
+			reqExt:             json.RawMessage(`{"prebid":{"nosale":["appnexus"]}}`),
+			ccpaConsent:        "1-Y-",
+			ccpaHostEnabled:    true,
+			ccpaAccountEnabled: &trueValue,
+			expectDataScrub:    false,
 			expectPrivacyLabels: pbsmetrics.PrivacyLabels{
 				CCPAProvided: true,
 				CCPAEnforced: true,
 			},
 		},
 		{
-			description:     "Feature Flag Enabled - No Sale Different Bidder - Scrubs",
-			reqExt:          json.RawMessage(`{"prebid":{"nosale":["rubicon"]}}`),
-			ccpaConsent:     "1-Y-",
-			enforceCCPA:     true,
-			expectDataScrub: true,
+			description:        "Feature Flags Enabled - No Sale Different Bidder - Scrubs",
+			reqExt:             json.RawMessage(`{"prebid":{"nosale":["rubicon"]}}`),
+			ccpaConsent:        "1-Y-",
+			ccpaHostEnabled:    true,
+			ccpaAccountEnabled: &trueValue,
+			expectDataScrub:    true,
 			expectPrivacyLabels: pbsmetrics.PrivacyLabels{
 				CCPAProvided: true,
 				CCPAEnforced: true,
 			},
 		},
 		{
-			description:     "Feature Flag Disabled",
-			ccpaConsent:     "1-Y-",
-			enforceCCPA:     false,
-			expectDataScrub: false,
+			description:        "Feature flags Account CCPA enabled, host CCPA disregarded - Opt Out",
+			ccpaConsent:        "1-Y-",
+			ccpaHostEnabled:    false,
+			ccpaAccountEnabled: &trueValue,
+			expectDataScrub:    true,
+			expectPrivacyLabels: pbsmetrics.PrivacyLabels{
+				CCPAProvided: true,
+				CCPAEnforced: true,
+			},
+		},
+		{
+			description:        "Feature flags Account CCPA disabled, host CCPA disregarded",
+			ccpaConsent:        "1-Y-",
+			ccpaHostEnabled:    true,
+			ccpaAccountEnabled: &falseValue,
+			expectDataScrub:    false,
+			expectPrivacyLabels: pbsmetrics.PrivacyLabels{
+				CCPAProvided: true,
+				CCPAEnforced: false,
+			},
+		},
+		{
+			description:        "Feature flags Account CCPA not specified, host CCPA enabled - Opt Out",
+			ccpaConsent:        "1-Y-",
+			ccpaHostEnabled:    true,
+			ccpaAccountEnabled: nil,
+			expectDataScrub:    true,
+			expectPrivacyLabels: pbsmetrics.PrivacyLabels{
+				CCPAProvided: true,
+				CCPAEnforced: true,
+			},
+		},
+		{
+			description:        "Feature flags Account CCPA not specified, host CCPA disabled",
+			ccpaConsent:        "1-Y-",
+			ccpaHostEnabled:    false,
+			ccpaAccountEnabled: nil,
+			expectDataScrub:    false,
 			expectPrivacyLabels: pbsmetrics.PrivacyLabels{
 				CCPAProvided: true,
 				CCPAEnforced: false,
@@ -175,11 +217,27 @@ func TestCleanOpenRTBRequestsCCPA(t *testing.T) {
 
 		privacyConfig := config.Privacy{
 			CCPA: config.CCPA{
-				Enforce: test.enforceCCPA,
+				Enforce: test.ccpaHostEnabled,
 			},
 		}
 
-		results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, nil, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig, &config.Account{})
+		accountConfig := config.Account{
+			CCPA: config.AccountCCPA{
+				Enabled: test.ccpaAccountEnabled,
+			},
+		}
+
+		results, _, privacyLabels, errs := cleanOpenRTBRequests(
+			context.Background(),
+			req,
+			nil,
+			&emptyUsersync{},
+			map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{},
+			pbsmetrics.Labels{},
+			&permissionsMock{personalInfoAllowed: true},
+			true,
+			privacyConfig,
+			&accountConfig)
 		result := results["appnexus"]
 
 		assert.Nil(t, errs)
@@ -968,7 +1026,6 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 		gdpr                string
 		gdprConsent         string
 		gdprScrub           bool
-		enforceGDPR         bool
 		expectPrivacyLabels pbsmetrics.PrivacyLabels
 	}{
 		{