Repository: prebid/prebid-server
Pull request #2993 (2023-07-31 21:49:55)

Refactor Disabled Bidders List
We ask that bidders removed form Prebid Server remain known to the server for the purposes of nice warning messages. The current implementation doesn't scale as it requires too many test updated when a change is made. Refactoring to make the tests sane again.


Patch:
diff --git a/adapters/adocean/adocean.go b/adapters/adocean/adocean.go
index ce0f78e8..a4e6223b 100644
--- a/adapters/adocean/adocean.go
+++ b/adapters/adocean/adocean.go
@@ -21,7 +21,7 @@ import (
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
-const adapterVersion = "1.2.0"
+const adapterVersion = "1.3.0"
 const maxUriLength = 8000
 const measurementCode = `
 	<script>
@@ -95,13 +95,13 @@ func (a *AdOceanAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 		}
 	}
 
-	var errors []error
+	var reqCreationErrors []error
 	var err error
 	requestsData := make([]*requestData, 0, len(request.Imp))
 	for _, auction := range request.Imp {
 		requestsData, err = a.addNewBid(requestsData, &auction, request, consentString)
 		if err != nil {
-			errors = append(errors, err)
+			reqCreationErrors = append(reqCreationErrors, err)
 		}
 	}
 
@@ -114,7 +114,7 @@ func (a *AdOceanAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 		})
 	}
 
-	return httpRequests, errors
+	return httpRequests, reqCreationErrors
 }
 
 func (a *AdOceanAdapter) addNewBid(
@@ -137,6 +137,12 @@ func (a *AdOceanAdapter) addNewBid(
 		}
 	}
 
+	if adOceanExt.EmitterPrefix == "" {
+		return requestsData, &errortypes.BadInput{
+			Message: "No emitterPrefix param",
+		}
+	}
+
 	addedToExistingRequest := addToExistingRequest(requestsData, &adOceanExt, imp, (request.Test == 1))
 	if addedToExistingRequest {
 		return requestsData, nil
@@ -196,7 +202,7 @@ func (a *AdOceanAdapter) makeURL(
 	slaveSizes map[string]string,
 	consentString string,
 ) (*url.URL, error) {
-	endpointParams := macros.EndpointTemplateParams{Host: params.EmitterDomain}
+	endpointParams := macros.EndpointTemplateParams{Host: params.EmitterPrefix}
 	host, err := macros.ResolveMacros(a.endpointTemplate, endpointParams)
 	if err != nil {
 		return nil, &errortypes.BadInput{
@@ -344,7 +350,7 @@ func (a *AdOceanAdapter) MakeBids(
 	}
 
 	var parsedResponses = adapters.NewBidderResponseWithBidsCapacity(len(auctionIDs))
-	var errors []error
+	var parsingErrors []error
 	var slaveToAuctionIDMap = make(map[string]string, len(auctionIDs))
 
 	for _, auctionFullID := range auctionIDs {
@@ -363,7 +369,7 @@ func (a *AdOceanAdapter) MakeBids(
 			height, _ := strconv.ParseInt(bid.Height, 10, 64)
 			adCode, err := a.prepareAdCodeForBid(bid)
 			if err != nil {
-				errors = append(errors, err)
+				parsingErrors = append(parsingErrors, err)
 				continue
 			}
 
@@ -383,7 +389,7 @@ func (a *AdOceanAdapter) MakeBids(
 		}
 	}
 
-	return parsedResponses, errors
+	return parsedResponses, parsingErrors
 }
 
 func (a *AdOceanAdapter) prepareAdCodeForBid(bid ResponseAdUnit) (string, error) {
diff --git a/adapters/appnexus/appnexus.go b/adapters/appnexus/appnexus.go
index 93a0bf95..ddba6a58 100644
--- a/adapters/appnexus/appnexus.go
+++ b/adapters/appnexus/appnexus.go
@@ -13,6 +13,8 @@ import (
 	"github.com/prebid/openrtb/v19/adcom1"
 	"github.com/prebid/openrtb/v19/openrtb2"
 	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/util/maputil"
+	"github.com/prebid/prebid-server/util/ptrutil"
 	"github.com/prebid/prebid-server/util/randomutil"
 
 	"github.com/prebid/prebid-server/adapters"
@@ -22,8 +24,8 @@ import (
 )
 
 const (
-	defaultPlatformID int = 5
-	maxImpsPerReq         = 10
+	defaultPlatformID = 5
+	maxImpsPerReq     = 10
 )
 
 type adapter struct {
@@ -65,7 +67,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
 	var (
 		shouldGenerateAdPodId *bool
 		uniqueMemberID        string
-		errs                  = make([]error, 0, len(request.Imp))
+		errs                  []error
 	)
 
 	validImps := []openrtb2.Imp{}
@@ -112,7 +114,6 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
 	}
 
 	requestURI := a.uri
-
 	if uniqueMemberID != "" {
 		requestURI = appendMemberId(requestURI, uniqueMemberID)
 	}
@@ -125,10 +126,20 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
 		isVIDEO = 1
 	}
 
-	reqExt, err := a.getRequestExt(request.Ext, isAMP, isVIDEO)
+	reqExt, err := getRequestExt(request.Ext)
+	if err != nil {
+		return nil, append(errs, err)
+	}
+
+	reqExtAppnexus, err := a.getAppnexusExt(reqExt, isAMP, isVIDEO)
 	if err != nil {
 		return nil, append(errs, err)
 	}
+
+	if err := moveSupplyChain(request, reqExt); err != nil {
+		return nil, append(errs, err)
+	}
+
 	// For long form requests if adpodId feature enabled, adpod_id must be sent downstream.
 	// Adpod id is a unique identifier for pod
 	// All impressions in the same pod must have the same pod id in request extension
@@ -136,11 +147,11 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
 	// If impressions number per pod is more than maxImpsPerReq - divide those imps to several requests but keep pod id the same
 	// If  adpodId feature disabled and impressions number per pod is more than maxImpsPerReq  - divide those imps to several requests but do not include ad pod id
 	if isVIDEO == 1 && *shouldGenerateAdPodId {
-		requests, errors := a.buildAdPodRequests(request.Imp, request, reqExt, requestURI.String())
+		requests, errors := a.buildAdPodRequests(request.Imp, request, reqExt, reqExtAppnexus, requestURI.String())
 		return requests, append(errs, errors...)
 	}
 
-	requests, errors := splitRequests(request.Imp, request, reqExt, requestURI.String())
+	requests, errors := splitRequests(request.Imp, request, reqExt, reqExtAppnexus, requestURI.String())
 	return requests, append(errs, errors...)
 }
 
@@ -200,25 +211,43 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest
 	return bidderResponse, errs
 }
 
-func (a *adapter) getRequestExt(ext json.RawMessage, isAMP int, isVIDEO int) (bidReqExt, error) {
-	var reqExt bidReqExt
+func getRequestExt(ext json.RawMessage) (map[string]json.RawMessage, error) {
+	extMap := make(map[string]json.RawMessage)
+
 	if len(ext) > 0 {
-		if err := json.Unmarshal(ext, &reqExt); err != nil {
-			return bidReqExt{}, err
+		if err := json.Unmarshal(ext, &extMap); err != nil {
+			return nil, err
 		}
 	}
-	if reqExt.Appnexus == nil {
-		reqExt.Appnexus = &bidReqExtAppnexus{}
+
+	return extMap, nil
+}
+
+func (a *adapter) getAppnexusExt(extMap map[string]json.RawMessage, isAMP int, isVIDEO int) (bidReqExtAppnexus, error) {
+	var appnexusExt bidReqExtAppnexus
+
+	if appnexusExtJson, exists := extMap["appnexus"]; exists && len(appnexusExtJson) > 0 {
+		if err := json.Unmarshal(appnexusExtJson, &appnexusExt); err != nil {
+			return appnexusExt, err
+		}
 	}
-	includeBrandCategory := reqExt.Prebid.Targeting != nil && reqExt.Prebid.Targeting.IncludeBrandCategory != nil
-	if includeBrandCategory {
-		reqExt.Appnexus.BrandCategoryUniqueness = &includeBrandCategory
-		reqExt.Appnexus.IncludeBrandCategory = &includeBrandCategory
+
+	if prebidJson, exists := extMap["prebid"]; exists {
+		_, valueType, _, err := jsonparser.Get(prebidJson, "targeting", "includebrandcategory")
+		if err != nil && !errors.Is(err, jsonparser.KeyPathNotFoundError) {
+			return appnexusExt, err
+		}
+
+		if valueType == jsonparser.Object {
+			appnexusExt.BrandCategoryUniqueness = ptrutil.ToPtr(true)
+			appnexusExt.IncludeBrandCategory = ptrutil.ToPtr(true)
+		}
 	}
-	reqExt.Appnexus.IsAMP = isAMP
-	reqExt.Appnexus.HeaderBiddingSource = a.hbSource + isVIDEO
 
-	return reqExt, nil
+	appnexusExt.IsAMP = isAMP
+	appnexusExt.HeaderBiddingSource = a.hbSource + isVIDEO
+
+	return appnexusExt, nil
 }
 
 func validateAndBuildAppNexusExt(imp *openrtb2.Imp) (openrtb_ext.ExtImpAppnexus, error) {
@@ -266,7 +295,7 @@ func groupByPods(imps []openrtb2.Imp) map[string]([]openrtb2.Imp) {
 	return podImps
 }
 
-func splitRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, requestExtension bidReqExt, uri string) ([]*adapters.RequestData, []error) {
+func splitRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, requestExt map[string]json.RawMessage, requestExtAppnexus bidReqExtAppnexus, uri string) ([]*adapters.RequestData, []error) {
 	var errs []error
 	// Initial capacity for future array of requests, memory optimization.
 	// Let's say there are 35 impressions and limit impressions per request equals to 10.
@@ -281,14 +310,20 @@ func splitRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, requestExt
 	headers.Add("Content-Type", "application/json;charset=utf-8")
 	headers.Add("Accept", "application/json")
 
-	var err error
-	request.Ext, err = json.Marshal(requestExtension)
+	appnexusExtJson, err := json.Marshal(requestExtAppnexus)
 	if err != nil {
 		errs = append(errs, err)
 	}
 
-	for impsLeft {
+	requestExtClone := maputil.Clone(requestExt)
+	requestExtClone["appnexus"] = appnexusExtJson
 
+	request.Ext, err = json.Marshal(requestExtClone)
+	if err != nil {
+		errs = append(errs, err)
+	}
+
+	for impsLeft {
 		endInd := startInd + maxImpsPerReq
 		if endInd >= len(imps) {
 			endInd = len(imps)
@@ -327,9 +362,11 @@ func buildRequestImp(imp *openrtb2.Imp, appnexusExt *openrtb_ext.ExtImpAppnexus,
 	if appnexusExt.InvCode != "" {
 		imp.TagID = appnexusExt.InvCode
 	}
+
 	if imp.BidFloor <= 0 && appnexusExt.Reserve > 0 {
 		imp.BidFloor = appnexusExt.Reserve // This will be broken for non-USD currency.
 	}
+
 	if imp.Banner != nil {
 		bannerCopy := *imp.Banner
 		if appnexusExt.Position == "above" {
@@ -358,7 +395,7 @@ func buildRequestImp(imp *openrtb2.Imp, appnexusExt *openrtb_ext.ExtImpAppnexus,
 		UsePmtRule:        appnexusExt.UsePaymentRule,
 		PrivateSizes:      appnexusExt.PrivateSizes,
 		ExtInvCode:        appnexusExt.ExtInvCode,
-		ExternalImpId:     appnexusExt.ExternalImpId,
+		ExternalImpID:     appnexusExt.ExternalImpId,
 	}}
 
 	var err error
@@ -413,14 +450,49 @@ func buildDisplayManageVer(req *openrtb2.BidRequest) string {
 	return fmt.Sprintf("%s-%s", source, version)
 }
 
-func (a *adapter) buildAdPodRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, requestExtension bidReqExt, uri string) ([]*adapters.RequestData, []error) {
+// moveSupplyChain moves the supply chain object from source.ext.schain to ext.schain.
+func moveSupplyChain(request *openrtb2.BidRequest, extMap map[string]json.RawMessage) error {
+	if request == nil || request.Source == nil || len(request.Source.Ext) == 0 {
+		return nil
+	}
+
+	sourceExtMap := make(map[string]json.RawMessage)
+	if err := json.Unmarshal(request.Source.Ext, &sourceExtMap); err != nil {
+		return err
+	}
+
+	schainJson, exists := sourceExtMap["schain"]
+	if !exists {
+		return nil
+	}
+
+	delete(sourceExtMap, "schain")
+
+	request.Source = ptrutil.Clone(request.Source)
+
+	if len(sourceExtMap) > 0 {
+		ext, err := json.Marshal(sourceExtMap)
+		if err != nil {
+			return err
+		}
+		request.Source.Ext = ext
+	} else {
+		request.Source.Ext = nil
+	}
+
+	extMap["schain"] = schainJson
+
+	return nil
+}
+
+func (a *adapter) buildAdPodRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, requestExt map[string]json.RawMessage, requestExtAppnexus bidReqExtAppnexus, uri string) ([]*adapters.RequestData, []error) {
 	var errs []error
 	podImps := groupByPods(imps)
 	requests := make([]*adapters.RequestData, 0, len(podImps))
 	for _, podImps := range podImps {
-		requestExtension.Appnexus.AdPodId = fmt.Sprint(a.randomGenerator.GenerateInt63())
+		requestExtAppnexus.AdPodID = fmt.Sprint(a.randomGenerator.GenerateInt63())
 
-		reqs, errors := splitRequests(podImps, request, requestExtension, uri)
+		reqs, errors := splitRequests(podImps, request, requestExt, requestExtAppnexus, uri)
 		requests = append(requests, reqs...)
 		errs = append(errs, errors...)
 	}
diff --git a/adapters/appnexus/models.go b/adapters/appnexus/models.go
index 826451b4..c70f89fa 100644
--- a/adapters/appnexus/models.go
+++ b/adapters/appnexus/models.go
@@ -2,8 +2,6 @@ package appnexus
 
 import (
 	"encoding/json"
-
-	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
 type impExtAppnexus struct {
@@ -13,7 +11,7 @@ type impExtAppnexus struct {
 	UsePmtRule        *bool           `json:"use_pmt_rule,omitempty"`
 	PrivateSizes      json.RawMessage `json:"private_sizes,omitempty"`
 	ExtInvCode        string          `json:"ext_inv_code,omitempty"`
-	ExternalImpId     string          `json:"external_imp_id,omitempty"`
+	ExternalImpID     string          `json:"external_imp_id,omitempty"`
 }
 
 type impExt struct {
@@ -45,11 +43,5 @@ type bidReqExtAppnexus struct {
 	BrandCategoryUniqueness *bool  `json:"brand_category_uniqueness,omitempty"`
 	IsAMP                   int    `json:"is_amp,omitempty"`
 	HeaderBiddingSource     int    `json:"hb_source,omitempty"`
-	AdPodId                 string `json:"adpod_id,omitempty"`
-}
-
-// Full request extension including appnexus extension object
-type bidReqExt struct {
-	openrtb_ext.ExtRequest
-	Appnexus *bidReqExtAppnexus `json:"appnexus,omitempty"`
+	AdPodID                 string `json:"adpod_id,omitempty"`
 }
diff --git a/adapters/ix/ix.go b/adapters/ix/ix.go
index 796fefbb..300858e3 100644
--- a/adapters/ix/ix.go
+++ b/adapters/ix/ix.go
@@ -83,7 +83,7 @@ func (a *IxAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters
 	}
 	requestCopy.Imp = filteredImps
 
-	setSitePublisherId(&requestCopy, uniqueSiteIDs, ixDiag)
+	setPublisherId(&requestCopy, uniqueSiteIDs, ixDiag)
 
 	err := setIxDiagIntoExtRequest(&requestCopy, ixDiag)
 	if err != nil {
@@ -101,7 +101,11 @@ func (a *IxAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters
 	return requests, errs
 }
 
-func setSitePublisherId(requestCopy *openrtb2.BidRequest, uniqueSiteIDs map[string]struct{}, ixDiag *IxDiag) {
+func setPublisherId(requestCopy *openrtb2.BidRequest, uniqueSiteIDs map[string]struct{}, ixDiag *IxDiag) {
+	siteIDs := make([]string, 0, len(uniqueSiteIDs))
+	for key := range uniqueSiteIDs {
+		siteIDs = append(siteIDs, key)
+	}
 	if requestCopy.Site != nil {
 		site := *requestCopy.Site
 		if site.Publisher == nil {
@@ -110,22 +114,33 @@ func setSitePublisherId(requestCopy *openrtb2.BidRequest, uniqueSiteIDs map[stri
 			publisher := *site.Publisher
 			site.Publisher = &publisher
 		}
-
-		siteIDs := make([]string, 0, len(uniqueSiteIDs))
-		for key := range uniqueSiteIDs {
-			siteIDs = append(siteIDs, key)
-		}
 		if len(siteIDs) == 1 {
 			site.Publisher.ID = siteIDs[0]
 		}
-		if len(siteIDs) > 1 {
-			// Sorting siteIDs for predictable output as Go maps don't guarantee order
-			sort.Strings(siteIDs)
-			multipleSiteIDs := strings.Join(siteIDs, ", ")
-			ixDiag.MultipleSiteIds = multipleSiteIDs
-		}
 		requestCopy.Site = &site
 	}
+
+	if requestCopy.App != nil {
+		app := *requestCopy.App
+
+		if app.Publisher == nil {
+			app.Publisher = &openrtb2.Publisher{}
+		} else {
+			publisher := *app.Publisher
+			app.Publisher = &publisher
+		}
+		if len(siteIDs) == 1 {
+			app.Publisher.ID = siteIDs[0]
+		}
+		requestCopy.App = &app
+	}
+
+	if len(siteIDs) > 1 {
+		// Sorting siteIDs for predictable output as Go maps don't guarantee order
+		sort.Strings(siteIDs)
+		multipleSiteIDs := strings.Join(siteIDs, ", ")
+		ixDiag.MultipleSiteIds = multipleSiteIDs
+	}
 }
 
 func unmarshalToIxExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpIx, error) {
diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go
index 49ef7074..c7dc23e1 100644
--- a/endpoints/cookie_sync.go
+++ b/endpoints/cookie_sync.go
@@ -528,7 +528,7 @@ func (p usersyncPrivacy) CCPAAllowsBidderSync(bidder string) bool {
 }
 
 func (p usersyncPrivacy) ActivityAllowsUserSync(bidder string) bool {
-	activityResult := p.activityControl.Allow(privacy.ActivitySyncUser,
+	activityResult := p.activityControl.Evaluate(privacy.ActivitySyncUser,
 		privacy.ScopedName{Scope: privacy.ScopeTypeBidder, Name: bidder})
 	return activityResult == privacy.ActivityAllow
 }
diff --git a/endpoints/setuid.go b/endpoints/setuid.go
index 8f691389..4fae58cb 100644
--- a/endpoints/setuid.go
+++ b/endpoints/setuid.go
@@ -111,7 +111,7 @@ func NewSetUIDEndpoint(cfg *config.Configuration, syncersByBidder map[string]use
 			}
 		}
 
-		userSyncActivityAllowed := activities.Allow(privacy.ActivitySyncUser,
+		userSyncActivityAllowed := activities.Evaluate(privacy.ActivitySyncUser,
 			privacy.ScopedName{Scope: privacy.ScopeTypeBidder, Name: bidderName})
 		if userSyncActivityAllowed == privacy.ActivityDeny {
 			w.WriteHeader(http.StatusUnavailableForLegalReasons)
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index c360ad91..ac004cc4 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -377,6 +377,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderVox:               vox.Builder,
 		openrtb_ext.BidderVrtcal:            vrtcal.Builder,
 		openrtb_ext.BidderXeworks:           xeworks.Builder,
+		openrtb_ext.BidderXtrmqb:            limelightDigital.Builder,
 		openrtb_ext.BidderYahooAds:          yahooAds.Builder,
 		openrtb_ext.BidderYahooAdvertising:  yahooAds.Builder,
 		openrtb_ext.BidderYahooSSP:          yahooAds.Builder,
diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go
index 624a22ce..c863f52a 100644
--- a/exchange/adapter_util.go
+++ b/exchange/adapter_util.go
@@ -86,9 +86,8 @@ func GetActiveBidders(infos config.BidderInfos) map[string]openrtb_ext.BidderNam
 	return activeBidders
 }
 
-// GetDisabledBiddersErrorMessages returns a map of error messages for disabled bidders.
-func GetDisabledBiddersErrorMessages(infos config.BidderInfos) map[string]string {
-	disabledBidders := map[string]string{
+func GetDisabledBidderWarningMessages(infos config.BidderInfos) map[string]string {
+	removed := map[string]string{
 		"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
 		"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 		"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
@@ -100,6 +99,12 @@ func GetDisabledBiddersErrorMessages(infos config.BidderInfos) map[string]string
 		"brightroll":     `Bidder "brightroll" is no longer available in Prebid Server. Please update your configuration.`,
 	}
 
+	return mergeRemovedAndDisabledBidderWarningMessages(removed, infos)
+}
+
+func mergeRemovedAndDisabledBidderWarningMessages(removed map[string]string, infos config.BidderInfos) map[string]string {
+	disabledBidders := removed
+
 	for name, info := range infos {
 		if info.Disabled {
 			msg := fmt.Sprintf(`Bidder "%s" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`, name)
diff --git a/exchange/bidder.go b/exchange/bidder.go
index 03cd81f5..838c46f7 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -548,6 +548,7 @@ func (bidder *bidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re
 
 	if tmaxAdjustments != nil && tmaxAdjustments.IsEnforced {
 		if hasShorterDurationThanTmax(&bidderTmaxCtx{ctx}, *tmaxAdjustments) {
+			bidder.me.RecordTMaxTimeout()
 			return &httpCallInfo{
 				request: req,
 				err:     errTmaxTimeout,
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 7ad15200..70d92c08 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -490,17 +490,14 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog
 	e.bidValidationEnforcement.SetBannerCreativeMaxSize(r.Account.Validations)
 
 	// Build the response
-	bidResponse, err := e.buildBidResponse(ctx, liveAdapters, adapterBids, r.BidRequestWrapper.BidRequest, adapterExtra, auc, bidResponseExt, cacheInstructions.returnCreative, r.ImpExtInfoMap, r.PubID, errs)
-
+	bidResponse := e.buildBidResponse(ctx, liveAdapters, adapterBids, r.BidRequestWrapper.BidRequest, adapterExtra, auc, bidResponseExt, cacheInstructions.returnCreative, r.ImpExtInfoMap, r.PubID, errs)
 	bidResponse = adservertargeting.Apply(r.BidRequestWrapper, r.ResolvedBidRequest, bidResponse, r.QueryParams, bidResponseExt, r.Account.TruncateTargetAttribute)
 
 	bidResponse.Ext, err = encodeBidResponseExt(bidResponseExt)
-
-	bidResponseExt = setSeatNonBid(bidResponseExt, seatNonBids)
-
 	if err != nil {
 		return nil, err
 	}
+	bidResponseExt = setSeatNonBid(bidResponseExt, seatNonBids)
 
 	return &AuctionResponse{
 		BidResponse:    bidResponse,
@@ -880,9 +877,8 @@ func errsToBidderWarnings(errs []error) []openrtb_ext.ExtBidderMessage {
 }
 
 // This piece takes all the bids supplied by the adapters and crafts an openRTB response to send back to the requester
-func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_ext.BidderName, adapterSeatBids map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, bidRequest *openrtb2.BidRequest, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, auc *auction, bidResponseExt *openrtb_ext.ExtBidResponse, returnCreative bool, impExtInfoMap map[string]ImpExtInfo, pubID string, errList []error) (*openrtb2.BidResponse, error) {
+func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_ext.BidderName, adapterSeatBids map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, bidRequest *openrtb2.BidRequest, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, auc *auction, bidResponseExt *openrtb_ext.ExtBidResponse, returnCreative bool, impExtInfoMap map[string]ImpExtInfo, pubID string, errList []error) *openrtb2.BidResponse {
 	bidResponse := new(openrtb2.BidResponse)
-	var err error
 
 	bidResponse.ID = bidRequest.ID
 	if len(liveAdapters) == 0 {
@@ -903,7 +899,7 @@ func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_
 	}
 	bidResponse.SeatBid = seatBids
 
-	return bidResponse, err
+	return bidResponse
 }
 
 func encodeBidResponseExt(bidResponseExt *openrtb_ext.ExtBidResponse) ([]byte, error) {
diff --git a/exchange/utils.go b/exchange/utils.go
index e70f5249..8f6f00b2 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -153,7 +153,7 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context,
 
 		// fetchBids activity
 		scopedName := privacy.ScopedName{Scope: privacy.ScopeTypeBidder, Name: bidderRequest.BidderName.String()}
-		fetchBidsActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityFetchBids, scopedName)
+		fetchBidsActivityAllowed := auctionReq.Activities.Evaluate(privacy.ActivityFetchBids, scopedName)
 		if fetchBidsActivityAllowed == privacy.ActivityDeny {
 			// skip the call to a bidder if fetchBids activity is not allowed
 			// do not add this bidder to allowedBidderRequests
@@ -173,7 +173,7 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context,
 			}
 		}
 
-		passIDActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitUserFPD, scopedName)
+		passIDActivityAllowed := auctionReq.Activities.Evaluate(privacy.ActivityTransmitUserFPD, scopedName)
 		if passIDActivityAllowed == privacy.ActivityDeny {
 			privacyEnforcement.UFPD = true
 		} else {
@@ -190,7 +190,7 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context,
 			privacyEnforcement.CCPA = ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String())
 		}
 
-		passGeoActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitPreciseGeo, scopedName)
+		passGeoActivityAllowed := auctionReq.Activities.Evaluate(privacy.ActivityTransmitPreciseGeo, scopedName)
 		if passGeoActivityAllowed == privacy.ActivityDeny {
 			privacyEnforcement.PreciseGeo = true
 		} else {
diff --git a/metrics/config/metrics.go b/metrics/config/metrics.go
index 0cf0533d..bf173253 100644
--- a/metrics/config/metrics.go
+++ b/metrics/config/metrics.go
@@ -80,6 +80,12 @@ func (me *MultiMetricsEngine) RecordConnectionAccept(success bool) {
 	}
 }
 
+func (me *MultiMetricsEngine) RecordTMaxTimeout() {
+	for _, thisME := range *me {
+		thisME.RecordTMaxTimeout()
+	}
+}
+
 func (me *MultiMetricsEngine) RecordConnectionClose(success bool) {
 	for _, thisME := range *me {
 		thisME.RecordConnectionClose(success)
@@ -391,6 +397,10 @@ func (me *NilMetricsEngine) RecordRequest(labels metrics.Labels) {
 func (me *NilMetricsEngine) RecordConnectionAccept(success bool) {
 }
 
+// RecordTMaxTimeout as a noop
+func (me *NilMetricsEngine) RecordTMaxTimeout() {
+}
+
 // RecordConnectionClose as a noop
 func (me *NilMetricsEngine) RecordConnectionClose(success bool) {
 }
diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go
index 64726e30..382dc64c 100644
--- a/metrics/go_metrics.go
+++ b/metrics/go_metrics.go
@@ -14,6 +14,7 @@ import (
 type Metrics struct {
 	MetricsRegistry                metrics.Registry
 	ConnectionCounter              metrics.Counter
+	TMaxTimeoutCounter             metrics.Counter
 	ConnectionAcceptErrorMeter     metrics.Meter
 	ConnectionCloseErrorMeter      metrics.Meter
 	ImpMeter                       metrics.Meter
@@ -288,6 +289,7 @@ func getModuleNames(moduleStageNames map[string][]string) []string {
 func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, disableAccountMetrics config.DisabledMetrics, syncerKeys []string, moduleStageNames map[string][]string) *Metrics {
 	newMetrics := NewBlankMetrics(registry, exchanges, disableAccountMetrics, moduleStageNames)
 	newMetrics.ConnectionCounter = metrics.GetOrRegisterCounter("active_connections", registry)
+	newMetrics.TMaxTimeoutCounter = metrics.GetOrRegisterCounter("tmax_timeout", registry)
 	newMetrics.ConnectionAcceptErrorMeter = metrics.GetOrRegisterMeter("connection_accept_errors", registry)
 	newMetrics.ConnectionCloseErrorMeter = metrics.GetOrRegisterMeter("connection_close_errors", registry)
 	newMetrics.ImpMeter = metrics.GetOrRegisterMeter("imps_requested", registry)
@@ -713,6 +715,10 @@ func (me *Metrics) RecordConnectionAccept(success bool) {
 	}
 }
 
+func (m *Metrics) RecordTMaxTimeout() {
+	m.TMaxTimeoutCounter.Inc(1)
+}
+
 func (me *Metrics) RecordConnectionClose(success bool) {
 	if success {
 		me.ConnectionCounter.Dec(1)
diff --git a/metrics/metrics.go b/metrics/metrics.go
index 214e7c1d..c30f8167 100644
--- a/metrics/metrics.go
+++ b/metrics/metrics.go
@@ -421,6 +421,7 @@ func SyncerSetUidStatuses() []SyncerSetUidStatus {
 // is generally not useful.
 type MetricsEngine interface {
 	RecordConnectionAccept(success bool)
+	RecordTMaxTimeout()
 	RecordConnectionClose(success bool)
 	RecordRequest(labels Labels)                           // ignores adapter. only statusOk and statusErr fom status
 	RecordImps(labels ImpLabels)                           // RecordImps across openRTB2 engines that support the 'Native' Imp Type
diff --git a/metrics/metrics_mock.go b/metrics/metrics_mock.go
index 0ce238c5..a518b98d 100644
--- a/metrics/metrics_mock.go
+++ b/metrics/metrics_mock.go
@@ -22,6 +22,11 @@ func (me *MetricsEngineMock) RecordConnectionAccept(success bool) {
 	me.Called(success)
 }
 
+// RecordTMaxTimeout mock
+func (me *MetricsEngineMock) RecordTMaxTimeout() {
+	me.Called()
+}
+
 // RecordConnectionClose mock
 func (me *MetricsEngineMock) RecordConnectionClose(success bool) {
 	me.Called(success)
diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go
index f9d0c4d9..c57ba221 100644
--- a/metrics/prometheus/prometheus.go
+++ b/metrics/prometheus/prometheus.go
@@ -18,6 +18,7 @@ type Metrics struct {
 	Gatherer   *prometheus.Registry
 
 	// General Metrics
+	tmaxTimeout                  prometheus.Counter
 	connectionsClosed            prometheus.Counter
 	connectionsError             *prometheus.CounterVec
 	connectionsOpened            prometheus.Counter
@@ -197,6 +198,10 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet
 		"connections_opened",
 		"Count of successful connections opened to Prebid Server.")
 
+	metrics.tmaxTimeout = newCounterWithoutLabels(cfg, reg,
+		"tmax_timeout",
+		"Count of requests rejected due to Tmax timeout exceed.")
+
 	metrics.cookieSync = newCounter(cfg, reg,
 		"cookie_sync_requests",
 		"Count of cookie sync requests to Prebid Server.",
@@ -685,6 +690,10 @@ func (m *Metrics) RecordConnectionAccept(success bool) {
 	}
 }
 
+func (m *Metrics) RecordTMaxTimeout() {
+	m.tmaxTimeout.Inc()
+}
+
 func (m *Metrics) RecordConnectionClose(success bool) {
 	if success {
 		m.connectionsClosed.Inc()
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index b42966ee..26eaa422 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -274,6 +274,7 @@ const (
 	BidderVox               BidderName = "vox"
 	BidderVrtcal            BidderName = "vrtcal"
 	BidderXeworks           BidderName = "xeworks"
+	BidderXtrmqb            BidderName = "xtrmqb"
 	BidderYahooAds          BidderName = "yahooAds"
 	BidderYahooAdvertising  BidderName = "yahooAdvertising"
 	BidderYahooSSP          BidderName = "yahoossp"
@@ -476,6 +477,7 @@ func CoreBidderNames() []BidderName {
 		BidderVox,
 		BidderVrtcal,
 		BidderXeworks,
+		BidderXtrmqb,
 		BidderYahooAds,
 		BidderYahooAdvertising,
 		BidderYahooSSP,
diff --git a/openrtb_ext/imp_adocean.go b/openrtb_ext/imp_adocean.go
index e690e929..1dd64d28 100644
--- a/openrtb_ext/imp_adocean.go
+++ b/openrtb_ext/imp_adocean.go
@@ -1,7 +1,7 @@
 package openrtb_ext
 
 type ExtImpAdOcean struct {
-	EmitterDomain string `json:"emiter"`
+	EmitterPrefix string `json:"emitterPrefix"`
 	MasterID      string `json:"masterId"`
 	SlaveID       string `json:"slaveId"`
 }
diff --git a/privacy/enforcer.go b/privacy/enforcer.go
index bcd9e948..3a360c5d 100644
--- a/privacy/enforcer.go
+++ b/privacy/enforcer.go
@@ -2,8 +2,9 @@ package privacy
 
 import (
 	"fmt"
-	"github.com/prebid/prebid-server/config"
 	"strings"
+
+	"github.com/prebid/prebid-server/config"
 )
 
 type ActivityResult int
@@ -86,15 +87,24 @@ func buildEnforcementPlan(activity config.Activity) (ActivityPlan, error) {
 }
 
 func activityRulesToEnforcementRules(rules []config.ActivityRule) ([]ActivityRule, error) {
-	enfRules := make([]ActivityRule, 0)
+	var enfRules []ActivityRule
+
 	for _, r := range rules {
-		cmpName, err := conditionToRuleComponentName(r.Condition.ComponentName)
+		var result ActivityResult
+		if r.Allow {
+			result = ActivityAllow
+		} else {
+			result = ActivityDeny
+		}
+
+		componentName, err := conditionToRuleComponentNames(r.Condition.ComponentName)
 		if err != nil {
 			return nil, err
 		}
+
 		er := ComponentEnforcementRule{
-			allowed:       r.Allow,
-			componentName: cmpName,
+			result:        result,
+			componentName: componentName,
 			componentType: r.Condition.ComponentType,
 		}
 		enfRules = append(enfRules, er)
@@ -102,7 +112,7 @@ func activityRulesToEnforcementRules(rules []config.ActivityRule) ([]ActivityRul
 	return enfRules, nil
 }
 
-func conditionToRuleComponentName(conditions []string) ([]ScopedName, error) {
+func conditionToRuleComponentNames(conditions []string) ([]ScopedName, error) {
 	sn := make([]ScopedName, 0)
 	for _, condition := range conditions {
 		scope, err := NewScopedName(condition)
@@ -124,14 +134,14 @@ func activityDefaultToDefaultResult(activityDefault *bool) ActivityResult {
 	return ActivityDeny
 }
 
-func (e ActivityControl) Allow(activity Activity, target ScopedName) ActivityResult {
+func (e ActivityControl) Evaluate(activity Activity, target ScopedName) ActivityResult {
 	plan, planDefined := e.plans[activity]
 
 	if !planDefined {
 		return ActivityAbstain
 	}
 
-	return plan.Allow(target)
+	return plan.Evaluate(target)
 }
 
 type ActivityPlan struct {
@@ -139,9 +149,9 @@ type ActivityPlan struct {
 	rules         []ActivityRule
 }
 
-func (p ActivityPlan) Allow(target ScopedName) ActivityResult {
+func (p ActivityPlan) Evaluate(target ScopedName) ActivityResult {
 	for _, rule := range p.rules {
-		result := rule.Allow(target)
+		result := rule.Evaluate(target)
 		if result == ActivityDeny || result == ActivityAllow {
 			return result
 		}
@@ -150,51 +160,57 @@ func (p ActivityPlan) Allow(target ScopedName) ActivityResult {
 }
 
 type ActivityRule interface {
-	Allow(target ScopedName) ActivityResult
+	Evaluate(target ScopedName) ActivityResult
 }
 
 type ComponentEnforcementRule struct {
+	result        ActivityResult
 	componentName []ScopedName
 	componentType []string
-	// include gppSectionId from 3.5
-	// include geo from 3.5
-	allowed bool
 }
 
-func (r ComponentEnforcementRule) Allow(target ScopedName) ActivityResult {
-	if len(r.componentName) == 0 && len(r.componentType) == 0 {
+func (r ComponentEnforcementRule) Evaluate(target ScopedName) ActivityResult {
+	if matched := evaluateComponentName(target, r.componentName); !matched {
+		return ActivityAbstain
+	}
+
+	if matched := evaluateComponentType(target, r.componentType); !matched {
 		return ActivityAbstain
 	}
 
-	nameClauseExists := len(r.componentName) > 0
-	typeClauseExists := len(r.componentType) > 0
+	return r.result
+}
 
-	componentNameFound := false
-	for _, scope := range r.componentName {
-		if strings.EqualFold(scope.Scope, target.Scope) &&
-			(scope.Name == "*" || strings.EqualFold(scope.Name, target.Name)) {
-			componentNameFound = true
-			break
-		}
+func evaluateComponentName(target ScopedName, componentNames []ScopedName) bool {
+	// no clauses are considered a match
+	if len(componentNames) == 0 {
+		return true
 	}
 
-	componentTypeFound := false
-	for _, componentType := range r.componentType {
-		if strings.EqualFold(componentType, target.Scope) {
-			componentTypeFound = true
-			break
+	// if there are clauses, at least one needs to match
+	for _, n := range componentNames {
+		if strings.EqualFold(n.Scope, target.Scope) && (n.Name == "*" || strings.EqualFold(n.Name, target.Name)) {
+			return true
 		}
 	}
-	// behavior if rule matches: can be either true=allow or false=deny. result is abstain if the rule doesn't match
-	matchFound := (componentNameFound || !nameClauseExists) && (componentTypeFound || !typeClauseExists)
-	if matchFound {
-		if r.allowed {
-			return ActivityAllow
-		} else {
-			return ActivityDeny
+
+	return false
+}
+
+func evaluateComponentType(target ScopedName, componentTypes []string) bool {
+	// no clauses are considered a match
+	if len(componentTypes) == 0 {
+		return true
+	}
+
+	// if there are clauses, at least one needs to match
+	for _, s := range componentTypes {
+		if strings.EqualFold(s, target.Scope) {
+			return true
 		}
 	}
-	return ActivityAbstain
+
+	return false
 }
 
 type ScopedName struct {
diff --git a/router/router.go b/router/router.go
index 12bfbf59..fcf674b4 100644
--- a/router/router.go
+++ b/router/router.go
@@ -190,7 +190,7 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R
 	}
 
 	activeBidders := exchange.GetActiveBidders(cfg.BidderInfos)
-	disabledBidders := exchange.GetDisabledBiddersErrorMessages(cfg.BidderInfos)
+	disabledBidders := exchange.GetDisabledBidderWarningMessages(cfg.BidderInfos)
 
 	defaultAliases, defReqJSON := readDefaultRequest(cfg.DefReqConfig)
 	if err := validateDefaultAliases(defaultAliases); err != nil {
diff --git a/static/bidder-info/adocean.yaml b/static/bidder-info/adocean.yaml
index 50013095..3932a7a7 100644
--- a/static/bidder-info/adocean.yaml
+++ b/static/bidder-info/adocean.yaml
@@ -1,4 +1,4 @@
-endpoint: "https://{{.Host}}"
+endpoint: "https://{{.Host}}.adocean.pl"
 maintainer:
   email: "aoteam@gemius.com"
 gvlVendorID: 328
diff --git a/static/bidder-info/xtrmqb.yaml b/static/bidder-info/xtrmqb.yaml
new file mode 100644
index 00000000..c1f0da3f
--- /dev/null
+++ b/static/bidder-info/xtrmqb.yaml
@@ -0,0 +1,16 @@
+endpoint: "http://ads-pbs.ortb.tech/openrtb/{{.PublisherID}}?host={{.Host}}"
+maintainer:
+  email: "engineering@project-limelight.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - audio
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - audio
+      - native
diff --git a/static/bidder-params/adocean.json b/static/bidder-params/adocean.json
index 7530c647..a3c5cbc9 100644
--- a/static/bidder-params/adocean.json
+++ b/static/bidder-params/adocean.json
@@ -6,9 +6,14 @@
   "properties": {
     "emiter": {
       "type": "string",
-      "description": "AdOcean emiter",
+      "description": "Deprecated, use emitterPrefix instead. AdOcean emiter",
       "pattern": ".+"
     },
+    "emitterPrefix": {
+      "type": "string",
+      "description": "AdOcean emitter prefix",
+      "pattern": "^[\\w\\-]+$"
+    },
     "masterId": {
       "type": "string",
       "description": "Master's id",
@@ -20,5 +25,8 @@
       "pattern": "^adocean[\\w.]+$"
     }
   },
-  "required": ["emiter", "masterId", "slaveId"]
+  "oneOf": [
+    { "required": ["emiter", "masterId", "slaveId"] },
+    { "required": ["emitterPrefix", "masterId", "slaveId"] }
+  ]
 }
diff --git a/static/bidder-params/xtrmqb.json b/static/bidder-params/xtrmqb.json
new file mode 100644
index 00000000..59e711e9
--- /dev/null
+++ b/static/bidder-params/xtrmqb.json
@@ -0,0 +1,23 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "XTRM QB Adapter Params",
+  "description": "A schema which validates params accepted by the XTRM QB adapter",
+  "type": "object",
+
+  "properties": {
+    "host": {
+      "type": "string",
+      "description": "Ad network's RTB host",
+      "format": "hostname",
+      "pattern": "^.+\\..+$"
+    },
+    "publisherId": {
+      "type": ["integer", "string"],
+      "description": "Publisher ID",
+      "minimum": 1,
+      "pattern": "^[1-9][0-9]*$"
+    }
+  },
+
+  "required": ["host", "publisherId"]
+}


Test patch:
diff --git a/adapters/adocean/adocean_test.go b/adapters/adocean/adocean_test.go
index 47fe5848..8d646cb9 100644
--- a/adapters/adocean/adocean_test.go
+++ b/adapters/adocean/adocean_test.go
@@ -11,7 +11,7 @@ import (
 
 func TestJsonSamples(t *testing.T) {
 	bidder, buildErr := Builder(openrtb_ext.BidderAdOcean, config.Adapter{
-		Endpoint: "https://{{.Host}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+		Endpoint: "https://{{.Host}}.adocean.pl"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
 
 	if buildErr != nil {
 		t.Fatalf("Builder returned unexpected error %v", buildErr)
diff --git a/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json b/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json
index bdb5d969..f70bc467 100644
--- a/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json
+++ b/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json
@@ -9,7 +9,7 @@
       "id": "ao-test",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaozpniqismex"
         }
@@ -27,7 +27,7 @@
       "id": "secod-twelve",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaowafpdwlrks"
         }
@@ -72,7 +72,7 @@
   },
   "httpCalls": [{
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Asecod-twelve&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250_320x600&devmake=&devmodel=&devos=&devosv=&dpidmd5=f2ba45ece57cff9477d5a8083b138c9g&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Asecod-twelve&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250_320x600&devmake=&devmodel=&devos=&devosv=&dpidmd5=f2ba45ece57cff9477d5a8083b138c9g&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
     },
     "mockResponse": {
       "status": 200,
diff --git a/adapters/adocean/adoceantest/exemplary/single-banner-impression.json b/adapters/adocean/adoceantest/exemplary/single-banner-impression.json
index d4fabebb..19b95281 100644
--- a/adapters/adocean/adoceantest/exemplary/single-banner-impression.json
+++ b/adapters/adocean/adoceantest/exemplary/single-banner-impression.json
@@ -10,7 +10,7 @@
         "id": "ao-test",
         "ext": {
           "bidder": {
-            "emiter": "myao.adocean.pl",
+            "emitterPrefix": "myao",
             "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
             "slaveId": "adoceanmyaozpniqismex"
           }
@@ -60,7 +60,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&ifa=f2ba45ece57cff9477d5a8083b138c9a&nc=1&nosecure=1&pbsrv_v=1.2.0"
+        "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&ifa=f2ba45ece57cff9477d5a8083b138c9a&nc=1&nosecure=1&pbsrv_v=1.3.0"
       },
       "mockResponse": {
         "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/app.json b/adapters/adocean/adoceantest/supplemental/app.json
index efb53692..994495d5 100644
--- a/adapters/adocean/adoceantest/supplemental/app.json
+++ b/adapters/adocean/adoceantest/supplemental/app.json
@@ -10,7 +10,7 @@
         "id": "ao-test",
         "ext": {
           "bidder": {
-            "emiter": "myao.adocean.pl",
+            "emitterPrefix": "myao",
             "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
             "slaveId": "adoceanmyaozpniqismex"
           }
@@ -54,7 +54,7 @@
   "httpCalls": [
     {
         "expectedRequest": {
-          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&app=1&appbundle=12345&appdomain=example.com&appname=Weather+App&devmake=&devmodel=&devos=iOS&devosv=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&ifa=f2ba45ece57cff9477d5a8083b138c9a&nc=1&nosecure=1&pbsrv_v=1.2.0"
+          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&app=1&appbundle=12345&appdomain=example.com&appname=Weather+App&devmake=&devmodel=&devos=iOS&devosv=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&ifa=f2ba45ece57cff9477d5a8083b138c9a&nc=1&nosecure=1&pbsrv_v=1.3.0"
         },
       "mockResponse": {
         "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/bad-response.json b/adapters/adocean/adoceantest/supplemental/bad-response.json
index 62d23669..43e62d6f 100644
--- a/adapters/adocean/adoceantest/supplemental/bad-response.json
+++ b/adapters/adocean/adoceantest/supplemental/bad-response.json
@@ -10,7 +10,7 @@
         "id": "ao-test",
         "ext": {
           "bidder": {
-            "emiter": "myao.adocean.pl",
+            "emitterPrefix": "myao",
             "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
             "slaveId": "adoceanmyaozpniqismex"
           }
@@ -49,7 +49,7 @@
   "httpCalls": [
     {
         "expectedRequest": {
-          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
         },
       "mockResponse": {
         "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/emiter-param-error.json b/adapters/adocean/adoceantest/supplemental/emiter-param-error.json
new file mode 100644
index 00000000..154c92e8
--- /dev/null
+++ b/adapters/adocean/adoceantest/supplemental/emiter-param-error.json
@@ -0,0 +1,55 @@
+{
+  "mockBidRequest": {
+    "id": "9ed903f4-383d-406b-8011-4f06526cb02c",
+    "source": {
+      "tid": "9ed903f4-383d-406b-8011-4f06526cb02c"
+    },
+    "tmax": 1000,
+    "imp": [
+      {
+        "id": "ao-test",
+        "ext": {
+          "bidder": {
+            "emiter": "myao.adocean.pl",
+            "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
+            "slaveId": "adoceanmyaozpniqismex"
+          }
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        }
+      }
+    ],
+    "test": 1,
+    "ext": {
+      "prebid": {
+        "targeting": {
+          "includewinners": true,
+          "includebidderkeys": false
+        }
+      }
+    },
+    "site": {
+      "publisher": {
+        "id": "1"
+      },
+      "page": "http://example.com/test.html"
+    },
+    "device": {
+      "w": 1280,
+      "h": 720,
+      "ip": "192.168.1.1"
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "No emitterPrefix param",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/adocean/adoceantest/supplemental/encode-error.json b/adapters/adocean/adoceantest/supplemental/encode-error.json
index c5dce777..98b977fd 100644
--- a/adapters/adocean/adoceantest/supplemental/encode-error.json
+++ b/adapters/adocean/adoceantest/supplemental/encode-error.json
@@ -10,7 +10,7 @@
         "id": "ao-test",
         "ext": {
           "bidder": {
-            "emiter": "myao.adocean.pl",
+            "emitterPrefix": "myao",
             "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
             "slaveId": "adoceanmyaozpniqismex"
           }
@@ -49,7 +49,7 @@
   "httpCalls": [
     {
         "expectedRequest": {
-          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
         },
       "mockResponse": {
         "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/network-error.json b/adapters/adocean/adoceantest/supplemental/network-error.json
index 567179ab..c18ddf16 100644
--- a/adapters/adocean/adoceantest/supplemental/network-error.json
+++ b/adapters/adocean/adoceantest/supplemental/network-error.json
@@ -10,7 +10,7 @@
         "id": "ao-test",
         "ext": {
           "bidder": {
-            "emiter": "myao.adocean.pl",
+            "emitterPrefix": "myao",
             "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
             "slaveId": "adoceanmyaozpniqismex"
           }
@@ -49,7 +49,7 @@
   "httpCalls": [
     {
         "expectedRequest": {
-          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
         },
       "mockResponse": {
         "status": 500,
diff --git a/adapters/adocean/adoceantest/supplemental/no-bid.json b/adapters/adocean/adoceantest/supplemental/no-bid.json
index 19778b1e..caf2cc9e 100644
--- a/adapters/adocean/adoceantest/supplemental/no-bid.json
+++ b/adapters/adocean/adoceantest/supplemental/no-bid.json
@@ -9,7 +9,7 @@
       "id": "ao-test",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaozpniqismex"
         }
@@ -24,7 +24,7 @@
       "id": "ao-test-two",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaowafpdwlrks"
         }
@@ -39,7 +39,7 @@
       "id": "ao-test-three",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaowafpdwlrks"
         }
@@ -83,7 +83,7 @@
   },
   "httpCalls": [{
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
     },
     "mockResponse": {
       "status": 200,
@@ -108,7 +108,7 @@
     }
   }, {
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
     },
     "mockResponse": {
       "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/no-sizes.json b/adapters/adocean/adoceantest/supplemental/no-sizes.json
index 25503190..465698fd 100644
--- a/adapters/adocean/adoceantest/supplemental/no-sizes.json
+++ b/adapters/adocean/adoceantest/supplemental/no-sizes.json
@@ -9,7 +9,7 @@
       "id": "ao-test",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaozpniqismex"
         }
@@ -18,7 +18,7 @@
       "id": "ao-test-two",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaowafpdwlrks"
         }
@@ -30,7 +30,7 @@
       "id": "ao-test-three",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaowafpdwlrks"
         }
@@ -72,7 +72,7 @@
   },
   "httpCalls": [{
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
     },
     "mockResponse": {
       "status": 200,
@@ -106,7 +106,7 @@
     }
   }, {
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
     },
     "mockResponse": {
       "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/requests-merge.json b/adapters/adocean/adoceantest/supplemental/requests-merge.json
index eed67321..9021bf66 100644
--- a/adapters/adocean/adoceantest/supplemental/requests-merge.json
+++ b/adapters/adocean/adoceantest/supplemental/requests-merge.json
@@ -9,7 +9,7 @@
       "id": "ao-test",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaozpniqismex"
         }
@@ -24,7 +24,7 @@
       "id": "ao-test-two",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaowafpdwlrks"
         }
@@ -39,7 +39,7 @@
       "id": "ao-test-three",
       "ext": {
         "bidder": {
-          "emiter": "myao.adocean.pl",
+          "emitterPrefix": "myao",
           "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
           "slaveId": "adoceanmyaowafpdwlrks"
         }
@@ -83,7 +83,7 @@
   },
   "httpCalls": [{
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
     },
     "mockResponse": {
       "status": 200,
@@ -117,7 +117,7 @@
     }
   }, {
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.2.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0"
     },
     "mockResponse": {
       "status": 200,
diff --git a/adapters/adocean/params_test.go b/adapters/adocean/params_test.go
index 1a88c471..18625b5e 100644
--- a/adapters/adocean/params_test.go
+++ b/adapters/adocean/params_test.go
@@ -34,17 +34,20 @@ func TestInvalidParams(t *testing.T) {
 }
 
 var validParams = []string{
+	`{"emitterPrefix": "myao", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`,
 	`{"emiter": "myao.adocean.pl", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`,
 }
 
 var invalidParams = []string{
 	`{}`,
-	`{"masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`,
+	`{"emitterPrefix": "myao", "slaveId": "adoceanmyaozpniqismex"}`,
+	`{"emitterPrefix": "myao", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7"}`,
+	`{"emitterPrefix": "", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`,
+	`{"emitterPrefix": "myao", "", "slaveId": "adoceanmyaozpniqismex"}`,
+	`{"emitterPrefix": "myao", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": ""}`,
+	`{"emitterPrefix": "myao", "masterId": "tmYF.DMl7Z utQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`,
+	`{"emitterPrefix": "myao", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmy iqismex"}`,
+	`{"emitterPrefix": "myao.adocean.pl", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`,
 	`{"emiter": "myao.adocean.pl", "slaveId": "adoceanmyaozpniqismex"}`,
-	`{"emiter": "myao.adocean.pl", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7"}`,
 	`{"emiter": "", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`,
-	`{"emiter": "myao.adocean.pl", "", "slaveId": "adoceanmyaozpniqismex"}`,
-	`{"emiter": "myao.adocean.pl", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": ""}`,
-	`{"emiter": "myao.adocean.pl", "masterId": "tmYF.DMl7Z utQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`,
-	`{"emiter": "myao.adocean.pl", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmy iqismex"}`,
 }
diff --git a/adapters/appnexus/appnexus_test.go b/adapters/appnexus/appnexus_test.go
index e6ba0109..bb04b61b 100644
--- a/adapters/appnexus/appnexus_test.go
+++ b/adapters/appnexus/appnexus_test.go
@@ -8,6 +8,7 @@ import (
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestJsonSamples(t *testing.T) {
@@ -26,7 +27,8 @@ func TestJsonSamples(t *testing.T) {
 
 func TestAppendMemberID(t *testing.T) {
 	uri, err := url.Parse("http://ib.adnxs.com/openrtb2?query_param=true")
-	assert.NoError(t, err, "Failed to parse URI with query string")
+	require.NoError(t, err, "Failed to parse URI with query string")
+
 	uriWithMember := appendMemberId(*uri, "102")
 	expected := "http://ib.adnxs.com/openrtb2?member_id=102&query_param=true"
 	assert.Equal(t, expected, uriWithMember.String(), "Failed to append member id to URI with query string")
@@ -37,11 +39,10 @@ func TestBuilderWithPlatformID(t *testing.T) {
 		Endpoint: "http://ib.adnxs.com/openrtb2", PlatformID: "3"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
 
 	assert.NoError(t, buildErr)
-	assert.NotNil(t, bidder)
+	require.NotNil(t, bidder)
 	assert.Equal(t, 3, (*bidder.(*adapter)).hbSource)
 }
 
-// fakerandomNumberGenerator
 type FakeRandomNumberGenerator struct {
 	Number int64
 }
diff --git a/adapters/appnexus/appnexustest/amp/simple-banner.json b/adapters/appnexus/appnexustest/amp/simple-banner.json
index 54e6a143..4ed3403d 100644
--- a/adapters/appnexus/appnexustest/amp/simple-banner.json
+++ b/adapters/appnexus/appnexustest/amp/simple-banner.json
@@ -34,8 +34,6 @@
             "appnexus": {
               "is_amp": 1,
               "hb_source": 5
-            },
-            "prebid": {
             }
           },
           "id": "test-request-id",
diff --git a/adapters/appnexus/appnexustest/amp/simple-video.json b/adapters/appnexus/appnexustest/amp/simple-video.json
index c9744831..623085e7 100644
--- a/adapters/appnexus/appnexustest/amp/simple-video.json
+++ b/adapters/appnexus/appnexustest/amp/simple-video.json
@@ -30,8 +30,6 @@
 				"appnexus": {
 					"is_amp": 1,
 					"hb_source": 5
-				},
-				"prebid": {
 				}
 			},
 			"id": "test-request-id",
diff --git a/adapters/appnexus/appnexustest/exemplary/dynamic-keywords-params.json b/adapters/appnexus/appnexustest/exemplary/dynamic-keywords-params.json
index 869c32d8..d0af71e6 100644
--- a/adapters/appnexus/appnexustest/exemplary/dynamic-keywords-params.json
+++ b/adapters/appnexus/appnexustest/exemplary/dynamic-keywords-params.json
@@ -41,8 +41,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/exemplary/native-1.1.json b/adapters/appnexus/appnexustest/exemplary/native-1.1.json
index 189304fd..b40543f1 100644
--- a/adapters/appnexus/appnexustest/exemplary/native-1.1.json
+++ b/adapters/appnexus/appnexustest/exemplary/native-1.1.json
@@ -51,8 +51,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "site": {
             "domain": "prebid.org",
diff --git a/adapters/appnexus/appnexustest/exemplary/optional-params.json b/adapters/appnexus/appnexustest/exemplary/optional-params.json
index e105d6e1..01af8252 100644
--- a/adapters/appnexus/appnexustest/exemplary/optional-params.json
+++ b/adapters/appnexus/appnexustest/exemplary/optional-params.json
@@ -46,8 +46,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/exemplary/schain-24-other-ext.json b/adapters/appnexus/appnexustest/exemplary/schain-24-other-ext.json
new file mode 100644
index 00000000..e5a258e7
--- /dev/null
+++ b/adapters/appnexus/appnexustest/exemplary/schain-24-other-ext.json
@@ -0,0 +1,193 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "app": {
+            "ext": {
+                "prebid": {
+                    "source": "source",
+                    "version": "version"
+                }
+            }
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 1,
+                        "position": "above"
+                    }
+                }
+            }
+        ],
+        "ext": {
+            "schain": {
+                "complete": 0,
+                "nodes": [
+                    {
+                        "asi": "pbshostcompany.com",
+                        "sid": "00001",
+                        "rid": "BidRequest",
+                        "hp": 1
+                    }
+                ],
+                "ver": "1.0"
+            },
+            "otherRequest": "value"
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://ib.adnxs.com/openrtb2",
+                "body": {
+                    "id": "test-request-id",
+                    "app": {
+                        "ext": {
+                            "prebid": {
+                                "source": "source",
+                                "version": "version"
+                            }
+                        }
+                    },
+                    "ext": {
+                        "appnexus": {
+                            "hb_source": 5
+                        },
+                        "schain": {
+                            "complete": 0,
+                            "nodes": [
+                                {
+                                    "asi": "pbshostcompany.com",
+                                    "sid": "00001",
+                                    "rid": "BidRequest",
+                                    "hp": 1
+                                }
+                            ],
+                            "ver": "1.0"
+                        },
+                        "otherRequest": "value"
+                    },
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ],
+                                "w": 300,
+                                "pos": 1,
+                                "h": 250
+                            },
+                            "displaymanagerver": "source-version",
+                            "ext": {
+                                "appnexus": {
+                                    "placement_id": 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": [
+                                        "appnexus.com"
+                                    ],
+                                    "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "appnexus": {
+                                            "brand_id": 1,
+                                            "brand_category_id": 1,
+                                            "auction_id": 8189378542222915032,
+                                            "bid_ad_type": 0,
+                                            "bidder_id": 2,
+                                            "ranking_price": 0.000000,
+                                            "deal_priority": 5
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "appnexus.com"
+                        ],
+                        "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "cat": [
+                            "IAB20-3"
+                        ],
+                        "ext": {
+                            "appnexus": {
+                                "brand_id": 1,
+                                "brand_category_id": 1,
+                                "auction_id": 8189378542222915032,
+                                "bid_ad_type": 0,
+                                "bidder_id": 2,
+                                "ranking_price": 0.000000,
+                                "deal_priority": 5
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/appnexus/appnexustest/exemplary/schain-24.json b/adapters/appnexus/appnexustest/exemplary/schain-24.json
new file mode 100644
index 00000000..d8f26d10
--- /dev/null
+++ b/adapters/appnexus/appnexustest/exemplary/schain-24.json
@@ -0,0 +1,191 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "app": {
+            "ext": {
+                "prebid": {
+                    "source": "source",
+                    "version": "version"
+                }
+            }
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 1,
+                        "position": "above"
+                    }
+                }
+            }
+        ],
+        "ext": {
+            "schain": {
+                "complete": 0,
+                "nodes": [
+                    {
+                        "asi": "pbshostcompany.com",
+                        "sid": "00001",
+                        "rid": "BidRequest",
+                        "hp": 1
+                    }
+                ],
+                "ver": "1.0"
+            }
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://ib.adnxs.com/openrtb2",
+                "body": {
+                    "id": "test-request-id",
+                    "app": {
+                        "ext": {
+                            "prebid": {
+                                "source": "source",
+                                "version": "version"
+                            }
+                        }
+                    },
+                    "ext": {
+                        "appnexus": {
+                            "hb_source": 5
+                        },
+                        "schain": {
+                            "complete": 0,
+                            "nodes": [
+                                {
+                                    "asi": "pbshostcompany.com",
+                                    "sid": "00001",
+                                    "rid": "BidRequest",
+                                    "hp": 1
+                                }
+                            ],
+                            "ver": "1.0"
+                        }
+                    },
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ],
+                                "w": 300,
+                                "pos": 1,
+                                "h": 250
+                            },
+                            "displaymanagerver": "source-version",
+                            "ext": {
+                                "appnexus": {
+                                    "placement_id": 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": [
+                                        "appnexus.com"
+                                    ],
+                                    "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "appnexus": {
+                                            "brand_id": 1,
+                                            "brand_category_id": 1,
+                                            "auction_id": 8189378542222915032,
+                                            "bid_ad_type": 0,
+                                            "bidder_id": 2,
+                                            "ranking_price": 0.000000,
+                                            "deal_priority": 5
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "appnexus.com"
+                        ],
+                        "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "cat": [
+                            "IAB20-3"
+                        ],
+                        "ext": {
+                            "appnexus": {
+                                "brand_id": 1,
+                                "brand_category_id": 1,
+                                "auction_id": 8189378542222915032,
+                                "bid_ad_type": 0,
+                                "bidder_id": 2,
+                                "ranking_price": 0.000000,
+                                "deal_priority": 5
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/appnexus/appnexustest/exemplary/schain-25-other-ext.json b/adapters/appnexus/appnexustest/exemplary/schain-25-other-ext.json
new file mode 100644
index 00000000..19b9f1db
--- /dev/null
+++ b/adapters/appnexus/appnexustest/exemplary/schain-25-other-ext.json
@@ -0,0 +1,203 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "app": {
+            "ext": {
+                "prebid": {
+                    "source": "source",
+                    "version": "version"
+                }
+            }
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 1,
+                        "position": "above"
+                    }
+                }
+            }
+        ],
+        "source": {
+            "ext": {
+                "schain": {
+                    "complete": 0,
+                    "nodes": [
+                        {
+                            "asi": "pbshostcompany.com",
+                            "sid": "00001",
+                            "rid": "BidRequest",
+                            "hp": 1
+                        }
+                    ],
+                    "ver": "1.0"
+                },
+                "otherSource": "value"
+            }
+        },
+        "ext": {
+            "otherRequest": "value"
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://ib.adnxs.com/openrtb2",
+                "body": {
+                    "id": "test-request-id",
+                    "app": {
+                        "ext": {
+                            "prebid": {
+                                "source": "source",
+                                "version": "version"
+                            }
+                        }
+                    },
+                    "ext": {
+                        "appnexus": {
+                            "hb_source": 5
+                        },
+                        "schain": {
+                            "complete": 0,
+                            "nodes": [
+                                {
+                                    "asi": "pbshostcompany.com",
+                                    "sid": "00001",
+                                    "rid": "BidRequest",
+                                    "hp": 1
+                                }
+                            ],
+                            "ver": "1.0"
+                        },
+                        "otherRequest": "value"
+                    },
+                    "source": {
+                        "ext": {
+                            "otherSource": "value"
+                        }
+                    },
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ],
+                                "w": 300,
+                                "pos": 1,
+                                "h": 250
+                            },
+                            "displaymanagerver": "source-version",
+                            "ext": {
+                                "appnexus": {
+                                    "placement_id": 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": [
+                                        "appnexus.com"
+                                    ],
+                                    "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "appnexus": {
+                                            "brand_id": 1,
+                                            "brand_category_id": 1,
+                                            "auction_id": 8189378542222915032,
+                                            "bid_ad_type": 0,
+                                            "bidder_id": 2,
+                                            "ranking_price": 0.000000,
+                                            "deal_priority": 5
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "appnexus.com"
+                        ],
+                        "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "cat": [
+                            "IAB20-3"
+                        ],
+                        "ext": {
+                            "appnexus": {
+                                "brand_id": 1,
+                                "brand_category_id": 1,
+                                "auction_id": 8189378542222915032,
+                                "bid_ad_type": 0,
+                                "bidder_id": 2,
+                                "ranking_price": 0.000000,
+                                "deal_priority": 5
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/appnexus/appnexustest/exemplary/schain-25.json b/adapters/appnexus/appnexustest/exemplary/schain-25.json
new file mode 100644
index 00000000..8ff11b01
--- /dev/null
+++ b/adapters/appnexus/appnexustest/exemplary/schain-25.json
@@ -0,0 +1,194 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "app": {
+            "ext": {
+                "prebid": {
+                    "source": "source",
+                    "version": "version"
+                }
+            }
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 1,
+                        "position": "above"
+                    }
+                }
+            }
+        ],
+        "source": {
+            "ext": {
+                "schain": {
+                    "complete": 0,
+                    "nodes": [
+                        {
+                            "asi": "pbshostcompany.com",
+                            "sid": "00001",
+                            "rid": "BidRequest",
+                            "hp": 1
+                        }
+                    ],
+                    "ver": "1.0"
+                }
+            }
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://ib.adnxs.com/openrtb2",
+                "body": {
+                    "id": "test-request-id",
+                    "app": {
+                        "ext": {
+                            "prebid": {
+                                "source": "source",
+                                "version": "version"
+                            }
+                        }
+                    },
+                    "ext": {
+                        "appnexus": {
+                            "hb_source": 5
+                        },
+                        "schain": {
+                            "complete": 0,
+                            "nodes": [
+                                {
+                                    "asi": "pbshostcompany.com",
+                                    "sid": "00001",
+                                    "rid": "BidRequest",
+                                    "hp": 1
+                                }
+                            ],
+                            "ver": "1.0"
+                        }
+                    },
+                    "source": {},
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ],
+                                "w": 300,
+                                "pos": 1,
+                                "h": 250
+                            },
+                            "displaymanagerver": "source-version",
+                            "ext": {
+                                "appnexus": {
+                                    "placement_id": 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": [
+                                        "appnexus.com"
+                                    ],
+                                    "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "appnexus": {
+                                            "brand_id": 1,
+                                            "brand_category_id": 1,
+                                            "auction_id": 8189378542222915032,
+                                            "bid_ad_type": 0,
+                                            "bidder_id": 2,
+                                            "ranking_price": 0.000000,
+                                            "deal_priority": 5
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "appnexus.com"
+                        ],
+                        "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "cat": [
+                            "IAB20-3"
+                        ],
+                        "ext": {
+                            "appnexus": {
+                                "brand_id": 1,
+                                "brand_category_id": 1,
+                                "auction_id": 8189378542222915032,
+                                "bid_ad_type": 0,
+                                "bidder_id": 2,
+                                "ranking_price": 0.000000,
+                                "deal_priority": 5
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json b/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json
index b46c6f5f..52112419 100644
--- a/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json
+++ b/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json
@@ -34,8 +34,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/exemplary/simple-banner.json b/adapters/appnexus/appnexustest/exemplary/simple-banner.json
index ec769abd..24deea82 100644
--- a/adapters/appnexus/appnexustest/exemplary/simple-banner.json
+++ b/adapters/appnexus/appnexustest/exemplary/simple-banner.json
@@ -51,8 +51,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/exemplary/simple-video.json b/adapters/appnexus/appnexustest/exemplary/simple-video.json
index a127e2a0..beb63010 100644
--- a/adapters/appnexus/appnexustest/exemplary/simple-video.json
+++ b/adapters/appnexus/appnexustest/exemplary/simple-video.json
@@ -30,8 +30,7 @@
 			"ext": {
 				"appnexus": {
 				  "hb_source": 5
-				},
-				"prebid": {}
+				}
 			  },
 			"imp": [
 			  {
diff --git a/adapters/appnexus/appnexustest/exemplary/string-keywords-params.json b/adapters/appnexus/appnexustest/exemplary/string-keywords-params.json
index f43c47fe..a6d8d95e 100644
--- a/adapters/appnexus/appnexustest/exemplary/string-keywords-params.json
+++ b/adapters/appnexus/appnexustest/exemplary/string-keywords-params.json
@@ -41,8 +41,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/exemplary/video-invalid-category.json b/adapters/appnexus/appnexustest/exemplary/video-invalid-category.json
index 257905c8..a65595e1 100644
--- a/adapters/appnexus/appnexustest/exemplary/video-invalid-category.json
+++ b/adapters/appnexus/appnexustest/exemplary/video-invalid-category.json
@@ -30,8 +30,7 @@
 			"ext": {
 				"appnexus": {
 				  "hb_source": 5
-				},
-				"prebid": {}
+				}
 			},
 			"imp": [
 			  {
diff --git a/adapters/appnexus/appnexustest/supplemental/displaymanager-test.json b/adapters/appnexus/appnexustest/supplemental/displaymanager-test.json
index c6ad330e..ebfa1f23 100644
--- a/adapters/appnexus/appnexustest/supplemental/displaymanager-test.json
+++ b/adapters/appnexus/appnexustest/supplemental/displaymanager-test.json
@@ -50,8 +50,7 @@
               "ext": {
                 "appnexus": {
                   "hb_source": 5
-                },
-                "prebid": {}
+                }
               },
               "imp": [
               {
diff --git a/adapters/appnexus/appnexustest/supplemental/explicit-dimensions.json b/adapters/appnexus/appnexustest/supplemental/explicit-dimensions.json
index 685a908b..c66f8973 100644
--- a/adapters/appnexus/appnexustest/supplemental/explicit-dimensions.json
+++ b/adapters/appnexus/appnexustest/supplemental/explicit-dimensions.json
@@ -31,8 +31,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/supplemental/invalid-bid-type.json b/adapters/appnexus/appnexustest/supplemental/invalid-bid-type.json
index 6c7f1633..a66f69e3 100644
--- a/adapters/appnexus/appnexustest/supplemental/invalid-bid-type.json
+++ b/adapters/appnexus/appnexustest/supplemental/invalid-bid-type.json
@@ -51,8 +51,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/supplemental/legacy-params.json b/adapters/appnexus/appnexustest/supplemental/legacy-params.json
index 82031145..15a4c545 100644
--- a/adapters/appnexus/appnexustest/supplemental/legacy-params.json
+++ b/adapters/appnexus/appnexustest/supplemental/legacy-params.json
@@ -37,8 +37,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/supplemental/multi-bid.json b/adapters/appnexus/appnexustest/supplemental/multi-bid.json
index 9e63bdce..664244a9 100644
--- a/adapters/appnexus/appnexustest/supplemental/multi-bid.json
+++ b/adapters/appnexus/appnexustest/supplemental/multi-bid.json
@@ -34,8 +34,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/supplemental/placement-id-as-string-test.json b/adapters/appnexus/appnexustest/supplemental/placement-id-as-string-test.json
index 1d28983b..b1e0401e 100644
--- a/adapters/appnexus/appnexustest/supplemental/placement-id-as-string-test.json
+++ b/adapters/appnexus/appnexustest/supplemental/placement-id-as-string-test.json
@@ -51,8 +51,7 @@
             "ext": {
               "appnexus": {
                 "hb_source": 5
-              },
-              "prebid": {}
+              }
             },
             "site": {
               "domain": "prebid.org",
diff --git a/adapters/appnexus/appnexustest/supplemental/request-ext-appnexus-existing.json b/adapters/appnexus/appnexustest/supplemental/request-ext-appnexus-existing.json
new file mode 100644
index 00000000..0f153117
--- /dev/null
+++ b/adapters/appnexus/appnexustest/supplemental/request-ext-appnexus-existing.json
@@ -0,0 +1,171 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "app": {
+            "ext": {
+                "prebid": {
+                    "source": "source",
+                    "version": "version"
+                }
+            }
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 1,
+                        "position": "above"
+                    }
+                }
+            }
+        ],
+        "ext": {
+            "appnexus": {
+                "adpod_id": "42"
+            }
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://ib.adnxs.com/openrtb2",
+                "body": {
+                    "id": "test-request-id",
+                    "app": {
+                        "ext": {
+                            "prebid": {
+                                "source": "source",
+                                "version": "version"
+                            }
+                        }
+                    },
+                    "ext": {
+                        "appnexus": {
+                            "hb_source": 5,
+                            "adpod_id": "42"
+                        }
+                    },
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ],
+                                "w": 300,
+                                "pos": 1,
+                                "h": 250
+                            },
+                            "displaymanagerver": "source-version",
+                            "ext": {
+                                "appnexus": {
+                                    "placement_id": 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": [
+                                        "appnexus.com"
+                                    ],
+                                    "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "appnexus": {
+                                            "brand_id": 1,
+                                            "brand_category_id": 1,
+                                            "auction_id": 8189378542222915032,
+                                            "bid_ad_type": 0,
+                                            "bidder_id": 2,
+                                            "ranking_price": 0.000000,
+                                            "deal_priority": 5
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "appnexus.com"
+                        ],
+                        "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "cat": [
+                            "IAB20-3"
+                        ],
+                        "ext": {
+                            "appnexus": {
+                                "brand_id": 1,
+                                "brand_category_id": 1,
+                                "auction_id": 8189378542222915032,
+                                "bid_ad_type": 0,
+                                "bidder_id": 2,
+                                "ranking_price": 0.000000,
+                                "deal_priority": 5
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/appnexus/appnexustest/supplemental/reserve-ignored.json b/adapters/appnexus/appnexustest/supplemental/reserve-ignored.json
index 84e2b484..e9df5038 100644
--- a/adapters/appnexus/appnexustest/supplemental/reserve-ignored.json
+++ b/adapters/appnexus/appnexustest/supplemental/reserve-ignored.json
@@ -36,8 +36,7 @@
             "ext": {
               "appnexus": {
                 "hb_source": 5
-              },
-              "prebid": {}
+              }
             },
             "imp": [
               {
diff --git a/adapters/appnexus/appnexustest/supplemental/reserve-test.json b/adapters/appnexus/appnexustest/supplemental/reserve-test.json
index f5c6dfce..df861897 100644
--- a/adapters/appnexus/appnexustest/supplemental/reserve-test.json
+++ b/adapters/appnexus/appnexustest/supplemental/reserve-test.json
@@ -35,8 +35,7 @@
             "ext": {
               "appnexus": {
                 "hb_source": 5
-              },
-              "prebid": {}
+              }
             },
             "imp": [
               {
diff --git a/adapters/appnexus/appnexustest/supplemental/status-400.json b/adapters/appnexus/appnexustest/supplemental/status-400.json
index dc889012..58c7a465 100644
--- a/adapters/appnexus/appnexustest/supplemental/status-400.json
+++ b/adapters/appnexus/appnexustest/supplemental/status-400.json
@@ -35,8 +35,7 @@
           "ext": {
             "appnexus": {
               "hb_source": 5
-            },
-            "prebid": {}
+            }
           },
           "imp": [
             {
diff --git a/adapters/appnexus/appnexustest/supplemental/usePmtRule-test.json b/adapters/appnexus/appnexustest/supplemental/usePmtRule-test.json
index 64e51927..2d3f307a 100644
--- a/adapters/appnexus/appnexustest/supplemental/usePmtRule-test.json
+++ b/adapters/appnexus/appnexustest/supplemental/usePmtRule-test.json
@@ -63,8 +63,7 @@
             "ext": {
               "appnexus": {
                 "hb_source": 5
-              },
-              "prebid": {}
+              }
             },
             "imp": [
               {
diff --git a/adapters/appnexus/appnexustest/video/video-brand-category.json b/adapters/appnexus/appnexustest/video/video-brand-category.json
new file mode 100644
index 00000000..1671b971
--- /dev/null
+++ b/adapters/appnexus/appnexustest/video/video-brand-category.json
@@ -0,0 +1,179 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "video": {
+                    "mimes": [
+                        "video/mp4"
+                    ],
+                    "minduration": 15,
+                    "maxduration": 30,
+                    "protocols": [
+                        2,
+                        3,
+                        5,
+                        6,
+                        7,
+                        8
+                    ],
+                    "w": 940,
+                    "h": 560
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 1
+                    }
+                }
+            }
+        ],
+        "ext": {
+            "prebid": {
+                "targeting": {
+                    "includebrandcategory": {
+                        "primaryadserver": 1,
+                        "publisher": "anyPublisher",
+                        "withcategory": true
+                    }
+                }
+            }
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://ib.adnxs.com/openrtb2",
+                "body": {
+                    "id": "test-request-id",
+                    "ext": {
+                        "appnexus": {
+                            "hb_source": 6,
+                            "brand_category_uniqueness": true,
+                            "include_brand_category": true
+                        },
+                        "prebid": {
+                            "targeting": {
+                                "includebrandcategory": {
+                                    "primaryadserver": 1,
+                                    "publisher": "anyPublisher",
+                                    "withcategory": true
+                                }
+                            }
+                        }
+                    },
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "video": {
+                                "mimes": [
+                                    "video/mp4"
+                                ],
+                                "minduration": 15,
+                                "maxduration": 30,
+                                "protocols": [
+                                    2,
+                                    3,
+                                    5,
+                                    6,
+                                    7,
+                                    8
+                                ],
+                                "w": 940,
+                                "h": 560
+                            },
+                            "ext": {
+                                "appnexus": {
+                                    "placement_id": 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": [
+                                        "appnexus.com"
+                                    ],
+                                    "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "cat": [
+                                        "IAB9-1"
+                                    ],
+                                    "ext": {
+                                        "appnexus": {
+                                            "brand_id": 9,
+                                            "brand_category_id": 9,
+                                            "auction_id": 8189378542222915032,
+                                            "bid_ad_type": 1,
+                                            "bidder_id": 2,
+                                            "ranking_price": 0.000000,
+                                            "deal_priority": 5
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "appnexus.com"
+                        ],
+                        "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "cat": [
+                            "IAB5-1"
+                        ],
+                        "ext": {
+                            "appnexus": {
+                                "brand_id": 9,
+                                "brand_category_id": 9,
+                                "auction_id": 8189378542222915032,
+                                "bid_ad_type": 1,
+                                "bidder_id": 2,
+                                "ranking_price": 0.000000,
+                                "deal_priority": 5
+                            }
+                        }
+                    },
+                    "type": "video"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/appnexus/appnexustest/video/video-no-adpodid-two-imps-different-pod.json b/adapters/appnexus/appnexustest/video/video-no-adpodid-two-imps-different-pod.json
index ef1368ab..811cfcb2 100644
--- a/adapters/appnexus/appnexustest/video/video-no-adpodid-two-imps-different-pod.json
+++ b/adapters/appnexus/appnexustest/video/video-no-adpodid-two-imps-different-pod.json
@@ -46,8 +46,7 @@
 			"ext": {
 				"appnexus": {
 				  "hb_source": 6
-				},
-				"prebid": {}
+				}
 			},
 			"imp": [
 			  {
diff --git a/adapters/appnexus/appnexustest/video/video-same-adpodid-two-imps-same-pod.json b/adapters/appnexus/appnexustest/video/video-same-adpodid-two-imps-same-pod.json
index efaf95ed..8f0f1526 100644
--- a/adapters/appnexus/appnexustest/video/video-same-adpodid-two-imps-same-pod.json
+++ b/adapters/appnexus/appnexustest/video/video-same-adpodid-two-imps-same-pod.json
@@ -49,8 +49,7 @@
 				"appnexus": {
 				 "adpod_id": "10",
 				  "hb_source": 6
-				},
-				"prebid": {}
+				}
 			},
 			"imp": [
 			  {
diff --git a/adapters/ix/ixtest/exemplary/app-site-id.json b/adapters/ix/ixtest/exemplary/app-site-id.json
new file mode 100644
index 00000000..80441cc4
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/app-site-id.json
@@ -0,0 +1,140 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id-1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "domain": "https://www.example.com/"
+        },
+        "ext": {
+            "prebid": {
+                "channel": {
+                    "name": "web",
+                    "version": "7.0.0"
+                }
+            }
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id-1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ],
+                    "app": {
+                        "domain": "https://www.example.com/",
+                        "publisher": {
+                            "id": "569749"
+                        }
+                    },
+                    "ext": {
+                        "ixdiag": {
+                          "pbjsv": "7.0.0"
+                        },
+                        "prebid": {
+                          "channel": {
+                            "name": "web",
+                            "version": "7.0.0"
+                          }
+                        }
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id-1",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id-1",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/app-site-id-publisher.json b/adapters/ix/ixtest/supplemental/app-site-id-publisher.json
new file mode 100644
index 00000000..aec2c124
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/app-site-id-publisher.json
@@ -0,0 +1,144 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id-1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "domain": "https://www.example.com/",
+            "publisher": {
+                "name": "https://www.example.com/"
+            }
+        },
+        "ext": {
+            "prebid": {
+                "channel": {
+                    "name": "web",
+                    "version": "7.0.0"
+                }
+            }
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id-1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ],
+                    "app": {
+                        "domain": "https://www.example.com/",
+                        "publisher": {
+                            "id": "569749",
+                            "name": "https://www.example.com/"
+                        }
+                    },
+                    "ext": {
+                        "ixdiag": {
+                          "pbjsv": "7.0.0"
+                        },
+                        "prebid": {
+                          "channel": {
+                            "name": "web",
+                            "version": "7.0.0"
+                          }
+                        }
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id-1",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id-1",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/sid.json b/adapters/ix/ixtest/supplemental/sid.json
index c2156b6b..3d6862d1 100644
--- a/adapters/ix/ixtest/supplemental/sid.json
+++ b/adapters/ix/ixtest/supplemental/sid.json
@@ -61,6 +61,12 @@
       "expectedRequest": {
         "uri": "http://host/endpoint",
         "body": {
+          "ext": {
+            "ixdiag": {
+              "multipleSiteIds": "569749, 569750"
+            },
+            "prebid": null
+          },
           "id": "test-request-id",
           "imp": [
             {
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index b39f6e03..c42209e0 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -495,7 +495,7 @@ func doBadAliasRequest(t *testing.T, filename string, expectMsg string) {
 	bidderInfos := getBidderInfos(nil, openrtb_ext.CoreBidderNames())
 
 	bidderMap := exchange.GetActiveBidders(bidderInfos)
-	disabledBidders := exchange.GetDisabledBiddersErrorMessages(bidderInfos)
+	disabledBidders := exchange.GetDisabledBidderWarningMessages(bidderInfos)
 
 	// NewMetrics() will create a new go_metrics MetricsEngine, bypassing the need for a crafted configuration set to support it.
 	// As a side effect this gives us some coverage of the go_metrics piece of the metrics engine.
diff --git a/endpoints/openrtb2/test_utils.go b/endpoints/openrtb2/test_utils.go
index 401fbf62..3d249dc8 100644
--- a/endpoints/openrtb2/test_utils.go
+++ b/endpoints/openrtb2/test_utils.go
@@ -1246,7 +1246,7 @@ func buildTestEndpoint(test testCase, cfg *config.Configuration) (httprouter.Han
 
 	bidderInfos := getBidderInfos(test.Config.DisabledAdapters, openrtb_ext.CoreBidderNames())
 	bidderMap := exchange.GetActiveBidders(bidderInfos)
-	disabledBidders := exchange.GetDisabledBiddersErrorMessages(bidderInfos)
+	disabledBidders := exchange.GetDisabledBidderWarningMessages(bidderInfos)
 	met := &metricsConfig.NilMetricsEngine{}
 	mockFetcher := empty_fetcher.EmptyFetcher{}
 
diff --git a/exchange/adapter_util_test.go b/exchange/adapter_util_test.go
index 2f3c8e9a..f860a1df 100644
--- a/exchange/adapter_util_test.go
+++ b/exchange/adapter_util_test.go
@@ -13,6 +13,7 @@ import (
 	metrics "github.com/prebid/prebid-server/metrics/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -204,79 +205,71 @@ func TestGetActiveBidders(t *testing.T) {
 	}
 }
 
-func TestGetDisabledBiddersErrorMessages(t *testing.T) {
+func TestGetDisabledBidderWarningMessages(t *testing.T) {
+	t.Run("removed", func(t *testing.T) {
+		result := GetDisabledBidderWarningMessages(nil)
+
+		// test proper construction by verifying one expected bidder is in the list
+		require.Contains(t, result, "groupm")
+		assert.Equal(t, result["groupm"], `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`)
+	})
+
+	t.Run("removed-and-disabled", func(t *testing.T) {
+		result := GetDisabledBidderWarningMessages(map[string]config.BidderInfo{"bidderA": infoDisabled})
+
+		// test proper construction by verifying one expected bidder is in the list with the disabled bidder
+		require.Contains(t, result, "groupm")
+		assert.Equal(t, result["groupm"], `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`)
+
+		require.Contains(t, result, "bidderA")
+		assert.Equal(t, result["bidderA"], `Bidder "bidderA" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`)
+	})
+}
+
+func TestMergeRemovedAndDisabledBidderWarningMessages(t *testing.T) {
 	testCases := []struct {
-		description string
-		bidderInfos map[string]config.BidderInfo
-		expected    map[string]string
+		name             string
+		givenRemoved     map[string]string
+		givenBidderInfos map[string]config.BidderInfo
+		expected         map[string]string
 	}{
 		{
-			description: "None",
-			bidderInfos: map[string]config.BidderInfo{},
-			expected: map[string]string{
-				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
-				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
-				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahooAds" in your configuration.`,
-				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
-				"oftmedia":       `Bidder "oftmedia" is no longer available in Prebid Server. Please update your configuration.`,
-				"groupm":         `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`,
-				"verizonmedia":   `Bidder "verizonmedia" is no longer available in Prebid Server. Please update your configuration.`,
-				"brightroll":     `Bidder "brightroll" is no longer available in Prebid Server. Please update your configuration.`,
-			},
+			name:             "none",
+			givenRemoved:     map[string]string{},
+			givenBidderInfos: map[string]config.BidderInfo{},
+			expected:         map[string]string{},
 		},
 		{
-			description: "Enabled",
-			bidderInfos: map[string]config.BidderInfo{"appnexus": infoEnabled},
-			expected: map[string]string{
-				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
-				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
-				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahooAds" in your configuration.`,
-				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
-				"oftmedia":       `Bidder "oftmedia" is no longer available in Prebid Server. Please update your configuration.`,
-				"groupm":         `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`,
-				"verizonmedia":   `Bidder "verizonmedia" is no longer available in Prebid Server. Please update your configuration.`,
-				"brightroll":     `Bidder "brightroll" is no longer available in Prebid Server. Please update your configuration.`,
-			},
+			name:             "removed",
+			givenRemoved:     map[string]string{"bidderA": `Bidder A Message`},
+			givenBidderInfos: map[string]config.BidderInfo{},
+			expected:         map[string]string{"bidderA": `Bidder A Message`},
 		},
 		{
-			description: "Disabled",
-			bidderInfos: map[string]config.BidderInfo{"appnexus": infoDisabled},
-			expected: map[string]string{
-				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
-				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
-				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahooAds" in your configuration.`,
-				"appnexus":       `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
-				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
-				"oftmedia":       `Bidder "oftmedia" is no longer available in Prebid Server. Please update your configuration.`,
-				"groupm":         `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`,
-				"verizonmedia":   `Bidder "verizonmedia" is no longer available in Prebid Server. Please update your configuration.`,
-				"brightroll":     `Bidder "brightroll" is no longer available in Prebid Server. Please update your configuration.`,
-			},
+			name:             "enabled",
+			givenRemoved:     map[string]string{},
+			givenBidderInfos: map[string]config.BidderInfo{"bidderA": infoEnabled},
+			expected:         map[string]string{},
 		},
 		{
-			description: "Mixed",
-			bidderInfos: map[string]config.BidderInfo{"appnexus": infoDisabled, "openx": infoEnabled},
-			expected: map[string]string{
-				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
-				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
-				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahooAds" in your configuration.`,
-				"appnexus":       `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
-				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
-				"oftmedia":       `Bidder "oftmedia" is no longer available in Prebid Server. Please update your configuration.`,
-				"groupm":         `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`,
-				"verizonmedia":   `Bidder "verizonmedia" is no longer available in Prebid Server. Please update your configuration.`,
-				"brightroll":     `Bidder "brightroll" is no longer available in Prebid Server. Please update your configuration.`,
-			},
+			name:             "disabled",
+			givenRemoved:     map[string]string{},
+			givenBidderInfos: map[string]config.BidderInfo{"bidderA": infoDisabled},
+			expected:         map[string]string{"bidderA": `Bidder "bidderA" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`},
+		},
+		{
+			name:             "mixed",
+			givenRemoved:     map[string]string{"bidderA": `Bidder A Message`},
+			givenBidderInfos: map[string]config.BidderInfo{"bidderB": infoEnabled, "bidderC": infoDisabled},
+			expected:         map[string]string{"bidderA": `Bidder A Message`, "bidderC": `Bidder "bidderC" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`},
 		},
 	}
 
 	for _, test := range testCases {
-		result := GetDisabledBiddersErrorMessages(test.bidderInfos)
-		assert.Equal(t, test.expected, result, test.description)
+		t.Run(test.name, func(t *testing.T) {
+			result := mergeRemovedAndDisabledBidderWarningMessages(test.givenRemoved, test.givenBidderInfos)
+			assert.Equal(t, test.expected, result, test.name)
+		})
 	}
 }
 
diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go
index 9d58e947..e2d476c0 100644
--- a/exchange/bidder_test.go
+++ b/exchange/bidder_test.go
@@ -3262,3 +3262,57 @@ func TestDoRequestImplWithTmax(t *testing.T) {
 		test.assertFn(httpCallInfo.err)
 	}
 }
+
+func TestDoRequestImplWithTmaxTimeout(t *testing.T) {
+	respStatus := 200
+	respBody := "{\"bid\":false}"
+	server := httptest.NewServer(mockHandler(respStatus, "getBody", respBody))
+	defer server.Close()
+	requestStartTime := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
+
+	bidRequest := adapters.RequestData{
+		Method: "POST",
+		Uri:    server.URL,
+		Body:   []byte(`{"id":"this-id","app":{"publisher":{"id":"pub-id"}}}`),
+	}
+
+	metricsMock := &metrics.MetricsEngineMock{}
+	metricsMock.On("RecordOverheadTime", metrics.PreBidder, mock.Anything).Once()
+	metricsMock.On("RecordTMaxTimeout").Once()
+
+	bidderAdapter := bidderAdapter{
+		me:     metricsMock,
+		Client: server.Client(),
+	}
+	logger := func(msg string, args ...interface{}) {}
+
+	tests := []struct {
+		ctxDeadline     time.Time
+		description     string
+		tmaxAdjustments *TmaxAdjustmentsPreprocessed
+		assertFn        func(err error)
+	}{
+		{
+			ctxDeadline:     time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
+			description:     "returns-tmax-timeout-error",
+			tmaxAdjustments: &TmaxAdjustmentsPreprocessed{IsEnforced: true, PBSResponsePreparationDuration: 100, BidderNetworkLatencyBuffer: 10, BidderResponseDurationMin: 5000},
+			assertFn:        func(err error) { assert.Equal(t, errTmaxTimeout, err) },
+		},
+	}
+	for _, test := range tests {
+		var (
+			ctx      context.Context
+			cancelFn context.CancelFunc
+		)
+
+		if test.ctxDeadline.IsZero() {
+			ctx = context.Background()
+		} else {
+			ctx, cancelFn = context.WithDeadline(context.Background(), test.ctxDeadline)
+			defer cancelFn()
+		}
+
+		httpCallInfo := bidderAdapter.doRequestImpl(ctx, &bidRequest, logger, requestStartTime, test.tmaxAdjustments)
+		test.assertFn(httpCallInfo.err)
+	}
+}
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 8e7ba80b..52813897 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -167,12 +167,9 @@ func TestCharacterEscape(t *testing.T) {
 	var errList []error
 
 	// 	4) Build bid response
-	bidResp, err := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, nil, nil, true, nil, "", errList)
+	bidResp := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, nil, nil, true, nil, "", errList)
 
 	// 	5) Assert we have no errors and one '&' character as we are supposed to
-	if err != nil {
-		t.Errorf("exchange.buildBidResponse returned unexpected error: %v", err)
-	}
 	if len(errList) > 0 {
 		t.Errorf("exchange.buildBidResponse returned %d errors", len(errList))
 	}
@@ -1533,10 +1530,7 @@ func TestGetBidCacheInfoEndToEnd(t *testing.T) {
 	var errList []error
 
 	// 	4) Build bid response
-	bid_resp, err := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, auc, nil, true, nil, "", errList)
-
-	// 	5) Assert we have no errors and the bid response we expected
-	assert.NoError(t, err, "[TestGetBidCacheInfo] buildBidResponse() threw an error")
+	bid_resp := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, auc, nil, true, nil, "", errList)
 
 	expectedBidResponse := &openrtb2.BidResponse{
 		SeatBid: []openrtb2.SeatBid{
@@ -1909,8 +1903,7 @@ func TestBidResponseCurrency(t *testing.T) {
 	}
 	// Run tests
 	for i := range testCases {
-		actualBidResp, err := e.buildBidResponse(context.Background(), liveAdapters, testCases[i].adapterBids, bidRequest, adapterExtra, nil, bidResponseExt, true, nil, "", errList)
-		assert.NoError(t, err, fmt.Sprintf("[TEST_FAILED] e.buildBidResponse resturns error in test: %s Error message: %s \n", testCases[i].description, err))
+		actualBidResp := e.buildBidResponse(context.Background(), liveAdapters, testCases[i].adapterBids, bidRequest, adapterExtra, nil, bidResponseExt, true, nil, "", errList)
 		assert.Equalf(t, testCases[i].expectedBidResponse, actualBidResp, fmt.Sprintf("[TEST_FAILED] Objects must be equal for test: %s \n Expected: >>%s<< \n Actual: >>%s<< ", testCases[i].description, testCases[i].expectedBidResponse.Ext, actualBidResp.Ext))
 	}
 }
@@ -1976,8 +1969,7 @@ func TestBidResponseImpExtInfo(t *testing.T) {
 
 	expectedBidResponseExt := `{"origbidcpm":0,"prebid":{"type":"video","passthrough":{"imp_passthrough_val":1}},"storedrequestattributes":{"h":480,"mimes":["video/mp4"]}}`
 
-	actualBidResp, err := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, nil, nil, nil, true, impExtInfo, "", errList)
-	assert.NoError(t, err, fmt.Sprintf("imp ext info was not passed through correctly: %s", err))
+	actualBidResp := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, nil, nil, nil, true, impExtInfo, "", errList)
 
 	resBidExt := string(actualBidResp.SeatBid[0].Bid[0].Ext)
 	assert.Equalf(t, expectedBidResponseExt, resBidExt, "Expected bid response extension is incorrect")
diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go
index 1ab22ac1..515691fe 100644
--- a/metrics/go_metrics_test.go
+++ b/metrics/go_metrics_test.go
@@ -84,6 +84,7 @@ func TestNewMetrics(t *testing.T) {
 	ensureContains(t, registry, "request_over_head_time.make-auction-response", m.OverheadTimer[MakeAuctionResponse])
 	ensureContains(t, registry, "request_over_head_time.make-bidder-requests", m.OverheadTimer[MakeBidderRequests])
 	ensureContains(t, registry, "bidder_server_response_time_seconds", m.BidderServerResponseTimer)
+	ensureContains(t, registry, "tmax_timeout", m.TMaxTimeoutCounter)
 
 	for module, stages := range moduleStageNames {
 		for _, stage := range stages {
diff --git a/privacy/enforcer_test.go b/privacy/enforcer_test.go
index 2b9715f8..49f3a507 100644
--- a/privacy/enforcer_test.go
+++ b/privacy/enforcer_test.go
@@ -2,10 +2,11 @@ package privacy
 
 import (
 	"errors"
+	"testing"
+
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/util/ptrutil"
 	"github.com/stretchr/testify/assert"
-	"testing"
 )
 
 func TestNewActivityControl(t *testing.T) {
@@ -144,24 +145,23 @@ func TestNewActivityControl(t *testing.T) {
 }
 
 func TestActivityDefaultToDefaultResult(t *testing.T) {
-
 	testCases := []struct {
 		name            string
 		activityDefault *bool
 		expectedResult  ActivityResult
 	}{
 		{
-			name:            "activityDefault_is_nil",
+			name:            "nil",
 			activityDefault: nil,
 			expectedResult:  ActivityAllow,
 		},
 		{
-			name:            "activityDefault_is_true",
+			name:            "true",
 			activityDefault: ptrutil.ToPtr(true),
 			expectedResult:  ActivityAllow,
 		},
 		{
-			name:            "activityDefault_is_false",
+			name:            "false",
 			activityDefault: ptrutil.ToPtr(false),
 			expectedResult:  ActivityDeny,
 		},
@@ -219,15 +219,14 @@ func TestAllowActivityControl(t *testing.T) {
 
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			actualResult := test.activityControl.Allow(test.activity, test.target)
+			actualResult := test.activityControl.Evaluate(test.activity, test.target)
 			assert.Equal(t, test.activityResult, actualResult)
 
 		})
 	}
 }
 
-func TestAllowComponentEnforcementRule(t *testing.T) {
-
+func TestComponentEnforcementRuleEvaluate(t *testing.T) {
 	testCases := []struct {
 		name           string
 		componentRule  ComponentEnforcementRule
@@ -237,7 +236,7 @@ func TestAllowComponentEnforcementRule(t *testing.T) {
 		{
 			name: "activity_is_allowed",
 			componentRule: ComponentEnforcementRule{
-				allowed: true,
+				result: ActivityAllow,
 				componentName: []ScopedName{
 					{Scope: "bidder", Name: "bidderA"},
 				},
@@ -249,7 +248,7 @@ func TestAllowComponentEnforcementRule(t *testing.T) {
 		{
 			name: "activity_is_not_allowed",
 			componentRule: ComponentEnforcementRule{
-				allowed: false,
+				result: ActivityDeny,
 				componentName: []ScopedName{
 					{Scope: "bidder", Name: "bidderA"},
 				},
@@ -261,7 +260,7 @@ func TestAllowComponentEnforcementRule(t *testing.T) {
 		{
 			name: "abstain_both_clauses_do_not_match",
 			componentRule: ComponentEnforcementRule{
-				allowed: true,
+				result: ActivityAllow,
 				componentName: []ScopedName{
 					{Scope: "bidder", Name: "bidderA"},
 				},
@@ -273,7 +272,7 @@ func TestAllowComponentEnforcementRule(t *testing.T) {
 		{
 			name: "activity_is_not_allowed_componentName_only",
 			componentRule: ComponentEnforcementRule{
-				allowed: true,
+				result: ActivityAllow,
 				componentName: []ScopedName{
 					{Scope: "bidder", Name: "bidderA"},
 				},
@@ -284,25 +283,33 @@ func TestAllowComponentEnforcementRule(t *testing.T) {
 		{
 			name: "activity_is_allowed_componentType_only",
 			componentRule: ComponentEnforcementRule{
-				allowed:       true,
+				result:        ActivityAllow,
 				componentType: []string{"bidder"},
 			},
 			target:         ScopedName{Scope: "bidder", Name: "bidderB"},
 			activityResult: ActivityAllow,
 		},
 		{
-			name: "abstain_activity_no_componentType_and_no_componentName",
+			name: "no-conditions-allow",
 			componentRule: ComponentEnforcementRule{
-				allowed: true,
+				result: ActivityAllow,
 			},
-			target:         ScopedName{Scope: "bidder", Name: "bidderB"},
-			activityResult: ActivityAbstain,
+			target:         ScopedName{Scope: "bidder", Name: "bidderA"},
+			activityResult: ActivityAllow,
+		},
+		{
+			name: "no-conditions-deny",
+			componentRule: ComponentEnforcementRule{
+				result: ActivityDeny,
+			},
+			target:         ScopedName{Scope: "bidder", Name: "bidderA"},
+			activityResult: ActivityDeny,
 		},
 	}
 
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			actualResult := test.componentRule.Allow(test.target)
+			actualResult := test.componentRule.Evaluate(test.target)
 			assert.Equal(t, test.activityResult, actualResult)
 
 		})
@@ -310,7 +317,6 @@ func TestAllowComponentEnforcementRule(t *testing.T) {
 }
 
 func TestNewScopedName(t *testing.T) {
-
 	testCases := []struct {
 		name              string
 		condition         string
@@ -318,49 +324,49 @@ func TestNewScopedName(t *testing.T) {
 		err               error
 	}{
 		{
-			name:              "condition_is_empty",
+			name:              "empty",
 			condition:         "",
 			expectedScopeName: ScopedName{},
 			err:               errors.New("unable to parse empty condition"),
 		},
 		{
-			name:              "condition_is_incorrect",
+			name:              "incorrect",
 			condition:         "bidder.bidderA.bidderB",
 			expectedScopeName: ScopedName{},
 			err:               errors.New("unable to parse condition: bidder.bidderA.bidderB"),
 		},
 		{
-			name:              "condition_is_scoped_to_bidder",
+			name:              "scope-bidder",
 			condition:         "bidder.bidderA",
 			expectedScopeName: ScopedName{Scope: "bidder", Name: "bidderA"},
 			err:               nil,
 		},
 		{
-			name:              "condition_is_scoped_to_analytics",
+			name:              "scope-analytics",
 			condition:         "analytics.bidderA",
 			expectedScopeName: ScopedName{Scope: "analytics", Name: "bidderA"},
 			err:               nil,
 		},
 		{
-			name:              "condition_is_scoped_to_userid",
+			name:              "scope-userid",
 			condition:         "userid.bidderA",
 			expectedScopeName: ScopedName{Scope: "userid", Name: "bidderA"},
 			err:               nil,
 		},
 		{
-			name:              "condition_is_bidder_name",
+			name:              "scope-default",
 			condition:         "bidderA",
 			expectedScopeName: ScopedName{Scope: "bidder", Name: "bidderA"},
 			err:               nil,
 		},
 		{
-			name:              "condition_is_module_tag_rtd",
+			name:              "scope-rtf",
 			condition:         "rtd.test",
 			expectedScopeName: ScopedName{Scope: "rtd", Name: "test"},
 			err:               nil,
 		},
 		{
-			name:              "condition_scope_defaults_to_genera",
+			name:              "scope-general",
 			condition:         "test.test",
 			expectedScopeName: ScopedName{Scope: "general", Name: "test"},
 			err:               nil,
@@ -401,7 +407,7 @@ func getDefaultActivityPlan() ActivityPlan {
 		defaultResult: ActivityAllow,
 		rules: []ActivityRule{
 			ComponentEnforcementRule{
-				allowed: true,
+				result: ActivityAllow,
 				componentName: []ScopedName{
 					{Scope: "bidder", Name: "bidderA"},
 				},