Repository: prebid/prebid-server
Pull request #2989 (2023-07-28 21:52:52)

Activities refactoring


Patch:
diff --git a/.semgrep/README.md b/.semgrep/README.md
new file mode 100644
index 00000000..cd19e4bc
--- /dev/null
+++ b/.semgrep/README.md
@@ -0,0 +1,17 @@
+# Semgrep Test
+
+Running semgrep unit tests:
+```bash
+semgrep --test
+```
+
+
+Running single semgrep rules against adapter code:
+```bash
+semgrep --config=./adapter/{rule}.yml ../adapters/
+```
+
+Running all semgrep rules simultaneously:
+```bash
+semgrep --config=./adapter ../adapters/
+```
diff --git a/.semgrep/adapter/bid-type-if-check.go b/.semgrep/adapter/bid-type-if-check.go
new file mode 100644
index 00000000..52b5d551
--- /dev/null
+++ b/.semgrep/adapter/bid-type-if-check.go
@@ -0,0 +1,55 @@
+/*
+	bid-type-if-check tests
+	https://semgrep.dev/docs/writing-rules/testing-rules
+	"ruleid" prefix in comment indicates patterns that should be flagged by semgrep
+	"ok" prefix in comment indidcates  patterns that should not be flagged by the semgrep
+*/
+
+func getMediaTypeForImp(impID string, imps []openrtb2.Imp) openrtb_ext.BidType {
+	for _, imp := range imps {
+		if imp.ID == impID {
+			// ruleid: bid-type-if-check
+			if imp.Banner != nil {
+				return openrtb_ext.BidTypeBanner, nil
+				// ruleid: bid-type-if-check
+			} else if imp.Video != nil {
+				return openrtb_ext.BidTypeVideo, nil
+				// ruleid: bid-type-if-check
+			} else if imp.Native != nil {
+				return openrtb_ext.BidTypeNative, nil
+				// ruleid: bid-type-if-check
+			} else if imp.Audio != nil {
+				return openrtb_ext.BidTypeAudio, nil
+			}
+		}
+	}
+	return openrtb_ext.BidTypeBanner
+}
+
+func getMediaTypeForImp(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
+	for _, imp := range imps {
+		if imp.ID == impID {
+			// ruleid: bid-type-if-check
+			if imp.Banner != nil {
+				return openrtb_ext.BidTypeBanner, nil
+			}
+		}
+	}
+	return "", &errortypes.BadInput{
+		Message: fmt.Sprintf("Failed to find native/banner/video impression \"%s\" ", impID),
+	}
+}
+
+func getMediaTypeForImp(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
+	for _, imp := range imps {
+		if imp.ID == impID {
+			// ruleid: bid-type-if-check
+			if imp.Banner != nil {
+				return openrtb_ext.BidTypeBanner
+			}
+		}
+	}
+	return "", &errortypes.BadInput{
+		Message: fmt.Sprintf("Failed to find native/banner/video impression \"%s\" ", impID),
+	}
+}
diff --git a/.semgrep/adapter/bid-type-if-check.yml b/.semgrep/adapter/bid-type-if-check.yml
new file mode 100644
index 00000000..a2aa238e
--- /dev/null
+++ b/.semgrep/adapter/bid-type-if-check.yml
@@ -0,0 +1,19 @@
+rules:
+  - id: bid-type-if-check
+    message: The current implementation follows an anti-pattern, assumes that if there is a multi-format request, the media type defaults to $ORTBTYPE. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, we strongly recommend implementing a pattern where the adapter server sets the [MType](https://github.com/prebid/openrtb/blob/main/openrtb2/bid.go#L334) field in the response to accurately determine the media type for the impression.
+    languages:
+      - go
+    severity: WARNING
+    patterns:
+      - pattern-inside: |
+          if $CONDITION != nil {
+            return $ORTBTYPE
+          }
+      - metavariable-pattern:
+          metavariable: $ORTBTYPE
+          patterns:
+            - pattern-either:
+                - pattern: openrtb_ext.$BIDTYPE
+            - metavariable-regex:
+                metavariable: $BIDTYPE
+                regex: BidType*
\ No newline at end of file
diff --git a/.semgrep/adapter/bid-type-switch-check.go b/.semgrep/adapter/bid-type-switch-check.go
new file mode 100644
index 00000000..c8adf4f9
--- /dev/null
+++ b/.semgrep/adapter/bid-type-switch-check.go
@@ -0,0 +1,36 @@
+/*
+	bid-type-switch-check tests
+	https://semgrep.dev/docs/writing-rules/testing-rules
+	"ruleid" prefix in comment indicates patterns that should be flagged by semgrep
+	"ok" prefix in comment indidcates  patterns that should not be flagged by the semgrep
+*/
+
+// ruleid: bid-type-switch-check
+switch bidExt.AdCodeType {
+case "banner":
+	return openrtb_ext.BidTypeBanner, nil
+case "native":
+	return openrtb_ext.BidTypeNative, nil
+case "video":
+	return openrtb_ext.BidTypeVideo, nil
+}
+
+// ruleid: bid-type-switch-check
+switch impExt.Adot.MediaType {
+case string(openrtb_ext.BidTypeBanner):
+	return openrtb_ext.BidTypeBanner, nil
+case string(openrtb_ext.BidTypeVideo):
+	return openrtb_ext.BidTypeVideo, nil
+case string(openrtb_ext.BidTypeNative):
+	return openrtb_ext.BidTypeNative, nil
+}
+
+// ok: bid-type-switch-check
+switch bid.MType {
+case "banner":
+	return openrtb_ext.BidTypeBanner, nil
+case "native":
+	return openrtb_ext.BidTypeNative, nil
+case "video":
+	return openrtb_ext.BidTypeVideo, nil
+}
diff --git a/.semgrep/adapter/bid-type-switch-check.yml b/.semgrep/adapter/bid-type-switch-check.yml
new file mode 100644
index 00000000..b39cf870
--- /dev/null
+++ b/.semgrep/adapter/bid-type-switch-check.yml
@@ -0,0 +1,23 @@
+rules:
+  - id: bid-type-switch-check
+    message: The current implementation follows an anti-pattern, assumes that if there is a multi-format request, the media type defaults to $ORTBTYPE. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, we strongly recommend implementing a pattern where the adapter server sets the [MType](https://github.com/prebid/openrtb/blob/main/openrtb2/bid.go#L334) field in the response to accurately determine the media type for the impression.
+    languages:
+      - go
+    severity: WARNING
+    patterns:
+      - pattern-inside: |
+          switch $BIDTYPE {
+          case ...:
+            return $ORTBTYPE, nil
+          }
+      - metavariable-regex:
+          metavariable: $BIDTYPE
+          regex: ^(?!bid\.MType$).*$
+      - metavariable-pattern:
+          metavariable: $ORTBTYPE
+          patterns:
+            - pattern-either:
+                - pattern: openrtb_ext.$W
+            - metavariable-regex:
+                metavariable: $W
+                regex: BidType*
\ No newline at end of file
diff --git a/.semgrep/adapter/parse-bid-type-check.go b/.semgrep/adapter/parse-bid-type-check.go
new file mode 100644
index 00000000..77badd14
--- /dev/null
+++ b/.semgrep/adapter/parse-bid-type-check.go
@@ -0,0 +1,29 @@
+/*
+	parse-bid-type-check tests
+	https://semgrep.dev/docs/writing-rules/testing-rules
+	"ruleid" prefix in comment indicates patterns that should be flagged by semgrep
+	"ok" prefix in comment indidcates  patterns that should not be flagged by the semgrep
+*/
+
+func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+	if bid.Ext != nil {
+		var bidExt openrtb_ext.ExtBid
+		err := json.Unmarshal(bid.Ext, &bidExt)
+		if err == nil && bidExt.Prebid != nil {
+			// ruleid: parse-bid-type-check
+			return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type))
+		}
+	}
+
+	return "", &errortypes.BadServerResponse{
+		Message: fmt.Sprintf("Failed to parse impression \"%s\" mediatype", bid.ImpID),
+	}
+}
+
+func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+	var bidExt bidExt
+	// ruleid: parse-bid-type-check
+	bidType, err := openrtb_ext.ParseBidType(bidExt.Prebid.Type)
+
+	return bidType, err
+}
diff --git a/.semgrep/adapter/parse-bid-type-check.yml b/.semgrep/adapter/parse-bid-type-check.yml
new file mode 100644
index 00000000..e2d36241
--- /dev/null
+++ b/.semgrep/adapter/parse-bid-type-check.yml
@@ -0,0 +1,8 @@
+rules:
+  - id: parse-bid-type-check
+    message: The current implementation follows an anti-pattern, assumes that if there is a multi-format request, the media type defaults to $ORTBTYPE. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, we strongly recommend implementing a pattern where the adapter server sets the [MType](https://github.com/prebid/openrtb/blob/main/openrtb2/bid.go#L334) field in the response to accurately determine the media type for the impression.
+    languages:
+      - go
+    severity: WARNING
+    patterns:
+      - pattern: openrtb_ext.ParseBidType(...)
\ No newline at end of file
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/bidder.go b/adapters/bidder.go
index 6e163057..bb7424f3 100644
--- a/adapters/bidder.go
+++ b/adapters/bidder.go
@@ -4,7 +4,6 @@ import (
 	"encoding/base64"
 	"encoding/json"
 	"net/http"
-	"time"
 
 	"github.com/prebid/openrtb/v19/openrtb2"
 	"github.com/prebid/prebid-server/config"
@@ -146,7 +145,6 @@ func (r *RequestData) SetBasicAuth(username string, password string) {
 
 type ExtraRequestInfo struct {
 	PbsEntryPoint              metrics.RequestType
-	BidderRequestStartTime     time.Time
 	GlobalPrivacyControlHeader string
 	CurrencyConversions        currency.Conversions
 }
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/adapters/rise/rise.go b/adapters/rise/rise.go
index 5570e27d..e18b7c93 100644
--- a/adapters/rise/rise.go
+++ b/adapters/rise/rise.go
@@ -8,6 +8,7 @@ import (
 	"strings"
 
 	"github.com/prebid/openrtb/v19/openrtb2"
+
 	"github.com/prebid/prebid-server/adapters"
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
@@ -26,9 +27,9 @@ func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (
 
 // MakeRequests prepares the HTTP requests which should be made to fetch bids.
 func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) (requestsToBidder []*adapters.RequestData, errs []error) {
-	publisherID, err := extractPublisherID(openRTBRequest)
+	org, err := extractOrg(openRTBRequest)
 	if err != nil {
-		errs = append(errs, fmt.Errorf("extractPublisherID: %w", err))
+		errs = append(errs, fmt.Errorf("extractOrg: %w", err))
 		return nil, errs
 	}
 
@@ -43,7 +44,7 @@ func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest, _ *adapters.
 
 	return append(requestsToBidder, &adapters.RequestData{
 		Method:  http.MethodPost,
-		Uri:     a.endpointURL + "?publisher_id=" + publisherID,
+		Uri:     a.endpointURL + "?publisher_id=" + org,
 		Body:    openRTBRequestJSON,
 		Headers: headers,
 	}), nil
@@ -87,7 +88,7 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData
 	return bidResponse, errs
 }
 
-func extractPublisherID(openRTBRequest *openrtb2.BidRequest) (string, error) {
+func extractOrg(openRTBRequest *openrtb2.BidRequest) (string, error) {
 	var err error
 	for _, imp := range openRTBRequest.Imp {
 		var bidderExt adapters.ExtImpBidder
@@ -100,12 +101,15 @@ func extractPublisherID(openRTBRequest *openrtb2.BidRequest) (string, error) {
 			return "", fmt.Errorf("unmarshal ImpExtRise: %w", err)
 		}
 
+		if impExt.Org != "" {
+			return strings.TrimSpace(impExt.Org), nil
+		}
 		if impExt.PublisherID != "" {
 			return strings.TrimSpace(impExt.PublisherID), nil
 		}
 	}
 
-	return "", errors.New("no publisherID supplied")
+	return "", errors.New("no org or publisher_id supplied")
 }
 
 func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
diff --git a/adapters/screencore/screencore.go b/adapters/screencore/screencore.go
new file mode 100644
index 00000000..668e8b5e
--- /dev/null
+++ b/adapters/screencore/screencore.go
@@ -0,0 +1,176 @@
+package screencore
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"text/template"
+
+	"github.com/prebid/openrtb/v19/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/macros"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+type adapter struct {
+	endpoint *template.Template
+}
+
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
+	template, err := template.New("endpointTemplate").Parse(config.Endpoint)
+	if err != nil {
+		return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
+	}
+
+	bidder := &adapter{
+		endpoint: template,
+	}
+	return bidder, nil
+}
+
+func getHeaders(request *openrtb2.BidRequest) http.Header {
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	headers.Add("X-Openrtb-Version", "2.5")
+
+	if request.Device != nil {
+		if len(request.Device.UA) > 0 {
+			headers.Add("User-Agent", request.Device.UA)
+		}
+
+		if len(request.Device.IPv6) > 0 {
+			headers.Add("X-Forwarded-For", request.Device.IPv6)
+		}
+
+		if len(request.Device.IP) > 0 {
+			headers.Add("X-Forwarded-For", request.Device.IP)
+		}
+	}
+
+	return headers
+}
+
+func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) (requestsToBidder []*adapters.RequestData, errs []error) {
+	if len(openRTBRequest.Imp) == 0 {
+		return nil, []error{&errortypes.BadInput{
+			Message: "Empty Imp array in BidRequest",
+		}}
+	}
+
+	screencoreExt, err := getImpressionExt(&openRTBRequest.Imp[0])
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	openRTBRequest.Imp[0].Ext = nil
+
+	url, err := a.buildEndpointURL(screencoreExt)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	reqJSON, err := json.Marshal(openRTBRequest)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	return []*adapters.RequestData{{
+		Method:  http.MethodPost,
+		Body:    reqJSON,
+		Uri:     url,
+		Headers: getHeaders(openRTBRequest),
+	}}, nil
+}
+
+func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtScreencore, error) {
+	var bidderExt adapters.ExtImpBidder
+	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: "Error parsing screencoreExt - " + err.Error(),
+		}
+	}
+	var screencoreExt openrtb_ext.ExtScreencore
+	if err := json.Unmarshal(bidderExt.Bidder, &screencoreExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: "Error parsing bidderExt - " + err.Error(),
+		}
+	}
+
+	return &screencoreExt, nil
+}
+
+func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtScreencore) (string, error) {
+	endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID, SourceId: params.PlacementID}
+	return macros.ResolveMacros(a.endpoint, endpointParams)
+}
+
+func checkResponseStatusCodes(response *adapters.ResponseData) error {
+	if response.StatusCode == http.StatusServiceUnavailable {
+		return &errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Something went wrong Status Code: [ %d ] ", response.StatusCode),
+		}
+	}
+
+	return adapters.CheckResponseStatusCodeForErrors(response)
+}
+
+func (a *adapter) MakeBids(openRTBRequest *openrtb2.BidRequest, requestToBidder *adapters.RequestData, bidderRawResponse *adapters.ResponseData) (bidderResponse *adapters.BidderResponse, errs []error) {
+	if adapters.IsResponseStatusCodeNoContent(bidderRawResponse) {
+		return nil, nil
+	}
+
+	httpStatusError := checkResponseStatusCodes(bidderRawResponse)
+	if httpStatusError != nil {
+		return nil, []error{httpStatusError}
+	}
+
+	responseBody := bidderRawResponse.Body
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Bad Server Response",
+		}}
+	}
+
+	if len(bidResp.SeatBid) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid array",
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)
+	var bidsArray []*adapters.TypedBid
+
+	for _, sb := range bidResp.SeatBid {
+		for idx, bid := range sb.Bid {
+			bidType, err := getMediaTypeForImp(bid)
+			if err != nil {
+				return nil, []error{err}
+			}
+
+			bidsArray = append(bidsArray, &adapters.TypedBid{
+				Bid:     &sb.Bid[idx],
+				BidType: bidType,
+			})
+		}
+	}
+
+	bidResponse.Bids = bidsArray
+	return bidResponse, nil
+}
+
+func getMediaTypeForImp(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+	switch bid.MType {
+	case openrtb2.MarkupBanner:
+		return openrtb_ext.BidTypeBanner, nil
+	case openrtb2.MarkupVideo:
+		return openrtb_ext.BidTypeVideo, nil
+	case openrtb2.MarkupNative:
+		return openrtb_ext.BidTypeNative, nil
+	default:
+		return "", fmt.Errorf("unsupported MType %d", bid.MType)
+	}
+}
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/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go
index 0d5c35f9..fb4b1928 100644
--- a/endpoints/openrtb2/amp_auction.go
+++ b/endpoints/openrtb2/amp_auction.go
@@ -296,9 +296,6 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
 	}
 
 	labels, ao = sendAmpResponse(w, hookExecutor, auctionResponse, reqWrapper, account, labels, ao, errL)
-	if len(ao.Errors) == 0 && !auctionRequest.BidderResponseStartTime.IsZero() {
-		deps.metricsEngine.RecordOverheadTime(metrics.MakeAuctionResponse, time.Since(auctionRequest.BidderResponseStartTime))
-	}
 }
 
 func rejectAmpRequest(
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 8e01552c..edb478d2 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -292,9 +292,6 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http
 		glog.Errorf("Error setting seat non-bid: %v", err)
 	}
 	labels, ao = sendAuctionResponse(w, hookExecutor, response, req.BidRequest, account, labels, ao)
-	if len(ao.Errors) == 0 && !auctionRequest.BidderResponseStartTime.IsZero() {
-		deps.metricsEngine.RecordOverheadTime(metrics.MakeAuctionResponse, time.Since(auctionRequest.BidderResponseStartTime))
-	}
 }
 
 // setSeatNonBidRaw is transitional function for setting SeatNonBid inside bidResponse.Ext
diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go
index a2a1e03e..49e4585d 100644
--- a/endpoints/openrtb2/video_auction.go
+++ b/endpoints/openrtb2/video_auction.go
@@ -375,10 +375,6 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
 		return
 	}
 
-	if len(vo.Errors) == 0 && !auctionRequest.BidderResponseStartTime.IsZero() {
-		deps.metricsEngine.RecordOverheadTime(metrics.MakeAuctionResponse, time.Since(auctionRequest.BidderResponseStartTime))
-	}
-
 	w.Header().Set("Content-Type", "application/json")
 	w.Write(resp)
 
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 11529c5e..ac004cc4 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -140,6 +140,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/rtbhouse"
 	"github.com/prebid/prebid-server/adapters/rubicon"
 	salunamedia "github.com/prebid/prebid-server/adapters/sa_lunamedia"
+	"github.com/prebid/prebid-server/adapters/screencore"
 	"github.com/prebid/prebid-server/adapters/seedingAlliance"
 	"github.com/prebid/prebid-server/adapters/sharethrough"
 	"github.com/prebid/prebid-server/adapters/silvermob"
@@ -338,6 +339,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderRubicon:           rubicon.Builder,
 		openrtb_ext.BidderSeedingAlliance:   seedingAlliance.Builder,
 		openrtb_ext.BidderSaLunaMedia:       salunamedia.Builder,
+		openrtb_ext.BidderScreencore:        screencore.Builder,
 		openrtb_ext.BidderSharethrough:      sharethrough.Builder,
 		openrtb_ext.BidderSilverMob:         silvermob.Builder,
 		openrtb_ext.BidderSmaato:            smaato.Builder,
@@ -375,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/bidder.go b/exchange/bidder.go
index 5d9d5cba..838c46f7 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -63,11 +63,12 @@ type AdaptedBidder interface {
 
 // bidRequestOptions holds additional options for bid request execution to maintain clean code and reasonable number of parameters
 type bidRequestOptions struct {
-	accountDebugAllowed bool
-	headerDebugAllowed  bool
-	addCallSignHeader   bool
-	bidAdjustments      map[string]float64
-	tmaxAdjustments     *TmaxAdjustmentsPreprocessed
+	accountDebugAllowed    bool
+	headerDebugAllowed     bool
+	addCallSignHeader      bool
+	bidAdjustments         map[string]float64
+	tmaxAdjustments        *TmaxAdjustmentsPreprocessed
+	bidderRequestStartTime time.Time
 }
 
 type extraBidderRespInfo struct {
@@ -87,6 +88,8 @@ const (
 	Gzip string = "GZIP"
 )
 
+var errTmaxTimeout = errors.New("exceeded tmax duration")
+
 // AdaptBidder converts an adapters.Bidder into an exchange.AdaptedBidder.
 //
 // The name refers to the "Adapter" architecture pattern, and should not be confused with a Prebid "Adapter"
@@ -190,11 +193,11 @@ func (bidder *bidderAdapter) requestBid(ctx context.Context, bidderRequest Bidde
 		dataLen = len(reqData) + len(bidderRequest.BidderStoredResponses)
 		responseChannel = make(chan *httpCallInfo, dataLen)
 		if len(reqData) == 1 {
-			responseChannel <- bidder.doRequest(ctx, reqData[0], reqInfo.BidderRequestStartTime)
+			responseChannel <- bidder.doRequest(ctx, reqData[0], bidRequestOptions.bidderRequestStartTime, bidRequestOptions.tmaxAdjustments)
 		} else {
 			for _, oneReqData := range reqData {
 				go func(data *adapters.RequestData) {
-					responseChannel <- bidder.doRequest(ctx, data, reqInfo.BidderRequestStartTime)
+					responseChannel <- bidder.doRequest(ctx, data, bidRequestOptions.bidderRequestStartTime, bidRequestOptions.tmaxAdjustments)
 				}(oneReqData) // Method arg avoids a race condition on oneReqData
 			}
 		}
@@ -513,11 +516,11 @@ func makeExt(httpInfo *httpCallInfo) *openrtb_ext.ExtHttpCall {
 
 // doRequest makes a request, handles the response, and returns the data needed by the
 // Bidder interface.
-func (bidder *bidderAdapter) doRequest(ctx context.Context, req *adapters.RequestData, pbsRequestStartTime time.Time) *httpCallInfo {
-	return bidder.doRequestImpl(ctx, req, glog.Warningf, pbsRequestStartTime)
+func (bidder *bidderAdapter) doRequest(ctx context.Context, req *adapters.RequestData, bidderRequestStartTime time.Time, tmaxAdjustments *TmaxAdjustmentsPreprocessed) *httpCallInfo {
+	return bidder.doRequestImpl(ctx, req, glog.Warningf, bidderRequestStartTime, tmaxAdjustments)
 }
 
-func (bidder *bidderAdapter) doRequestImpl(ctx context.Context, req *adapters.RequestData, logger util.LogMsg, pbsRequestStartTime time.Time) *httpCallInfo {
+func (bidder *bidderAdapter) doRequestImpl(ctx context.Context, req *adapters.RequestData, logger util.LogMsg, bidderRequestStartTime time.Time, tmaxAdjustments *TmaxAdjustmentsPreprocessed) *httpCallInfo {
 	var requestBody []byte
 
 	switch strings.ToUpper(bidder.config.EndpointCompression) {
@@ -541,7 +544,18 @@ func (bidder *bidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re
 	if !bidder.config.DisableConnMetrics {
 		ctx = bidder.addClientTrace(ctx)
 	}
-	bidder.me.RecordOverheadTime(metrics.PreBidder, time.Since(pbsRequestStartTime))
+	bidder.me.RecordOverheadTime(metrics.PreBidder, time.Since(bidderRequestStartTime))
+
+	if tmaxAdjustments != nil && tmaxAdjustments.IsEnforced {
+		if hasShorterDurationThanTmax(&bidderTmaxCtx{ctx}, *tmaxAdjustments) {
+			bidder.me.RecordTMaxTimeout()
+			return &httpCallInfo{
+				request: req,
+				err:     errTmaxTimeout,
+			}
+		}
+	}
+
 	httpCallStart := time.Now()
 	httpResp, err := ctxhttp.Do(ctx, bidder.Client, httpReq)
 	if err != nil {
@@ -724,3 +738,16 @@ func getBidTypeForAdjustments(bidType openrtb_ext.BidType, impID string, imp []o
 	}
 	return string(bidType)
 }
+
+func hasShorterDurationThanTmax(ctx bidderTmaxContext, tmaxAdjustments TmaxAdjustmentsPreprocessed) bool {
+	if tmaxAdjustments.IsEnforced {
+		if deadline, ok := ctx.Deadline(); ok {
+			overheadNS := time.Duration(tmaxAdjustments.BidderNetworkLatencyBuffer+tmaxAdjustments.PBSResponsePreparationDuration) * time.Millisecond
+			bidderTmax := deadline.Add(-overheadNS)
+
+			remainingDuration := ctx.Until(bidderTmax).Milliseconds()
+			return remainingDuration < int64(tmaxAdjustments.BidderResponseDurationMin)
+		}
+	}
+	return false
+}
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 1436f3ea..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,
@@ -695,14 +692,14 @@ func (e *exchange) getAllBids(
 			reqInfo := adapters.NewExtraRequestInfo(conversions)
 			reqInfo.PbsEntryPoint = bidderRequest.BidderLabels.RType
 			reqInfo.GlobalPrivacyControlHeader = globalPrivacyControlHeader
-			reqInfo.BidderRequestStartTime = start
 
 			bidReqOptions := bidRequestOptions{
-				accountDebugAllowed: accountDebugAllowed,
-				headerDebugAllowed:  headerDebugAllowed,
-				addCallSignHeader:   isAdsCertEnabled(experiment, e.bidderInfo[string(bidderRequest.BidderName)]),
-				bidAdjustments:      bidAdjustments,
-				tmaxAdjustments:     tmaxAdjustments,
+				accountDebugAllowed:    accountDebugAllowed,
+				headerDebugAllowed:     headerDebugAllowed,
+				addCallSignHeader:      isAdsCertEnabled(experiment, e.bidderInfo[string(bidderRequest.BidderName)]),
+				bidAdjustments:         bidAdjustments,
+				tmaxAdjustments:        tmaxAdjustments,
+				bidderRequestStartTime: start,
 			}
 			seatBids, extraBidderRespInfo, err := e.adapterMap[bidderRequest.BidderCoreName].requestBid(ctx, bidderRequest, conversions, &reqInfo, e.adsCertSigner, bidReqOptions, alternateBidderCodes, hookExecutor, bidAdjustmentRules)
 			brw.bidderResponseStartTime = extraBidderRespInfo.respProcessingStartTime
@@ -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/tmax_adjustments.go b/exchange/tmax_adjustments.go
index 86934ecc..29e73299 100644
--- a/exchange/tmax_adjustments.go
+++ b/exchange/tmax_adjustments.go
@@ -36,6 +36,7 @@ func ProcessTMaxAdjustments(adjustmentsConfig config.TmaxAdjustments) *TmaxAdjus
 type bidderTmaxContext interface {
 	Deadline() (deadline time.Time, ok bool)
 	RemainingDurationMS(deadline time.Time) int64
+	Until(t time.Time) time.Duration
 }
 type bidderTmaxCtx struct{ ctx context.Context }
 
@@ -47,6 +48,11 @@ func (b *bidderTmaxCtx) Deadline() (deadline time.Time, ok bool) {
 	return
 }
 
+// Until returns the remaining duration until the specified time
+func (b *bidderTmaxCtx) Until(t time.Time) time.Duration {
+	return time.Until(t)
+}
+
 func getBidderTmax(ctx bidderTmaxContext, requestTmaxMS int64, tmaxAdjustments TmaxAdjustmentsPreprocessed) int64 {
 	if tmaxAdjustments.IsEnforced {
 		if deadline, ok := ctx.Deadline(); ok {
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 c873e9ab..26eaa422 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -236,6 +236,7 @@ const (
 	BidderRubicon           BidderName = "rubicon"
 	BidderSeedingAlliance   BidderName = "seedingAlliance"
 	BidderSaLunaMedia       BidderName = "sa_lunamedia"
+	BidderScreencore        BidderName = "screencore"
 	BidderSharethrough      BidderName = "sharethrough"
 	BidderSilverMob         BidderName = "silvermob"
 	BidderSmaato            BidderName = "smaato"
@@ -273,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"
@@ -437,6 +439,7 @@ func CoreBidderNames() []BidderName {
 		BidderRubicon,
 		BidderSeedingAlliance,
 		BidderSaLunaMedia,
+		BidderScreencore,
 		BidderSharethrough,
 		BidderSilverMob,
 		BidderSmaato,
@@ -474,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/openrtb_ext/imp_freewheelssp.go b/openrtb_ext/imp_freewheelssp.go
index 11c22ff8..110f018f 100644
--- a/openrtb_ext/imp_freewheelssp.go
+++ b/openrtb_ext/imp_freewheelssp.go
@@ -1,5 +1,9 @@
 package openrtb_ext
 
+import (
+	"github.com/prebid/prebid-server/util/jsonutil"
+)
+
 type ImpExtFreewheelSSP struct {
-	ZoneId int `json:"zoneId"`
+	ZoneId jsonutil.StringInt `json:"zoneId"`
 }
diff --git a/openrtb_ext/imp_rise.go b/openrtb_ext/imp_rise.go
index 4bdd302e..7311f05d 100644
--- a/openrtb_ext/imp_rise.go
+++ b/openrtb_ext/imp_rise.go
@@ -3,4 +3,5 @@ package openrtb_ext
 // ImpExtRise defines the contract for bidrequest.imp[i].ext.prebid.bidder.rise
 type ImpExtRise struct {
 	PublisherID string `json:"publisher_id"`
+	Org         string `json:"org"`
 }
diff --git a/openrtb_ext/imp_screencore.go b/openrtb_ext/imp_screencore.go
new file mode 100644
index 00000000..5a3fa1c3
--- /dev/null
+++ b/openrtb_ext/imp_screencore.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ExtScreencore struct {
+	AccountID   string `json:"accountId"`
+	PlacementID string `json:"placementId"`
+}
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/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/conversant.yaml b/static/bidder-info/conversant.yaml
index 2135544d..7ffd2761 100644
--- a/static/bidder-info/conversant.yaml
+++ b/static/bidder-info/conversant.yaml
@@ -13,6 +13,6 @@ capabilities:
       - video
 userSync:
   redirect:
-    url: "https://prebid-match.dotomi.com/match/bounce/current?version=1&networkId=72582&rurl={{.RedirectURL}}"
+    url: "https://prebid-match.dotomi.com/match/bounce/current?version=1&networkId=72582&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&rurl={{.RedirectURL}}"
     userMacro: ""
     # epsilon appends the user id to end of the redirect url and does not utilize a macro
diff --git a/static/bidder-info/screencore.yaml b/static/bidder-info/screencore.yaml
new file mode 100644
index 00000000..67777a13
--- /dev/null
+++ b/static/bidder-info/screencore.yaml
@@ -0,0 +1,14 @@
+endpoint: 'http://h1.screencore.io/?kp={{.AccountID}}&kn={{.SourceId}}'
+maintainer:
+  email: 'connect@screencore.io'
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
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/freewheel-ssp.json b/static/bidder-params/freewheel-ssp.json
index 103aed03..23375f76 100644
--- a/static/bidder-params/freewheel-ssp.json
+++ b/static/bidder-params/freewheel-ssp.json
@@ -6,7 +6,7 @@
 
   "properties": {
     "zoneId": {
-      "type": "integer",
+      "type": ["integer", "string"],
       "description": "Zone ID"
     }
   },
diff --git a/static/bidder-params/freewheelssp.json b/static/bidder-params/freewheelssp.json
index 6f93501a..ced3c28d 100644
--- a/static/bidder-params/freewheelssp.json
+++ b/static/bidder-params/freewheelssp.json
@@ -6,7 +6,7 @@
 
   "properties": {
     "zoneId": {
-      "type": "integer",
+      "type": ["integer", "string"],
       "description": "Zone ID"
     }
   },
diff --git a/static/bidder-params/rise.json b/static/bidder-params/rise.json
index 8e745d89..c5344b7a 100644
--- a/static/bidder-params/rise.json
+++ b/static/bidder-params/rise.json
@@ -4,10 +4,17 @@
   "description": "A schema which validates params accepted by the Rise adapter",
   "type": "object",
   "properties": {
+    "org": {
+      "type": "string",
+      "description": "The organization ID."
+    },
     "publisher_id": {
       "type": "string",
-      "description": "The publisher ID"
+      "description": "Deprecated, use org instead."
     }
   },
-  "required": ["publisher_id"]
+  "oneOf": [
+    { "required": ["org"] },
+    { "required": ["publisher_id"] }
+  ]
 }
diff --git a/static/bidder-params/screencore.json b/static/bidder-params/screencore.json
new file mode 100644
index 00000000..0a181b20
--- /dev/null
+++ b/static/bidder-params/screencore.json
@@ -0,0 +1,22 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "Screencore Adapter Params",
+    "description": "A schema which validates params accepted by the Screencore adapter",
+    "type": "object",
+    "properties": {
+        "accountId": {
+            "type": "string",
+            "description": "Account id",
+            "minLength": 1
+        },
+        "placementId": {
+            "type": "string",
+            "description": "Placement id",
+            "minLength": 1
+        }
+    },
+    "required": [
+        "accountId",
+        "placementId"
+    ]
+}
\ No newline at end of file
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/freewheelssp/freewheelssptest/exemplary/multi-imp.json b/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json
index 5ec36993..e6838240 100644
--- a/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json
+++ b/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json
@@ -14,7 +14,7 @@
         },
         "ext": {
           "bidder": {
-            "zoneId": 12345
+            "zoneId": "12345"
           }
         }
       },
diff --git a/adapters/freewheelssp/freewheelssptest/exemplary/string-single-imp.json b/adapters/freewheelssp/freewheelssptest/exemplary/string-single-imp.json
new file mode 100644
index 00000000..c17c7167
--- /dev/null
+++ b/adapters/freewheelssp/freewheelssptest/exemplary/string-single-imp.json
@@ -0,0 +1,97 @@
+{
+  "mockBidRequest": {
+    "id": "freewheelssp-test",
+    "site": {
+      "page": "prebid.org"
+    },
+    "imp": [
+      {
+        "id": "imp-1",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 300,
+          "h": 250
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "12345"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://testjsonsample.com",
+        "body":{
+          "id": "freewheelssp-test",
+          "site": {
+            "page": "prebid.org"
+          },
+          "imp": [{
+            "id": "imp-1",
+            "video": {
+              "mimes": ["video/mp4"],
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "zoneId": 12345
+            }
+          }]
+        },
+        "headers": {
+          "Componentid": [
+            "prebid-go"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "freewheelssp-test",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "12345_freewheelssp-test_1",
+                  "impid": "imp-1",
+                  "price": 1.0,
+                  "adid": "7857",
+                  "adm": "<?xml version='1.0' encoding='UTF-8'?><VAST version='2.0'></VAST>",
+                  "cid": "4001",
+                  "crid": "7857"
+                }
+              ],
+              "seat": "freewheelsspTv"
+            }
+          ],
+          "bidid": "freewheelssp-test",
+          "cur": "EUR"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "CUR",
+      "bids": [
+        {
+          "bid":  {
+            "id": "12345_freewheelssp-test_1",
+            "impid": "imp-1",
+            "price": 1.0,
+            "adid": "7857",
+            "adm": "<?xml version='1.0' encoding='UTF-8'?><VAST version='2.0'></VAST>",
+            "cid": "4001",
+            "crid": "7857"
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/freewheelssp/freewheelssptest/supplemental/zoneid_error.json b/adapters/freewheelssp/freewheelssptest/supplemental/zoneid_error.json
new file mode 100644
index 00000000..b45296ab
--- /dev/null
+++ b/adapters/freewheelssp/freewheelssptest/supplemental/zoneid_error.json
@@ -0,0 +1,29 @@
+{
+  "mockBidRequest": {
+    "id": "freewheelssp-test",
+    "site": {
+      "page": "prebid.org"
+    },
+    "imp": [
+      {
+        "id": "imp-1",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 300,
+          "h": 250
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "abc123"
+          }
+        }
+      }
+    ]
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": ".*Invalid imp.ext for impression index 0.*",
+      "comparison": "regex"
+    }
+  ]
+}
\ No newline at end of file
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/adapters/rise/risetest/exemplary/banner-and-video-app.json b/adapters/rise/risetest/exemplary/banner-and-video-app.json
index 9eb79156..fa267977 100644
--- a/adapters/rise/risetest/exemplary/banner-and-video-app.json
+++ b/adapters/rise/risetest/exemplary/banner-and-video-app.json
@@ -18,7 +18,7 @@
         },
         "ext": {
           "bidder": {
-            "publisher_id": "72721",
+            "org": "72721",
             "path": "mvo",
             "zone": "1r"
           }
@@ -41,7 +41,7 @@
         },
         "ext": {
           "bidder": {
-            "publisher_id": "72721",
+            "org": "72721",
             "path": "mvo",
             "zone": "1r"
           }
@@ -98,7 +98,7 @@
               },
               "ext": {
                 "bidder": {
-                  "publisher_id": "72721",
+                  "org": "72721",
                   "zone": "1r",
                   "path": "mvo"
                 }
@@ -121,7 +121,7 @@
               },
               "ext": {
                 "bidder": {
-                  "publisher_id": "72721",
+                  "org": "72721",
                   "zone": "1r",
                   "path": "mvo"
                 }
diff --git a/adapters/rise/risetest/exemplary/banner-and-video-gdpr.json b/adapters/rise/risetest/exemplary/banner-and-video-gdpr.json
index dfdf54a8..980b6244 100644
--- a/adapters/rise/risetest/exemplary/banner-and-video-gdpr.json
+++ b/adapters/rise/risetest/exemplary/banner-and-video-gdpr.json
@@ -18,7 +18,7 @@
         },
         "ext": {
           "bidder": {
-            "publisher_id": "72721",
+            "org": "72721",
             "path": "mvo",
             "zone": "1r"
           }
@@ -41,7 +41,7 @@
         },
         "ext": {
           "bidder": {
-            "publisher_id": "72721",
+            "org": "72721",
             "path": "mvo",
             "zone": "1r"
           }
@@ -83,7 +83,7 @@
               },
               "ext": {
                 "bidder": {
-                  "publisher_id": "72721",
+                  "org": "72721",
                   "zone": "1r",
                   "path": "mvo"
                 }
@@ -106,7 +106,7 @@
               },
               "ext": {
                 "bidder": {
-                  "publisher_id": "72721",
+                  "org": "72721",
                   "zone": "1r",
                   "path": "mvo"
                 }
diff --git a/adapters/rise/risetest/exemplary/banner-and-video.json b/adapters/rise/risetest/exemplary/banner-and-video.json
index 2a2e3f68..d0d6a9bc 100644
--- a/adapters/rise/risetest/exemplary/banner-and-video.json
+++ b/adapters/rise/risetest/exemplary/banner-and-video.json
@@ -55,7 +55,7 @@
         },
         "ext": {
           "bidder": {
-            "publisher_id": "72721",
+            "org": "72721",
             "path": "mvo",
             "zone": "1r"
           }
@@ -123,7 +123,7 @@
               },
               "ext": {
                 "bidder": {
-                  "publisher_id": "72721",
+                  "org": "72721",
                   "zone": "1r",
                   "path": "mvo"
                 }
diff --git a/adapters/rise/risetest/exemplary/simple-banner-both-ids.json b/adapters/rise/risetest/exemplary/simple-banner-both-ids.json
new file mode 100644
index 00000000..cb6bbfa7
--- /dev/null
+++ b/adapters/rise/risetest/exemplary/simple-banner-both-ids.json
@@ -0,0 +1,117 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 300
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "org": "72720",
+            "publisher_id": "72721",
+            "path": "mvo",
+            "zone": "1r"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://localhost/prebid_server?publisher_id=72720",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 300
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "org": "72720",
+                  "publisher_id": "72721",
+                  "zone": "1r",
+                  "path": "mvo"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "Rhythmone",
+              "bid": [
+                {
+                  "id": "7706636740145184841",
+                  "impid": "test-imp-id",
+                  "price": 0.500000,
+                  "adid": "29681110",
+                  "adm": "some-test-ad",
+                  "adomain": [
+                    "yahoo.com"
+                  ],
+                  "cid": "958",
+                  "crid": "29681110",
+                  "h": 250,
+                  "w": 300,
+                  "mtype": 1
+                }
+              ]
+            }
+          ],
+          "bidid": "5778926625248726496",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [{
+        "bid": {
+          "id": "7706636740145184841",
+          "impid": "test-imp-id",
+          "price": 0.5,
+          "adm": "some-test-ad",
+          "adid": "29681110",
+          "adomain": [
+            "yahoo.com"
+          ],
+          "cid": "958",
+          "crid": "29681110",
+          "w": 300,
+          "h": 250,
+          "mtype": 1
+        },
+        "type": "banner"
+      }]
+    }
+  ]
+}
diff --git a/adapters/rise/risetest/exemplary/simple-video.json b/adapters/rise/risetest/exemplary/simple-video.json
index 16ca8ac7..921736a6 100644
--- a/adapters/rise/risetest/exemplary/simple-video.json
+++ b/adapters/rise/risetest/exemplary/simple-video.json
@@ -21,7 +21,7 @@
         },
         "ext": {
           "bidder": {
-            "publisher_id": "72721",
+            "org": "72721",
             "path": "mvo",
             "zone": "1r"
           }
@@ -55,7 +55,7 @@
               },
               "ext": {
                 "bidder": {
-                  "publisher_id": "72721",
+                  "org": "72721",
                   "zone": "1r",
                   "path": "mvo"
                 }
diff --git a/adapters/rise/risetest/supplemental/bad-request.json b/adapters/rise/risetest/supplemental/bad-request.json
index f2ba84b1..b5bedc09 100644
--- a/adapters/rise/risetest/supplemental/bad-request.json
+++ b/adapters/rise/risetest/supplemental/bad-request.json
@@ -21,7 +21,7 @@
         },
         "ext": {
           "bidder": {
-            "publisher_id": "72721",
+            "org": "72721",
             "path": "mvo",
             "zone": "1r"
           }
@@ -55,7 +55,7 @@
               },
               "ext": {
                 "bidder": {
-                  "publisher_id": "72721",
+                  "org": "72721",
                   "zone": "1r",
                   "path": "mvo"
                 }
diff --git a/adapters/rise/risetest/supplemental/missing-bidder.json b/adapters/rise/risetest/supplemental/missing-bidder.json
index 2bda5161..0a7cc67c 100644
--- a/adapters/rise/risetest/supplemental/missing-bidder.json
+++ b/adapters/rise/risetest/supplemental/missing-bidder.json
@@ -28,7 +28,7 @@
   },
   "expectedMakeRequestsErrors": [
     {
-      "value": "extractPublisherID: unmarshal ImpExtRise: unexpected end of JSON input",
+      "value": "extractOrg: unmarshal ImpExtRise: unexpected end of JSON input",
       "comparison": "literal"
     }
   ]
diff --git a/adapters/rise/risetest/supplemental/missing-extension.json b/adapters/rise/risetest/supplemental/missing-extension.json
index db8dbdf7..74e94f45 100644
--- a/adapters/rise/risetest/supplemental/missing-extension.json
+++ b/adapters/rise/risetest/supplemental/missing-extension.json
@@ -27,7 +27,7 @@
   },
   "expectedMakeRequestsErrors": [
     {
-      "value": "extractPublisherID: unmarshal bidderExt: unexpected end of JSON input",
+      "value": "extractOrg: unmarshal bidderExt: unexpected end of JSON input",
       "comparison": "literal"
     }
   ]
diff --git a/adapters/rise/risetest/supplemental/missing-mtype.json b/adapters/rise/risetest/supplemental/missing-mtype.json
index be45db58..5693f25a 100644
--- a/adapters/rise/risetest/supplemental/missing-mtype.json
+++ b/adapters/rise/risetest/supplemental/missing-mtype.json
@@ -21,7 +21,7 @@
         },
         "ext": {
           "bidder": {
-            "publisher_id": "72721",
+            "org": "72721",
             "path": "mvo",
             "zone": "1r"
           }
@@ -55,7 +55,7 @@
               },
               "ext": {
                 "bidder": {
-                  "publisher_id": "72721",
+                  "org": "72721",
                   "zone": "1r",
                   "path": "mvo"
                 }
diff --git a/adapters/rise/risetest/supplemental/missing-publisher-id.json b/adapters/rise/risetest/supplemental/missing-org.json
similarity index 89%
rename from adapters/rise/risetest/supplemental/missing-publisher-id.json
rename to adapters/rise/risetest/supplemental/missing-org.json
index 3a14b213..4107d40e 100644
--- a/adapters/rise/risetest/supplemental/missing-publisher-id.json
+++ b/adapters/rise/risetest/supplemental/missing-org.json
@@ -24,6 +24,7 @@
         },
         "ext": {
           "bidder": {
+            "org": "",
             "publisher_id": ""
           }}
       }
@@ -31,7 +32,7 @@
   },
   "expectedMakeRequestsErrors": [
     {
-      "value": "extractPublisherID: no publisherID supplied",
+      "value": "extractOrg: no org or publisher_id supplied",
       "comparison": "literal"
     }
   ]
diff --git a/adapters/screencore/params_test.go b/adapters/screencore/params_test.go
new file mode 100644
index 00000000..faa2f854
--- /dev/null
+++ b/adapters/screencore/params_test.go
@@ -0,0 +1,50 @@
+package screencore
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+var validParams = []string{
+	`{  "accountId": "hash",  "placementId": "hash"}`,
+}
+
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderScreencore, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected Screencore params: %s", validParam)
+		}
+	}
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`5.2`,
+	`[]`,
+	`{}`,
+	`{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`,
+	`{ "placementId": "", "accountId": "" }`,
+}
+
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderScreencore, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
diff --git a/adapters/screencore/screencore_test.go b/adapters/screencore/screencore_test.go
new file mode 100644
index 00000000..6ee7f3ad
--- /dev/null
+++ b/adapters/screencore/screencore_test.go
@@ -0,0 +1,20 @@
+package screencore
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderScreencore, config.Adapter{
+		Endpoint: "http://h1.screencore.io/?kp={{.AccountID}}&kn={{.SourceId}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "screencoretest", bidder)
+}
diff --git a/adapters/screencore/screencoretest/exemplary/banner-app.json b/adapters/screencore/screencoretest/exemplary/banner-app.json
new file mode 100644
index 00000000..0b75398d
--- /dev/null
+++ b/adapters/screencore/screencoretest/exemplary/banner-app.json
@@ -0,0 +1,152 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "1",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "1",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "1",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50,
+                  "mtype": 1
+                }
+              ],
+              "type": "banner",
+              "seat": "screencore"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "1",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 320,
+            "h": 50,
+            "mtype": 1
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/exemplary/banner-web.json b/adapters/screencore/screencoretest/exemplary/banner-web.json
new file mode 100644
index 00000000..a9eed6bf
--- /dev/null
+++ b/adapters/screencore/screencoretest/exemplary/banner-web.json
@@ -0,0 +1,197 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id1",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      },
+      {
+        "id": "some-impression-id2",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id1",
+              "tagid": "ogTAGID",
+              "banner": {
+                "w": 320,
+                "h": 50
+              }
+            },
+            {
+              "id": "some-impression-id2",
+              "tagid": "ogTAGID",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "ext": {
+                "bidder": {
+                  "accountId": "accountId",
+                  "placementId": "placementId"
+                }
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id1",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50,
+                  "mtype": 1
+                },
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e162",
+                  "impid": "some-impression-id2",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50,
+                  "mtype": 1
+                }
+              ],
+              "type": "banner",
+              "seat": "screencore"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id1",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 320,
+            "h": 50,
+            "mtype": 1
+          },
+          "type": "banner"
+        },
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e162",
+            "impid": "some-impression-id2",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 320,
+            "h": 50,
+            "mtype": 1
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/exemplary/native-app.json b/adapters/screencore/screencoretest/exemplary/native-app.json
new file mode 100644
index 00000000..eece64ee
--- /dev/null
+++ b/adapters/screencore/screencoretest/exemplary/native-app.json
@@ -0,0 +1,148 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "native": {
+          "ver": "1.1",
+          "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "native": {
+                "ver": "1.1",
+                "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "mtype": 4
+                }
+              ],
+              "type": "native",
+              "seat": "screencore"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "mtype": 4
+          },
+          "type": "native"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/exemplary/native-web.json b/adapters/screencore/screencoretest/exemplary/native-web.json
new file mode 100644
index 00000000..5878519f
--- /dev/null
+++ b/adapters/screencore/screencoretest/exemplary/native-web.json
@@ -0,0 +1,135 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "native": {
+          "ver": "1.1",
+          "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "2607:fb90:f27:4512:d800:cb23:a603:e245"
+          ]
+        },
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "native": {
+                "ver": "1.1",
+                "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "mtype": 4
+                }
+              ],
+              "seat": "screencore"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "mtype": 4
+          },
+          "type": "native"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/exemplary/video-app.json b/adapters/screencore/screencoretest/exemplary/video-app.json
new file mode 100644
index 00000000..7368af33
--- /dev/null
+++ b/adapters/screencore/screencoretest/exemplary/video-app.json
@@ -0,0 +1,161 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 1280,
+                  "h": 720,
+                  "mtype": 2
+                }
+              ],
+              "seat": "screencore"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 1280,
+            "h": 720,
+            "mtype": 2
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/exemplary/video-web.json b/adapters/screencore/screencoretest/exemplary/video-web.json
new file mode 100644
index 00000000..a56ddb78
--- /dev/null
+++ b/adapters/screencore/screencoretest/exemplary/video-web.json
@@ -0,0 +1,159 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 1280,
+                  "h": 720,
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  },
+                  "mtype": 2
+                }
+              ],
+              "seat": "screencore"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 1280,
+            "h": 720,
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            },
+            "mtype": 2
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/bad_media_type.json b/adapters/screencore/screencoretest/supplemental/bad_media_type.json
new file mode 100644
index 00000000..ed7200c5
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/bad_media_type.json
@@ -0,0 +1,135 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "1",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "1",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "test-imp-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                }
+              ],
+              "mtype": 0,
+              "seat": "screencore"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "unsupported MType 0",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/empty-imp-array.json b/adapters/screencore/screencoretest/supplemental/empty-imp-array.json
new file mode 100644
index 00000000..e19996fb
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/empty-imp-array.json
@@ -0,0 +1,16 @@
+{
+    "expectedMakeRequestsErrors": [
+      {
+        "value": "Empty Imp array in BidRequest",
+        "comparison": "literal"
+      }
+    ],
+    "mockBidRequest": {
+      "id": "test-request-id",
+      "imp": [],
+      "site": {
+        "page": "test.com"
+      }
+    },
+    "httpCalls": []
+  }
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/empty-seatbid-array.json b/adapters/screencore/screencoretest/supplemental/empty-seatbid-array.json
new file mode 100644
index 00000000..0ed6159a
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/empty-seatbid-array.json
@@ -0,0 +1,130 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "mockResponse": {
+    "status": 200,
+    "body": "invalid response"
+  },
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid array",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/invalid-bidder-ext-object.json b/adapters/screencore/screencoretest/supplemental/invalid-bidder-ext-object.json
new file mode 100644
index 00000000..4dc5c5a6
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/invalid-bidder-ext-object.json
@@ -0,0 +1,33 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Error parsing bidderExt - json: cannot unmarshal string into Go value of type openrtb_ext.ExtScreencore",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "my-adcode",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": "wrongBidderExt"
+        }
+      }
+    ],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/invalid-response.json b/adapters/screencore/screencoretest/supplemental/invalid-response.json
new file mode 100644
index 00000000..b2417d9d
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/invalid-response.json
@@ -0,0 +1,112 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": "invalid response"
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bad Server Response",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/invalid-screencore-ext-object.json b/adapters/screencore/screencoretest/supplemental/invalid-screencore-ext-object.json
new file mode 100644
index 00000000..b52e18fa
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/invalid-screencore-ext-object.json
@@ -0,0 +1,31 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Error parsing screencoreExt - json: cannot unmarshal string into Go value of type adapters.ExtImpBidder",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "my-adcode",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": "wrongscreencoreExt"
+      }
+    ],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/status-code-bad-request.json b/adapters/screencore/screencoretest/supplemental/status-code-bad-request.json
new file mode 100644
index 00000000..68deeef9
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/status-code-bad-request.json
@@ -0,0 +1,93 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "publisher": {
+              "id": "123456789"
+            },
+            "cat": [
+              "IAB22-1"
+            ],
+            "bundle": "com.app.awesome",
+            "name": "Awesome App",
+            "domain": "awesomeapp.com",
+            "id": "123456789"
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 400
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/status-code-no-content.json b/adapters/screencore/screencoretest/supplemental/status-code-no-content.json
new file mode 100644
index 00000000..1b6fa699
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/status-code-no-content.json
@@ -0,0 +1,76 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 204
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": []
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/status-code-other-error.json b/adapters/screencore/screencoretest/supplemental/status-code-other-error.json
new file mode 100644
index 00000000..994b33f2
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/status-code-other-error.json
@@ -0,0 +1,81 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 306
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 306. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/screencore/screencoretest/supplemental/status-code-service-unavailable.json b/adapters/screencore/screencoretest/supplemental/status-code-service-unavailable.json
new file mode 100644
index 00000000..b885df20
--- /dev/null
+++ b/adapters/screencore/screencoretest/supplemental/status-code-service-unavailable.json
@@ -0,0 +1,81 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId",
+        "body": {
+          "id": "some-request-id",
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 503
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Something went wrong Status Code: [ 503 ] ",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go
index 3eeb3e90..e2d476c0 100644
--- a/exchange/bidder_test.go
+++ b/exchange/bidder_test.go
@@ -555,11 +555,11 @@ func TestBidderTimeout(t *testing.T) {
 		Client:     server.Client(),
 		me:         &metricsConfig.NilMetricsEngine{},
 	}
-
+	tmaxAdjustments := &TmaxAdjustmentsPreprocessed{}
 	callInfo := bidder.doRequest(ctx, &adapters.RequestData{
 		Method: "POST",
 		Uri:    server.URL,
-	}, time.Now())
+	}, time.Now(), tmaxAdjustments)
 	if callInfo.err == nil {
 		t.Errorf("The bidder should report an error if the context has expired already.")
 	}
@@ -575,10 +575,10 @@ func TestInvalidRequest(t *testing.T) {
 		Bidder: &mixedMultiBidder{},
 		Client: server.Client(),
 	}
-
+	tmaxAdjustments := &TmaxAdjustmentsPreprocessed{}
 	callInfo := bidder.doRequest(context.Background(), &adapters.RequestData{
 		Method: "\"", // force http.NewRequest() to fail
-	}, time.Now())
+	}, time.Now(), tmaxAdjustments)
 	if callInfo.err == nil {
 		t.Errorf("bidderAdapter.doRequest should return an error if the request data is malformed.")
 	}
@@ -598,11 +598,11 @@ func TestConnectionClose(t *testing.T) {
 		BidderName: openrtb_ext.BidderAppnexus,
 		me:         &metricsConfig.NilMetricsEngine{},
 	}
-
+	tmaxAdjustments := &TmaxAdjustmentsPreprocessed{}
 	callInfo := bidder.doRequest(context.Background(), &adapters.RequestData{
 		Method: "POST",
 		Uri:    server.URL,
-	}, time.Now())
+	}, time.Now(), tmaxAdjustments)
 	if callInfo.err == nil {
 		t.Errorf("bidderAdapter.doRequest should return an error if the connection closes unexpectedly.")
 	}
@@ -2107,9 +2107,10 @@ func TestCallRecordDNSTime(t *testing.T) {
 		Client: &http.Client{Transport: DNSDoneTripper{}},
 		me:     metricsMock,
 	}
+	tmaxAdjustments := &TmaxAdjustmentsPreprocessed{}
 
 	// Run test
-	bidder.doRequest(context.Background(), &adapters.RequestData{Method: "POST", Uri: "http://www.example.com/"}, time.Now())
+	bidder.doRequest(context.Background(), &adapters.RequestData{Method: "POST", Uri: "http://www.example.com/"}, time.Now(), tmaxAdjustments)
 
 	// Tried one or another, none seem to work without panicking
 	metricsMock.AssertExpectations(t)
@@ -2130,9 +2131,10 @@ func TestCallRecordTLSHandshakeTime(t *testing.T) {
 		Client: &http.Client{Transport: TLSHandshakeTripper{}},
 		me:     metricsMock,
 	}
+	tmaxAdjustments := &TmaxAdjustmentsPreprocessed{}
 
 	// Run test
-	bidder.doRequest(context.Background(), &adapters.RequestData{Method: "POST", Uri: "http://www.example.com/"}, time.Now())
+	bidder.doRequest(context.Background(), &adapters.RequestData{Method: "POST", Uri: "http://www.example.com/"}, time.Now(), tmaxAdjustments)
 
 	// Tried one or another, none seem to work without panicking
 	metricsMock.AssertExpectations(t)
@@ -2219,8 +2221,8 @@ func TestTimeoutNotificationOn(t *testing.T) {
 	logger := func(msg string, args ...interface{}) {
 		loggerBuffer.WriteString(fmt.Sprintf(fmt.Sprintln(msg), args...))
 	}
-
-	bidderAdapter.doRequestImpl(ctx, &bidRequest, logger, time.Now())
+	tmaxAdjustments := &TmaxAdjustmentsPreprocessed{}
+	bidderAdapter.doRequestImpl(ctx, &bidRequest, logger, time.Now(), tmaxAdjustments)
 
 	// Wait a little longer than the 205ms mock server sleep.
 	time.Sleep(210 * time.Millisecond)
@@ -3065,8 +3067,8 @@ func TestGetBidType(t *testing.T) {
 }
 
 type mockBidderTmaxCtx struct {
-	startTime, deadline time.Time
-	ok                  bool
+	startTime, deadline, now time.Time
+	ok                       bool
 }
 
 func (m *mockBidderTmaxCtx) Deadline() (deadline time.Time, _ bool) {
@@ -3076,6 +3078,10 @@ func (m *mockBidderTmaxCtx) RemainingDurationMS(deadline time.Time) int64 {
 	return deadline.Sub(m.startTime).Milliseconds()
 }
 
+func (m *mockBidderTmaxCtx) Until(t time.Time) time.Duration {
+	return t.Sub(m.now)
+}
+
 func TestUpdateBidderTmax(t *testing.T) {
 	respStatus := 200
 	respBody := "{\"bid\":false}"
@@ -3129,9 +3135,10 @@ func TestUpdateBidderTmax(t *testing.T) {
 				bidResponse: &adapters.BidderResponse{},
 			}
 
-			ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(50*time.Millisecond))
+			now := time.Now()
+			ctx, cancel := context.WithDeadline(context.Background(), now.Add(500*time.Millisecond))
 			defer cancel()
-			bidReqOptions := bidRequestOptions{tmaxAdjustments: test.tmaxAdjustments}
+			bidReqOptions := bidRequestOptions{bidderRequestStartTime: now, tmaxAdjustments: test.tmaxAdjustments}
 			bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, &config.DebugInfo{Allow: false}, "")
 			_, _, errs := bidder.requestBid(ctx, bidderReq, currencyConverter.Rates(), extraInfo, &adscert.NilSigner{}, bidReqOptions, openrtb_ext.ExtAlternateBidderCodes{}, &hookexecution.EmptyHookExecutor{}, nil)
 			assert.Empty(t, errs)
@@ -3139,3 +3146,173 @@ func TestUpdateBidderTmax(t *testing.T) {
 		})
 	}
 }
+
+func TestHasShorterDurationThanTmax(t *testing.T) {
+	var requestTmaxMS int64 = 700
+	requestTmaxNS := requestTmaxMS * int64(time.Millisecond)
+	startTime := time.Date(2023, 5, 30, 1, 0, 0, 0, time.UTC)
+	now := time.Date(2023, 5, 30, 1, 0, 0, int(200*time.Millisecond), time.UTC)
+	deadline := time.Date(2023, 5, 30, 1, 0, 0, int(requestTmaxNS), time.UTC)
+	ctx := &mockBidderTmaxCtx{startTime: startTime, deadline: deadline, now: now, ok: true}
+
+	tests := []struct {
+		description     string
+		ctx             bidderTmaxContext
+		requestTmax     int64
+		tmaxAdjustments TmaxAdjustmentsPreprocessed
+		expected        bool
+	}{
+		{
+			description:     "tmax-disabled",
+			ctx:             ctx,
+			requestTmax:     requestTmaxMS,
+			tmaxAdjustments: TmaxAdjustmentsPreprocessed{IsEnforced: false},
+			expected:        false,
+		},
+		{
+			description:     "remaing-duration-greater-than-bidder-response-min",
+			ctx:             ctx,
+			requestTmax:     requestTmaxMS,
+			tmaxAdjustments: TmaxAdjustmentsPreprocessed{IsEnforced: true, PBSResponsePreparationDuration: 50, BidderNetworkLatencyBuffer: 10, BidderResponseDurationMin: 40},
+			expected:        false,
+		},
+		{
+			description:     "remaing-duration-less-than-bidder-response-min",
+			ctx:             ctx,
+			requestTmax:     requestTmaxMS,
+			tmaxAdjustments: TmaxAdjustmentsPreprocessed{IsEnforced: true, PBSResponsePreparationDuration: 100, BidderNetworkLatencyBuffer: 10, BidderResponseDurationMin: 500},
+			expected:        true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.description, func(t *testing.T) {
+			assert.Equal(t, test.expected, hasShorterDurationThanTmax(test.ctx, test.tmaxAdjustments))
+		})
+	}
+}
+
+func TestDoRequestImplWithTmax(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"}}}`),
+	}
+
+	bidderAdapter := bidderAdapter{
+		me:     &metricsConfig.NilMetricsEngine{},
+		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) },
+		},
+		{
+			ctxDeadline:     time.Now().Add(5 * time.Second),
+			description:     "remaining-duration-greater-than-tmax-min",
+			tmaxAdjustments: &TmaxAdjustmentsPreprocessed{IsEnforced: true, PBSResponsePreparationDuration: 100, BidderNetworkLatencyBuffer: 10, BidderResponseDurationMin: 100},
+			assertFn:        func(err error) { assert.Nil(t, err) },
+		},
+		{
+			description:     "tmax-disabled",
+			tmaxAdjustments: &TmaxAdjustmentsPreprocessed{IsEnforced: false},
+			assertFn:        func(err error) { assert.Nil(t, err) },
+		},
+		{
+			description:     "tmax-BidderResponseDurationMin-not-set",
+			tmaxAdjustments: &TmaxAdjustmentsPreprocessed{IsEnforced: true, BidderResponseDurationMin: 0},
+			assertFn:        func(err error) { assert.Nil(t, err) },
+		},
+		{
+			description:     "tmax-is-nil",
+			tmaxAdjustments: nil,
+			assertFn:        func(err error) { assert.Nil(t, 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)
+	}
+}
+
+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"},
 				},