Repository: prebid/prebid-server
Pull request #2249 (2022-05-18 03:15:44)

New Adapter: StroeerCore

philipwatson: https://github.com/prebid/prebid.github.io/pull/3781

Patch:
diff --git a/adapters/bliink/bliink.go b/adapters/bliink/bliink.go
new file mode 100644
index 00000000..6e179a3f
--- /dev/null
+++ b/adapters/bliink/bliink.go
@@ -0,0 +1,120 @@
+package bliink
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"net/http"
+)
+
+type adapter struct {
+	endpoint string
+}
+
+// Builder builds a new instance of the Bliink adapter for the given bidder with the given config.
+func Builder(_ openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+
+	return bidder, nil
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	requestJSON, err := json.Marshal(request)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	headers.Add("x-openrtb-version", "2.5")
+
+	requestData := &adapters.RequestData{
+		Method:  "POST",
+		Uri:     a.endpoint,
+		Body:    requestJSON,
+		Headers: headers,
+	}
+
+	return []*adapters.RequestData{requestData}, nil
+}
+
+func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if responseData.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if responseData.StatusCode == http.StatusBadRequest {
+		err := &errortypes.BadInput{
+			Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.",
+		}
+		return nil, []error{err}
+	}
+
+	if responseData.StatusCode != http.StatusOK {
+		err := &errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode),
+		}
+		return nil, []error{err}
+	}
+
+	var response openrtb2.BidResponse
+	if err := json.Unmarshal(responseData.Body, &response); err != nil {
+		return nil, []error{err}
+	}
+
+	if len(response.SeatBid) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid array",
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(response.SeatBid[0].Bid))
+	bidResponse.Currency = response.Cur
+	seatBid := response.SeatBid[0]
+	var errs []error
+	for i, bid := range seatBid.Bid {
+		mediaType, err := getMediaTypeForImp(bid.ImpID, request.Imp)
+		if err != nil {
+			errs = append(errs, err)
+		} else {
+			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+				Bid:     &seatBid.Bid[i],
+				BidType: mediaType,
+			})
+		}
+	}
+
+	return bidResponse, errs
+}
+
+func getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
+	var mediaType openrtb_ext.BidType
+	var typeCnt = 0
+	for _, imp := range imps {
+		if imp.ID == impId {
+			if imp.Banner != nil {
+				typeCnt += 1
+				mediaType = openrtb_ext.BidTypeBanner
+			}
+			if imp.Native != nil {
+				typeCnt += 1
+				mediaType = openrtb_ext.BidTypeNative
+			}
+			if imp.Video != nil {
+				typeCnt += 1
+				mediaType = openrtb_ext.BidTypeVideo
+			}
+		}
+	}
+	if typeCnt == 1 {
+		return mediaType, nil
+	}
+	return mediaType, fmt.Errorf("unable to fetch mediaType in multi-format: %s", impId)
+}
diff --git a/adapters/nextmillennium/nextmillennium.go b/adapters/nextmillennium/nextmillennium.go
index 68ca4dc2..bcb0b287 100644
--- a/adapters/nextmillennium/nextmillennium.go
+++ b/adapters/nextmillennium/nextmillennium.go
@@ -99,12 +99,35 @@ func (adapter *adapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidReques
 }
 
 func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ImpExtNextMillennium) *NextMillenniumBidRequest {
+	placementID := params.PlacementID
 	bidRequest := NextMillenniumBidRequest{
 		ID:   prebidBidRequest.ID,
 		Test: uint8(prebidBidRequest.Test),
 	}
-	bidRequest.Ext.Prebid.StoredRequest.ID = params.PlacementID
 
+	if params.GroupID != "" {
+		domain := ""
+		size := ""
+
+		if prebidBidRequest.Site != nil {
+			domain = prebidBidRequest.Site.Domain
+		}
+		if prebidBidRequest.App != nil {
+			domain = prebidBidRequest.App.Domain
+		}
+
+		if banner := prebidBidRequest.Imp[0].Banner; banner != nil {
+			if len(banner.Format) > 0 {
+				size = fmt.Sprintf("%dx%d", banner.Format[0].W, banner.Format[0].H)
+			} else if banner.W != nil && banner.H != nil {
+				size = fmt.Sprintf("%dx%d", *banner.W, *banner.H)
+			}
+		}
+
+		placementID = fmt.Sprintf("g%s;%s;%s", params.GroupID, size, domain)
+	}
+
+	bidRequest.Ext.Prebid.StoredRequest.ID = placementID
 	return &bidRequest
 }
 
diff --git a/adapters/stroeerCore/stroeercore.go b/adapters/stroeerCore/stroeercore.go
new file mode 100644
index 00000000..2f9f39ec
--- /dev/null
+++ b/adapters/stroeerCore/stroeercore.go
@@ -0,0 +1,114 @@
+package stroeerCore
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"net/http"
+)
+
+type adapter struct {
+	URL string `json:"url"`
+}
+
+type response struct {
+	Bids []bidResponse `json:"bids"`
+}
+
+type bidResponse struct {
+	ID     string  `json:"id"`
+	BidID  string  `json:"bidId"`
+	CPM    float64 `json:"cpm"`
+	Width  int64   `json:"width"`
+	Height int64   `json:"height"`
+	Ad     string  `json:"ad"`
+	CrID   string  `json:"crid"`
+}
+
+func (a *adapter) MakeBids(bidRequest *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if responseData.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected http status code: %d.", responseData.StatusCode),
+		}}
+	}
+
+	var errors []error
+	stroeerResponse := response{}
+
+	if err := json.Unmarshal(responseData.Body, &stroeerResponse); err != nil {
+		errors = append(errors, err)
+		return nil, errors
+	}
+
+	bidderResponse := adapters.NewBidderResponseWithBidsCapacity(len(stroeerResponse.Bids))
+	bidderResponse.Currency = "EUR"
+
+	for _, bid := range stroeerResponse.Bids {
+		openRtbBid := openrtb2.Bid{
+			ID:    bid.ID,
+			ImpID: bid.BidID,
+			W:     bid.Width,
+			H:     bid.Height,
+			Price: bid.CPM,
+			AdM:   bid.Ad,
+			CrID:  bid.CrID,
+		}
+
+		bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
+			Bid:     &openRtbBid,
+			BidType: openrtb_ext.BidTypeBanner,
+		})
+	}
+
+	return bidderResponse, errors
+}
+
+func (a *adapter) MakeRequests(bidRequest *openrtb2.BidRequest, extraRequestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	var errors []error
+
+	for idx := range bidRequest.Imp {
+		imp := &bidRequest.Imp[idx]
+		var bidderExt adapters.ExtImpBidder
+		if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+			errors = append(errors, err)
+			continue
+		}
+
+		var stroeerExt openrtb_ext.ExtImpStroeerCore
+		if err := json.Unmarshal(bidderExt.Bidder, &stroeerExt); err != nil {
+			errors = append(errors, err)
+			continue
+		}
+
+		imp.TagID = stroeerExt.Sid
+	}
+
+	reqJSON, err := json.Marshal(bidRequest)
+	if err != nil {
+		errors = append(errors, err)
+		return nil, errors
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+
+	return []*adapters.RequestData{{
+		Method:  "POST",
+		Uri:     a.URL,
+		Body:    reqJSON,
+		Headers: headers,
+	}}, errors
+}
+
+// Builder builds a new instance of the StroeerCore adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		URL: config.Endpoint,
+	}
+	return bidder, nil
+}
diff --git a/adapters/trafficgate/trafficgate.go b/adapters/trafficgate/trafficgate.go
new file mode 100644
index 00000000..30ec08b0
--- /dev/null
+++ b/adapters/trafficgate/trafficgate.go
@@ -0,0 +1,181 @@
+package trafficgate
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"text/template"
+
+	"github.com/mxmCherry/openrtb/v15/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 {
+	EndpointTemplate *template.Template
+}
+
+type BidResponseExt struct {
+	Prebid struct {
+		Type string
+	}
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+
+	headers := http.Header{
+		"Content-Type": {"application/json"},
+		"Accept":       {"application/json"},
+	}
+
+	// Pull the host and source ID info from the bidder params.
+	reqImps, err := splitImpressions(request.Imp)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	requests := []*adapters.RequestData{}
+
+	var errs []error
+	for reqExt, reqImp := range reqImps {
+		request.Imp = reqImp
+		reqJson, err := json.Marshal(request)
+
+		if err != nil {
+			errs = append(errs, err)
+			continue
+		}
+
+		urlParams := macros.EndpointTemplateParams{Host: reqExt.Host}
+		url, err := macros.ResolveMacros(a.EndpointTemplate, urlParams)
+
+		if err != nil {
+			errs = append(errs, err)
+			continue
+		}
+
+		request := adapters.RequestData{
+			Method:  "POST",
+			Uri:     url,
+			Body:    reqJson,
+			Headers: headers}
+
+		requests = append(requests, &request)
+	}
+
+	return requests, errs
+}
+
+/*
+internal original request in OpenRTB, external = result of us having converted it (what comes out of MakeRequests)
+*/
+func (a *adapter) MakeBids(
+	internalRequest *openrtb2.BidRequest,
+	externalRequest *adapters.RequestData,
+	response *adapters.ResponseData,
+) (*adapters.BidderResponse, []error) {
+
+	if response.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Error response with status %d", response.StatusCode),
+		}}
+	}
+
+	var bidResp openrtb2.BidResponse
+
+	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: err.Error(),
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp))
+	bidResponse.Currency = bidResp.Cur
+
+	for _, seatBid := range bidResp.SeatBid {
+		for i := range seatBid.Bid {
+			var bidExt BidResponseExt
+			if err := json.Unmarshal(seatBid.Bid[i].Ext, &bidExt); err != nil {
+				return nil, []error{&errortypes.BadServerResponse{
+					Message: fmt.Sprintf("Missing response ext"),
+				}}
+			}
+			if len(bidExt.Prebid.Type) < 1 {
+				return nil, []error{&errortypes.BadServerResponse{
+					Message: fmt.Sprintf("Unable to read bid.ext.prebid.type"),
+				}}
+			}
+			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+				Bid:     &seatBid.Bid[i],
+				BidType: getMediaTypeForImp(bidExt.Prebid.Type),
+			})
+		}
+	}
+
+	return bidResponse, nil
+}
+
+func splitImpressions(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpTrafficGate][]openrtb2.Imp, error) {
+
+	var multipleImps = make(map[openrtb_ext.ExtImpTrafficGate][]openrtb2.Imp)
+
+	for _, imp := range imps {
+		bidderParams, err := getBidderParams(&imp)
+		if err != nil {
+			return nil, err
+		}
+
+		multipleImps[*bidderParams] = append(multipleImps[*bidderParams], imp)
+	}
+
+	return multipleImps, nil
+}
+
+func getBidderParams(imp *openrtb2.Imp) (*openrtb_ext.ExtImpTrafficGate, error) {
+	var bidderExt adapters.ExtImpBidder
+	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: fmt.Sprintf("Missing bidder ext"),
+		}
+	}
+	var TrafficGateExt openrtb_ext.ExtImpTrafficGate
+	if err := json.Unmarshal(bidderExt.Bidder, &TrafficGateExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: fmt.Sprintf("Bidder parameters required"),
+		}
+	}
+
+	return &TrafficGateExt, nil
+}
+
+func getMediaTypeForImp(bidType string) openrtb_ext.BidType {
+	switch bidType {
+	case "video":
+		return openrtb_ext.BidTypeVideo
+	case "native":
+		return openrtb_ext.BidTypeNative
+	case "audio":
+		return openrtb_ext.BidTypeAudio
+	}
+	return openrtb_ext.BidTypeBanner
+}
+
+// Builder builds a new instance of the TrafficGate adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (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{
+		EndpointTemplate: template,
+	}
+	return bidder, nil
+}
diff --git a/config/accounts.go b/config/accounts.go
index e475da8a..14e52180 100644
--- a/config/accounts.go
+++ b/config/accounts.go
@@ -33,9 +33,9 @@ type Account struct {
 
 // CookieSync represents the account-level defaults for the cookie sync endpoint.
 type CookieSync struct {
-	DefaultLimit    int  `mapstructure:"default_limit" json:"default_limit"`
-	MaxLimit        int  `mapstructure:"max_limit" json:"max_limit"`
-	DefaultCoopSync bool `mapstructure:"default_coop_sync" json:"default_coop_sync"`
+	DefaultLimit    *int  `mapstructure:"default_limit" json:"default_limit"`
+	MaxLimit        *int  `mapstructure:"max_limit" json:"max_limit"`
+	DefaultCoopSync *bool `mapstructure:"default_coop_sync" json:"default_coop_sync"`
 }
 
 // AccountCCPA represents account-specific CCPA configuration
diff --git a/config/config.go b/config/config.go
index a8bf31c0..76948b25 100644
--- a/config/config.go
+++ b/config/config.go
@@ -487,6 +487,9 @@ type DisabledMetrics struct {
 	// True if we want to stop collecting account-to-adapter metrics
 	AccountAdapterDetails bool `mapstructure:"account_adapter_details"`
 
+	// True if we want to stop collecting account debug request metrics
+	AccountDebug bool `mapstructure:"account_debug"`
+
 	// True if we don't want to collect metrics about the connections prebid
 	// server establishes with bidder servers such as the number of connections
 	// that were created or reused.
@@ -780,6 +783,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("http_client_cache.idle_connection_timeout_seconds", 60)
 	// no metrics configured by default (metrics{host|database|username|password})
 	v.SetDefault("metrics.disabled_metrics.account_adapter_details", false)
+	v.SetDefault("metrics.disabled_metrics.account_debug", true)
 	v.SetDefault("metrics.disabled_metrics.adapter_connections_metrics", true)
 	v.SetDefault("metrics.disabled_metrics.adapter_gdpr_request_blocked", false)
 	v.SetDefault("metrics.influxdb.host", "")
@@ -942,6 +946,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.bidmyadz.endpoint", "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc")
 	v.SetDefault("adapters.bidscube.endpoint", "http://supply.bidscube.com/?c=o&m=rtb")
 	v.SetDefault("adapters.bizzclick.endpoint", "http://us-e-node1.bizzclick.com/bid?rtb_seat_id={{.SourceId}}&secret_key={{.AccountID}}")
+	v.SetDefault("adapters.bliink.endpoint", "http://engine.bliink.io/bid")
 	v.SetDefault("adapters.bmtm.endpoint", "https://one.elitebidder.com/api/pbs")
 	v.SetDefault("adapters.brightroll.endpoint", "http://east-bid.ybp.yahoo.com/bid/appnexuspbs")
 	v.SetDefault("adapters.coinzilla.endpoint", "http://request-global.czilladx.com/serve/prebid-server.php")
@@ -1028,9 +1033,12 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.sonobi.endpoint", "https://apex.go.sonobi.com/prebid?partnerid=71d9d3d8af")
 	v.SetDefault("adapters.sovrn.endpoint", "http://ap.lijit.com/rtb/bid?src=prebid_server")
 	v.SetDefault("adapters.streamkey.endpoint", "http://ghb.hb.streamkey.net/pbs/ortb")
+	v.SetDefault("adapters.stroeercore.disabled", true)
+	v.SetDefault("adapters.stroeercore.endpoint", "http://mhb.adscale.de/s2sdsh")
 	v.SetDefault("adapters.synacormedia.endpoint", "http://{{.Host}}.technoratimedia.com/openrtb/bids/{{.Host}}")
 	v.SetDefault("adapters.tappx.endpoint", "http://{{.Host}}")
 	v.SetDefault("adapters.telaria.endpoint", "https://ads.tremorhub.com/ad/rtb/prebid")
+	v.SetDefault("adapters.trafficgate.endpoint", "http://{{.Host}}.bc-plugin.com/?c=o&m=rtb")
 	v.SetDefault("adapters.triplelift_native.disabled", true)
 	v.SetDefault("adapters.triplelift_native.extra_info", "{\"publisher_whitelist\":[]}")
 	v.SetDefault("adapters.triplelift.endpoint", "https://tlx.3lift.com/s2s/auction?sra=1&supplier_id=20")
diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go
index 7cb1d2d7..a3d9772e 100644
--- a/endpoints/cookie_sync.go
+++ b/endpoints/cookie_sync.go
@@ -113,6 +113,11 @@ func (c *cookieSyncEndpoint) parseRequest(r *http.Request) (usersync.Request, pr
 		return usersync.Request{}, privacy.Policies{}, fmt.Errorf("JSON parsing failed: %s", err.Error())
 	}
 
+	account, fetchErrs := accountService.GetAccount(context.Background(), c.config, c.accountsFetcher, request.Account)
+	if len(fetchErrs) > 0 {
+		return usersync.Request{}, privacy.Policies{}, combineErrors(fetchErrs)
+	}
+
 	var gdprString string
 	if request.GDPR != nil {
 		gdprString = strconv.Itoa(*request.GDPR)
@@ -132,10 +137,8 @@ func (c *cookieSyncEndpoint) parseRequest(r *http.Request) (usersync.Request, pr
 		}
 	}
 
-	request, err = c.setLimit(request)
-	if err != nil {
-		return usersync.Request{}, privacy.Policies{}, err
-	}
+	request = c.setLimit(request, account.CookieSync)
+	request = c.setCooperativeSync(request, account.CookieSync)
 
 	privacyPolicies := privacy.Policies{
 		GDPR: gdprPrivacy.Policy{
@@ -192,26 +195,26 @@ func (c *cookieSyncEndpoint) writeParseRequestErrorMetrics(err error) {
 	}
 }
 
-func (c *cookieSyncEndpoint) setLimit(request cookieSyncRequest) (cookieSyncRequest, error) {
-	if request.Account != "" {
-		accountInfo, errs := accountService.GetAccount(context.Background(), c.config, c.accountsFetcher, request.Account)
-		if len(errs) > 0 {
-			return request, combineErrors(errs)
-		}
-		if request.Limit <= 0 {
-			request.Limit = accountInfo.CookieSync.DefaultLimit
-		}
-		if request.Limit <= 0 || request.Limit > accountInfo.CookieSync.MaxLimit {
-			request.Limit = accountInfo.CookieSync.MaxLimit
-		}
-		if request.Limit < 0 {
-			request.Limit = 0
-		}
-		if request.CooperativeSync == nil {
-			request.CooperativeSync = &accountInfo.CookieSync.DefaultCoopSync
-		}
+func (c *cookieSyncEndpoint) setLimit(request cookieSyncRequest, cookieSyncConfig config.CookieSync) cookieSyncRequest {
+	if request.Limit <= 0 && cookieSyncConfig.DefaultLimit != nil {
+		request.Limit = *cookieSyncConfig.DefaultLimit
+	}
+	if cookieSyncConfig.MaxLimit != nil && (request.Limit <= 0 || request.Limit > *cookieSyncConfig.MaxLimit) {
+		request.Limit = *cookieSyncConfig.MaxLimit
+	}
+	if request.Limit < 0 {
+		request.Limit = 0
+	}
+
+	return request
+}
+
+func (c *cookieSyncEndpoint) setCooperativeSync(request cookieSyncRequest, cookieSyncConfig config.CookieSync) cookieSyncRequest {
+	if request.CooperativeSync == nil && cookieSyncConfig.DefaultCoopSync != nil {
+		request.CooperativeSync = cookieSyncConfig.DefaultCoopSync
 	}
-	return request, nil
+
+	return request
 }
 
 func parseTypeFilter(request *cookieSyncRequestFilterSettings) (usersync.SyncTypeFilter, error) {
diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go
index 1d5f8a5e..1303d398 100644
--- a/endpoints/openrtb2/amp_auction.go
+++ b/endpoints/openrtb2/amp_auction.go
@@ -206,6 +206,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
 		GDPRPermissionsBuilder:     aggregatedGDPR.NewPermissions,
 		StoredAuctionResponses:     storedAuctionResponses,
 		StoredBidResponses:         storedBidResponses,
+		PubID:                      labels.PubID,
 	}
 
 	response, err := deps.ex.HoldAuction(ctx, auctionRequest, nil)
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 05a020a8..64858530 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -5,7 +5,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"github.com/prebid/prebid-server/gdpr"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -14,6 +13,8 @@ import (
 	"strconv"
 	"time"
 
+	"github.com/prebid/prebid-server/gdpr"
+
 	"github.com/buger/jsonparser"
 	"github.com/gofrs/uuid"
 	"github.com/golang/glog"
@@ -214,8 +215,8 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http
 		StoredBidResponses:         storedBidResponses,
 		TCF2ConfigBuilder:          gdpr.NewTCF2Config,
 		GDPRPermissionsBuilder:     gdpr.NewPermissions,
+		PubID:                      labels.PubID,
 	}
-
 	response, err := deps.ex.HoldAuction(ctx, auctionRequest, nil)
 	ao.Request = req.BidRequest
 	ao.Response = response
diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go
index ec5b1c57..80585e3b 100644
--- a/endpoints/openrtb2/video_auction.go
+++ b/endpoints/openrtb2/video_auction.go
@@ -297,6 +297,7 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
 		TCF2ConfigBuilder:          gdpr.NewTCF2Config,
 		GDPRPermissionsBuilder:     gdpr.NewPermissions,
 		GlobalPrivacyControlHeader: secGPC,
+		PubID:                      labels.PubID,
 	}
 
 	response, err := deps.ex.HoldAuction(ctx, auctionRequest, &debugLog)
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 24a2f0b8..f095553d 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -41,6 +41,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/bidmyadz"
 	"github.com/prebid/prebid-server/adapters/bidscube"
 	"github.com/prebid/prebid-server/adapters/bizzclick"
+	"github.com/prebid/prebid-server/adapters/bliink"
 	"github.com/prebid/prebid-server/adapters/bmtm"
 	"github.com/prebid/prebid-server/adapters/brightroll"
 	"github.com/prebid/prebid-server/adapters/coinzilla"
@@ -116,9 +117,11 @@ import (
 	"github.com/prebid/prebid-server/adapters/smilewanted"
 	"github.com/prebid/prebid-server/adapters/sonobi"
 	"github.com/prebid/prebid-server/adapters/sovrn"
+	"github.com/prebid/prebid-server/adapters/stroeerCore"
 	"github.com/prebid/prebid-server/adapters/synacormedia"
 	"github.com/prebid/prebid-server/adapters/tappx"
 	"github.com/prebid/prebid-server/adapters/telaria"
+	"github.com/prebid/prebid-server/adapters/trafficgate"
 	"github.com/prebid/prebid-server/adapters/triplelift"
 	"github.com/prebid/prebid-server/adapters/triplelift_native"
 	"github.com/prebid/prebid-server/adapters/ucfunnel"
@@ -182,6 +185,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderBidmyadz:          bidmyadz.Builder,
 		openrtb_ext.BidderBidsCube:          bidscube.Builder,
 		openrtb_ext.BidderBizzclick:         bizzclick.Builder,
+		openrtb_ext.BidderBliink:            bliink.Builder,
 		openrtb_ext.BidderBmtm:              bmtm.Builder,
 		openrtb_ext.BidderBrightroll:        brightroll.Builder,
 		openrtb_ext.BidderCoinzilla:         coinzilla.Builder,
@@ -262,10 +266,12 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderSmileWanted:       smilewanted.Builder,
 		openrtb_ext.BidderSonobi:            sonobi.Builder,
 		openrtb_ext.BidderSovrn:             sovrn.Builder,
+		openrtb_ext.BidderStroeerCore:       stroeerCore.Builder,
 		openrtb_ext.BidderStreamkey:         adtelligent.Builder,
 		openrtb_ext.BidderSynacormedia:      synacormedia.Builder,
 		openrtb_ext.BidderTappx:             tappx.Builder,
 		openrtb_ext.BidderTelaria:           telaria.Builder,
+		openrtb_ext.BidderTrafficGate:       trafficgate.Builder,
 		openrtb_ext.BidderTriplelift:        triplelift.Builder,
 		openrtb_ext.BidderTripleliftNative:  triplelift_native.Builder,
 		openrtb_ext.BidderTrustX:            grid.Builder,
diff --git a/exchange/exchange.go b/exchange/exchange.go
index d2362107..37527389 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -172,6 +172,7 @@ type AuctionRequest struct {
 	GDPRPermissionsBuilder gdpr.PermissionsBuilder
 	// map of imp id to bidder to stored response
 	StoredBidResponses stored_responses.ImpBidderStoredResp
+	PubID              string
 }
 
 // BidderRequest holds the bidder specific request and all other
@@ -209,6 +210,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
 		}
 		r.ResolvedBidRequest = resolvedBidReq
 	}
+	e.me.RecordDebugRequest(responseDebugAllow || accountDebugAllow, r.PubID)
 
 	if r.RequestType == metrics.ReqTypeORTB2Web || r.RequestType == metrics.ReqTypeORTB2App {
 		//Extract First party data for auction endpoint only
diff --git a/exchange/utils.go b/exchange/utils.go
index a3f3f4c4..611b62a7 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -4,9 +4,10 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"github.com/prebid/prebid-server/stored_responses"
 	"math/rand"
 
+	"github.com/prebid/prebid-server/stored_responses"
+
 	"github.com/buger/jsonparser"
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/prebid/go-gdpr/vendorconsent"
@@ -127,12 +128,12 @@ func cleanOpenRTBRequests(ctx context.Context,
 		// GDPR
 		if gdprEnforced {
 			var publisherID = auctionReq.LegacyLabels.PubID
-			bidReq, geo, id, err := gdprPerms.AuctionActivitiesAllowed(ctx, bidderRequest.BidderCoreName, bidderRequest.BidderName, publisherID, gdprSignal, consent, aliasesGVLIDs)
-			bidRequestAllowed = bidReq
+			auctionPermissions, err := gdprPerms.AuctionActivitiesAllowed(ctx, bidderRequest.BidderCoreName, bidderRequest.BidderName, publisherID, gdprSignal, consent, aliasesGVLIDs)
+			bidRequestAllowed = auctionPermissions.AllowBidRequest
 
 			if err == nil {
-				privacyEnforcement.GDPRGeo = !geo
-				privacyEnforcement.GDPRID = !id
+				privacyEnforcement.GDPRGeo = !auctionPermissions.PassGeo
+				privacyEnforcement.GDPRID = !auctionPermissions.PassID
 			} else {
 				privacyEnforcement.GDPRGeo = true
 				privacyEnforcement.GDPRID = true
diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go
index ecbbd9f4..94ef864f 100644
--- a/gdpr/gdpr.go
+++ b/gdpr/gdpr.go
@@ -21,7 +21,7 @@ type Permissions interface {
 	// Determines whether or not to send PI information to a bidder, or mask it out.
 	//
 	// If the consent string was nonsensical, the returned error will be an ErrorMalformedConsent.
-	AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string, aliasGVLIDs map[string]uint16) (allowBidReq bool, passGeo bool, passID bool, err error)
+	AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string, aliasGVLIDs map[string]uint16) (permissions AuctionPermissions, err error)
 }
 
 type PermissionsBuilder func(config.GDPR, TCF2ConfigReader, map[openrtb_ext.BidderName]uint16, VendorListFetcher) Permissions
diff --git a/gdpr/impl.go b/gdpr/impl.go
index 06f9dc11..fd08d839 100644
--- a/gdpr/impl.go
+++ b/gdpr/impl.go
@@ -48,19 +48,19 @@ func (p *permissionsImpl) BidderSyncAllowed(ctx context.Context, bidder openrtb_
 	return false, nil
 }
 
-func (p *permissionsImpl) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string, aliasGVLIDs map[string]uint16) (allowBidReq bool, passGeo bool, passID bool, err error) {
+func (p *permissionsImpl) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string, aliasGVLIDs map[string]uint16) (permissions AuctionPermissions, err error) {
 	if _, ok := p.nonStandardPublishers[PublisherID]; ok {
-		return true, true, true, nil
+		return AllowAll, nil
 	}
 
 	gdprSignal = SignalNormalize(gdprSignal, p.gdprDefaultValue)
 
 	if gdprSignal == SignalNo {
-		return true, true, true, nil
+		return AllowAll, nil
 	}
 
 	if consent == "" && gdprSignal == SignalYes {
-		return false, false, false, nil
+		return DenyAll, nil
 	}
 
 	weakVendorEnforcement := p.cfg.BasicEnforcementVendor(bidder)
@@ -74,8 +74,8 @@ func (p *permissionsImpl) AuctionActivitiesAllowed(ctx context.Context, bidderCo
 	return p.defaultVendorPermissions()
 }
 
-func (p *permissionsImpl) defaultVendorPermissions() (allowBidRequest bool, passGeo bool, passID bool, err error) {
-	return false, false, false, nil
+func (p *permissionsImpl) defaultVendorPermissions() (permissions AuctionPermissions, err error) {
+	return DenyAll, nil
 }
 
 func (p *permissionsImpl) resolveVendorId(bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, aliasGVLIDs map[string]uint16) (id uint16, ok bool) {
@@ -119,10 +119,10 @@ func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, consen
 	return p.checkPurpose(consentMeta, vendor, vendorID, tcf2ConsentConstants.InfoStorageAccess, enforceVendors, vendorException, false), nil
 }
 
-func (p *permissionsImpl) allowActivities(ctx context.Context, vendorID uint16, bidder openrtb_ext.BidderName, consent string, weakVendorEnforcement bool) (allowBidRequest bool, passGeo bool, passID bool, err error) {
+func (p *permissionsImpl) allowActivities(ctx context.Context, vendorID uint16, bidder openrtb_ext.BidderName, consent string, weakVendorEnforcement bool) (AuctionPermissions, error) {
 	parsedConsent, vendor, err := p.parseVendor(ctx, vendorID, consent)
 	if err != nil {
-		return false, false, false, err
+		return DenyAll, err
 	}
 
 	// vendor will be nil if not a valid TCF2 consent string
@@ -130,43 +130,44 @@ func (p *permissionsImpl) allowActivities(ctx context.Context, vendorID uint16,
 		if weakVendorEnforcement && parsedConsent.Version() == 2 {
 			vendor = vendorTrue{}
 		} else {
-			return false, false, false, nil
+			return DenyAll, nil
 		}
 	}
 
 	if !p.cfg.IsEnabled() {
-		return true, false, false, nil
+		return AllowBidRequestOnly, nil
 	}
 
 	consentMeta, ok := parsedConsent.(tcf2.ConsentMetadata)
 	if !ok {
 		err = fmt.Errorf("Unable to access TCF2 parsed consent")
-		return
+		return DenyAll, err
 	}
 
+	permissions := AuctionPermissions{}
 	if p.cfg.FeatureOneEnforced() {
 		vendorException := p.cfg.FeatureOneVendorException(bidder)
-		passGeo = vendorException || (consentMeta.SpecialFeatureOptIn(1) && (vendor.SpecialFeature(1) || weakVendorEnforcement))
+		permissions.PassGeo = vendorException || (consentMeta.SpecialFeatureOptIn(1) && (vendor.SpecialFeature(1) || weakVendorEnforcement))
 	} else {
-		passGeo = true
+		permissions.PassGeo = true
 	}
 	if p.cfg.PurposeEnforced(consentconstants.Purpose(2)) {
 		enforceVendors := p.cfg.PurposeEnforcingVendors(consentconstants.Purpose(2))
 		vendorException := p.cfg.PurposeVendorException(consentconstants.Purpose(2), bidder)
-		allowBidRequest = p.checkPurpose(consentMeta, vendor, vendorID, consentconstants.Purpose(2), enforceVendors, vendorException, weakVendorEnforcement)
+		permissions.AllowBidRequest = p.checkPurpose(consentMeta, vendor, vendorID, consentconstants.Purpose(2), enforceVendors, vendorException, weakVendorEnforcement)
 	} else {
-		allowBidRequest = true
+		permissions.AllowBidRequest = true
 	}
 	for i := 2; i <= 10; i++ {
 		enforceVendors := p.cfg.PurposeEnforcingVendors(consentconstants.Purpose(i))
 		vendorException := p.cfg.PurposeVendorException(consentconstants.Purpose(i), bidder)
 		if p.checkPurpose(consentMeta, vendor, vendorID, consentconstants.Purpose(i), enforceVendors, vendorException, weakVendorEnforcement) {
-			passID = true
+			permissions.PassID = true
 			break
 		}
 	}
 
-	return
+	return permissions, nil
 }
 
 const pubRestrictNotAllowed = 0
@@ -273,8 +274,8 @@ func (a AlwaysAllow) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.B
 	return true, nil
 }
 
-func (a AlwaysAllow) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string, aliasGVLIDs map[string]uint16) (allowBidReq bool, passGeo bool, passID bool, err error) {
-	return true, true, true, nil
+func (a AlwaysAllow) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string, aliasGVLIDs map[string]uint16) (permissions AuctionPermissions, err error) {
+	return AllowAll, nil
 }
 
 // vendorTrue claims everything.
diff --git a/gdpr/permissions.go b/gdpr/permissions.go
new file mode 100644
index 00000000..2d4b5c9e
--- /dev/null
+++ b/gdpr/permissions.go
@@ -0,0 +1,25 @@
+package gdpr
+
+type AuctionPermissions struct {
+	AllowBidRequest bool
+	PassGeo         bool
+	PassID          bool
+}
+
+var AllowAll = AuctionPermissions{
+	AllowBidRequest: true,
+	PassGeo:         true,
+	PassID:          true,
+}
+
+var DenyAll = AuctionPermissions{
+	AllowBidRequest: false,
+	PassGeo:         false,
+	PassID:          false,
+}
+
+var AllowBidRequestOnly = AuctionPermissions{
+	AllowBidRequest: true,
+	PassGeo:         false,
+	PassID:          false,
+}
diff --git a/metrics/config/metrics.go b/metrics/config/metrics.go
index d8df48fa..c94557a1 100644
--- a/metrics/config/metrics.go
+++ b/metrics/config/metrics.go
@@ -254,6 +254,13 @@ func (me *MultiMetricsEngine) RecordAdapterGDPRRequestBlocked(adapter openrtb_ex
 	}
 }
 
+// RecordDebugRequest across all engines
+func (me *MultiMetricsEngine) RecordDebugRequest(debugEnabled bool, pubId string) {
+	for _, thisME := range *me {
+		thisME.RecordDebugRequest(debugEnabled, pubId)
+	}
+}
+
 // NilMetricsEngine implements the MetricsEngine interface where no metrics are actually captured. This is
 // used if no metric backend is configured and also for tests.
 type NilMetricsEngine struct{}
@@ -365,3 +372,7 @@ func (me *NilMetricsEngine) RecordRequestPrivacy(privacy metrics.PrivacyLabels)
 // RecordAdapterGDPRRequestBlocked as a noop
 func (me *NilMetricsEngine) RecordAdapterGDPRRequestBlocked(adapter openrtb_ext.BidderName) {
 }
+
+// RecordDebugRequest as a noop
+func (me *NilMetricsEngine) RecordDebugRequest(debugEnabled bool, pubId string) {
+}
diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go
index c93f1060..30752321 100644
--- a/metrics/go_metrics.go
+++ b/metrics/go_metrics.go
@@ -20,6 +20,7 @@ type Metrics struct {
 	ImpMeter                       metrics.Meter
 	AppRequestMeter                metrics.Meter
 	NoCookieMeter                  metrics.Meter
+	DebugRequestMeter              metrics.Meter
 	RequestTimer                   metrics.Timer
 	RequestsQueueTimer             map[RequestType]map[bool]metrics.Timer
 	PrebidCacheRequestTimerSuccess metrics.Timer
@@ -94,6 +95,7 @@ type MarkupDeliveryMetrics struct {
 
 type accountMetrics struct {
 	requestMeter      metrics.Meter
+	debugRequestMeter metrics.Meter
 	bidsReceivedMeter metrics.Meter
 	priceHistogram    metrics.Histogram
 	// store account by adapter metrics. Type is map[PBSBidder.BidderCode]
@@ -119,6 +121,7 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderNa
 		ConnectionCloseErrorMeter:      blankMeter,
 		ImpMeter:                       blankMeter,
 		AppRequestMeter:                blankMeter,
+		DebugRequestMeter:              blankMeter,
 		NoCookieMeter:                  blankMeter,
 		RequestTimer:                   blankTimer,
 		DNSLookupTimer:                 blankTimer,
@@ -219,6 +222,7 @@ func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, d
 
 	newMetrics.NoCookieMeter = metrics.GetOrRegisterMeter("no_cookie_requests", registry)
 	newMetrics.AppRequestMeter = metrics.GetOrRegisterMeter("app_requests", registry)
+	newMetrics.DebugRequestMeter = metrics.GetOrRegisterMeter("debug_requests", registry)
 	newMetrics.RequestTimer = metrics.GetOrRegisterTimer("request_time", registry)
 	newMetrics.DNSLookupTimer = metrics.GetOrRegisterTimer("dns_lookup_time", registry)
 	newMetrics.TLSHandshakeTimer = metrics.GetOrRegisterTimer("tls_handshake_time", registry)
@@ -394,6 +398,7 @@ func (me *Metrics) getAccountMetrics(id string) *accountMetrics {
 	}
 	am = &accountMetrics{}
 	am.requestMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.requests", id), me.MetricsRegistry)
+	am.debugRequestMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.debug_requests", id), me.MetricsRegistry)
 	am.bidsReceivedMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.bids_received", id), me.MetricsRegistry)
 	am.priceHistogram = metrics.GetOrRegisterHistogram(fmt.Sprintf("account.%s.prices", id), me.MetricsRegistry, metrics.NewExpDecaySample(1028, 0.015))
 	am.adapterMetrics = make(map[openrtb_ext.BidderName]*AdapterMetrics, len(me.exchanges))
@@ -430,6 +435,18 @@ func (me *Metrics) RecordRequest(labels Labels) {
 	am.requestMeter.Mark(1)
 }
 
+func (me *Metrics) RecordDebugRequest(debugEnabled bool, pubID string) {
+	if debugEnabled {
+		me.DebugRequestMeter.Mark(1)
+		if pubID != PublisherUnknown {
+			am := me.getAccountMetrics(pubID)
+			if !me.MetricsDisabled.AccountDebug {
+				am.debugRequestMeter.Mark(1)
+			}
+		}
+	}
+}
+
 func (me *Metrics) RecordImps(labels ImpLabels) {
 	me.ImpMeter.Mark(int64(1))
 	if labels.BannerImps {
diff --git a/metrics/metrics.go b/metrics/metrics.go
index b70907ea..8394f419 100644
--- a/metrics/metrics.go
+++ b/metrics/metrics.go
@@ -409,4 +409,5 @@ type MetricsEngine interface {
 	RecordTimeoutNotice(success bool)
 	RecordRequestPrivacy(privacy PrivacyLabels)
 	RecordAdapterGDPRRequestBlocked(adapterName openrtb_ext.BidderName)
+	RecordDebugRequest(debugEnabled bool, pubId string)
 }
diff --git a/metrics/metrics_mock.go b/metrics/metrics_mock.go
index c8d5311c..84f75491 100644
--- a/metrics/metrics_mock.go
+++ b/metrics/metrics_mock.go
@@ -145,3 +145,8 @@ func (me *MetricsEngineMock) RecordRequestPrivacy(privacy PrivacyLabels) {
 func (me *MetricsEngineMock) RecordAdapterGDPRRequestBlocked(adapterName openrtb_ext.BidderName) {
 	me.Called(adapterName)
 }
+
+// RecordDebugRequest mock
+func (me *MetricsEngineMock) RecordDebugRequest(debugEnabled bool, pubId string) {
+	me.Called(debugEnabled, pubId)
+}
diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go
index 368424c5..87c4d1c2 100644
--- a/metrics/prometheus/prometheus.go
+++ b/metrics/prometheus/prometheus.go
@@ -27,6 +27,7 @@ type Metrics struct {
 	impressionsLegacy            prometheus.Counter
 	prebidCacheWriteTimer        *prometheus.HistogramVec
 	requests                     *prometheus.CounterVec
+	debugRequests                prometheus.Counter
 	requestsTimer                *prometheus.HistogramVec
 	requestsQueueTimer           *prometheus.HistogramVec
 	requestsWithoutCookie        *prometheus.CounterVec
@@ -68,7 +69,8 @@ type Metrics struct {
 	syncerSets     *prometheus.CounterVec
 
 	// Account Metrics
-	accountRequests *prometheus.CounterVec
+	accountRequests      *prometheus.CounterVec
+	accountDebugRequests *prometheus.CounterVec
 
 	metricsDisabled config.DisabledMetrics
 }
@@ -182,6 +184,10 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet
 		"Count of total requests to Prebid Server labeled by type and status.",
 		[]string{requestTypeLabel, requestStatusLabel})
 
+	metrics.debugRequests = newCounterWithoutLabels(cfg, reg,
+		"debug_requests",
+		"Count of total requests to Prebid Server that have debug enabled")
+
 	metrics.requestsTimer = newHistogramVec(cfg, reg,
 		"request_time_seconds",
 		"Seconds to resolve successful Prebid Server requests labeled by type.",
@@ -370,6 +376,11 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet
 		"Count of total requests to Prebid Server labeled by account.",
 		[]string{accountLabel})
 
+	metrics.accountDebugRequests = newCounter(cfg, reg,
+		"account_debug_requests",
+		"Count of total requests to Prebid Server that have debug enabled labled by account",
+		[]string{accountLabel})
+
 	metrics.requestsQueueTimer = newHistogramVec(cfg, reg,
 		"request_queue_time",
 		"Seconds request was waiting in queue",
@@ -477,6 +488,17 @@ func (m *Metrics) RecordRequest(labels metrics.Labels) {
 	}
 }
 
+func (m *Metrics) RecordDebugRequest(debugEnabled bool, pubID string) {
+	if debugEnabled {
+		m.debugRequests.Inc()
+		if !m.metricsDisabled.AccountDebug && pubID != metrics.PublisherUnknown {
+			m.accountDebugRequests.With(prometheus.Labels{
+				accountLabel: pubID,
+			}).Inc()
+		}
+	}
+}
+
 func (m *Metrics) RecordImps(labels metrics.ImpLabels) {
 	m.impressions.With(prometheus.Labels{
 		isBannerLabel: strconv.FormatBool(labels.BannerImps),
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index de33aa57..f04f5432 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -116,6 +116,7 @@ const (
 	BidderBidmyadz          BidderName = "bidmyadz"
 	BidderBidsCube          BidderName = "bidscube"
 	BidderBizzclick         BidderName = "bizzclick"
+	BidderBliink            BidderName = "bliink"
 	BidderBmtm              BidderName = "bmtm"
 	BidderBrightroll        BidderName = "brightroll"
 	BidderCoinzilla         BidderName = "coinzilla"
@@ -197,9 +198,11 @@ const (
 	BidderSonobi            BidderName = "sonobi"
 	BidderSovrn             BidderName = "sovrn"
 	BidderStreamkey         BidderName = "streamkey"
+	BidderStroeerCore       BidderName = "stroeerCore"
 	BidderSynacormedia      BidderName = "synacormedia"
 	BidderTappx             BidderName = "tappx"
 	BidderTelaria           BidderName = "telaria"
+	BidderTrafficGate       BidderName = "trafficgate"
 	BidderTriplelift        BidderName = "triplelift"
 	BidderTripleliftNative  BidderName = "triplelift_native"
 	BidderTrustX            BidderName = "trustx"
@@ -265,6 +268,7 @@ func CoreBidderNames() []BidderName {
 		BidderBidmyadz,
 		BidderBidsCube,
 		BidderBizzclick,
+		BidderBliink,
 		BidderBmtm,
 		BidderBrightroll,
 		BidderCoinzilla,
@@ -346,9 +350,11 @@ func CoreBidderNames() []BidderName {
 		BidderSonobi,
 		BidderSovrn,
 		BidderStreamkey,
+		BidderStroeerCore,
 		BidderSynacormedia,
 		BidderTappx,
 		BidderTelaria,
+		BidderTrafficGate,
 		BidderTriplelift,
 		BidderTripleliftNative,
 		BidderTrustX,
diff --git a/openrtb_ext/imp_nextmillennium.go b/openrtb_ext/imp_nextmillennium.go
index dbc970d0..32b9579c 100644
--- a/openrtb_ext/imp_nextmillennium.go
+++ b/openrtb_ext/imp_nextmillennium.go
@@ -1,5 +1,6 @@
 package openrtb_ext
 
 type ImpExtNextMillennium struct {
+	GroupID     string `json:"group_id,omitempty"`
 	PlacementID string `json:"placement_id"`
 }
diff --git a/openrtb_ext/imp_stroeercore.go b/openrtb_ext/imp_stroeercore.go
new file mode 100644
index 00000000..a4a232dd
--- /dev/null
+++ b/openrtb_ext/imp_stroeercore.go
@@ -0,0 +1,5 @@
+package openrtb_ext
+
+type ExtImpStroeerCore struct {
+	Sid string `json:"sid,omitempty"`
+}
diff --git a/openrtb_ext/imp_trafficgate.go b/openrtb_ext/imp_trafficgate.go
new file mode 100644
index 00000000..3ec0f290
--- /dev/null
+++ b/openrtb_ext/imp_trafficgate.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ExtImpTrafficGate struct {
+	PlacementID string `json:"placementId"`
+	Host        string `json:"host"`
+}
diff --git a/static/bidder-info/bliink.yaml b/static/bidder-info/bliink.yaml
new file mode 100644
index 00000000..648f14db
--- /dev/null
+++ b/static/bidder-info/bliink.yaml
@@ -0,0 +1,19 @@
+maintainer:
+  email: "support@bliink.io"
+gvlVendorID: 658
+modifyingVastXmlAllowed: true
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
+userSync:
+  redirect:
+    url: "https://cookiesync.api.bliink.io/getuid?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url={{.RedirectURL}}"
+    userMacro: "$UID"
\ No newline at end of file
diff --git a/static/bidder-info/nextmillennium.yaml b/static/bidder-info/nextmillennium.yaml
index 8caf4ac3..2bb723bf 100644
--- a/static/bidder-info/nextmillennium.yaml
+++ b/static/bidder-info/nextmillennium.yaml
@@ -7,3 +7,7 @@ capabilities:
   site:
     mediaTypes:
       - banner
+userSync:
+  iframe:
+    url: "https://cookies.nextmillmedia.com/sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}"
+    userMacro: "[NMUID]"
diff --git a/static/bidder-info/stroeerCore.yaml b/static/bidder-info/stroeerCore.yaml
new file mode 100644
index 00000000..4db50fac
--- /dev/null
+++ b/static/bidder-info/stroeerCore.yaml
@@ -0,0 +1,18 @@
+maintainer:
+  email: "help@cz.stroeer-labs.com"
+gvlVendorID: 136
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+  site:
+    mediaTypes:
+      - banner
+userSync:
+  # for both user syncs, stroeerCore appends the user id to end of the redirect url and does not utilize a macro
+  iframe:
+    url: "https://js.adscale.de/pbsync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redirect={{.RedirectURL}}"
+    userMacro: ""
+  redirect:
+    url: "https://ih.adscale.de/uu?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&cburl={{.RedirectURL}}"
+    userMacro: ""
diff --git a/static/bidder-info/trafficgate.yaml b/static/bidder-info/trafficgate.yaml
new file mode 100644
index 00000000..1d9ff63c
--- /dev/null
+++ b/static/bidder-info/trafficgate.yaml
@@ -0,0 +1,16 @@
+maintainer:
+  email: "support@bidscube.com"
+modifyingVastXmlAllowed: true
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+      - audio
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
+      - audio
diff --git a/static/bidder-params/bliink.json b/static/bidder-params/bliink.json
new file mode 100644
index 00000000..00621dee
--- /dev/null
+++ b/static/bidder-params/bliink.json
@@ -0,0 +1,8 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Bliink Adapter Params",
+  "description": "A schema which validates params accepted by the Bliink adapter",
+  "type": "object",
+
+  "properties": {}
+}
\ No newline at end of file
diff --git a/static/bidder-params/nextmillennium.json b/static/bidder-params/nextmillennium.json
index 07b869c2..743d72f8 100644
--- a/static/bidder-params/nextmillennium.json
+++ b/static/bidder-params/nextmillennium.json
@@ -8,7 +8,23 @@
       "type": "string",
       "minLength": 1,
       "description": "An id used to identify NextMillennium placement"
+    },
+    "group_id": {
+      "type": "string",
+      "minLength": 1,
+      "description": "An id used to identify NextMillennium placement group"
     }
   },
-  "required": ["placement_id"]
+  "anyOf": [
+    {
+      "required": [
+        "placement_id"
+      ]
+    },
+    {
+      "required": [
+        "group_id"
+      ]
+    }
+  ]
 }
diff --git a/static/bidder-params/stroeerCore.json b/static/bidder-params/stroeerCore.json
new file mode 100644
index 00000000..d3476be4
--- /dev/null
+++ b/static/bidder-params/stroeerCore.json
@@ -0,0 +1,14 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "StroeerCore Adapter Params",
+  "description": "A schema which validates params accepted by the StroeerCore adapter",
+
+  "type": "object",
+  "properties": {
+    "sid": {
+      "type": "string",
+      "description": "Slot Id"
+    }
+  },
+  "required": ["sid"]
+}
diff --git a/static/bidder-params/trafficgate.json b/static/bidder-params/trafficgate.json
new file mode 100644
index 00000000..8b7ff3be
--- /dev/null
+++ b/static/bidder-params/trafficgate.json
@@ -0,0 +1,23 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "TrafficGate Adapter Params",
+  "description": "A schema which validates params accepted by the TrafficGate adapter",
+  "type": "object",
+  "properties": {
+    "placementId": {
+      "type": "string",
+      "minLength": 1,
+      "description": "An ID which identifies the TrafficGate placement"
+    },
+    "host": {
+      "type": "string",
+      "minLength": 1,
+      "description": "An ID which identifies the TrafficGate host"
+    },
+    "customParams": {
+      "type": "object",
+      "description": "User-defined targeting key-value pairs."
+    }
+  },
+  "required" : [ "placementId", "host" ]
+}


Test patch:
diff --git a/account/account_test.go b/account/account_test.go
index 2b7f6a4e..68522462 100644
--- a/account/account_test.go
+++ b/account/account_test.go
@@ -66,6 +66,12 @@ func TestGetAccount(t *testing.T) {
 		{accountID: "disabled_acct", required: true, disabled: false, err: &errortypes.BlacklistedAcct{}},
 		{accountID: "disabled_acct", required: false, disabled: true, err: &errortypes.BlacklistedAcct{}},
 		{accountID: "disabled_acct", required: true, disabled: true, err: &errortypes.BlacklistedAcct{}},
+
+		// account not provided (does not exist)
+		{accountID: "", required: false, disabled: false, err: nil},
+		{accountID: "", required: true, disabled: false, err: nil},
+		{accountID: "", required: false, disabled: true, err: &errortypes.BlacklistedAcct{}},
+		{accountID: "", required: true, disabled: true, err: &errortypes.AcctRequired{}},
 	}
 
 	for _, test := range testCases {
diff --git a/adapters/bliink/bliink_test.go b/adapters/bliink/bliink_test.go
new file mode 100644
index 00000000..faa062f8
--- /dev/null
+++ b/adapters/bliink/bliink_test.go
@@ -0,0 +1,19 @@
+package bliink
+
+import (
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"testing"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderBliink, config.Adapter{
+		Endpoint: "http://biddertest.url/bid"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "bliinktest", bidder)
+}
diff --git a/adapters/bliink/bliinktest/exemplary/banner.json b/adapters/bliink/bliinktest/exemplary/banner.json
new file mode 100644
index 00000000..dbff2dfc
--- /dev/null
+++ b/adapters/bliink/bliinktest/exemplary/banner.json
@@ -0,0 +1,126 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123"
+    },
+    "user": {
+      "buyeruid": "awesome-user",
+      "ext": {
+        "consent": "gdprConsentString"
+      }
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "TAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "http://biddertest.url/bid",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123"
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "TAGID"
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user",
+            "ext": {
+              "consent": "gdprConsentString"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 0.9,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                }
+              ],
+              "type": "banner",
+              "seat": "bliink"
+            }
+          ],
+          "cur": "EUR"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 0.9,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 320,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bliink/bliinktest/exemplary/native.json b/adapters/bliink/bliinktest/exemplary/native.json
new file mode 100644
index 00000000..960d91aa
--- /dev/null
+++ b/adapters/bliink/bliinktest/exemplary/native.json
@@ -0,0 +1,122 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123"
+    },
+    "user": {
+      "buyeruid": "awesome-user",
+      "ext": {
+        "consent": "gdprConsentString"
+      }
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "TAGID",
+        "native": {
+          "request": "{test json string}",
+          "ver": "1.2"
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "http://biddertest.url/bid",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123"
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "native": {
+                "request": "{test json string}",
+                "ver": "1.2"
+              },
+              "tagid": "TAGID"
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user",
+            "ext": {
+              "consent": "gdprConsentString"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 0.9,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20"
+                }
+              ],
+              "type": "native",
+              "seat": "bliink"
+            }
+          ],
+          "cur": "EUR"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 0.9,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20"
+          },
+          "type": "native"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bliink/bliinktest/exemplary/video.json b/adapters/bliink/bliinktest/exemplary/video.json
new file mode 100644
index 00000000..8b3bc5e1
--- /dev/null
+++ b/adapters/bliink/bliinktest/exemplary/video.json
@@ -0,0 +1,136 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123"
+    },
+    "user": {
+      "buyeruid": "awesome-user",
+      "ext": {
+        "consent": "gdprConsentString"
+      }
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "TAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 500,
+          "h": 300,
+          "minduration": 120,
+          "maxduration": 150
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "http://biddertest.url/bid",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123"
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "w": 500,
+                "h": 300,
+                "minduration": 120,
+                "maxduration": 150
+              },
+              "tagid": "TAGID"
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user",
+            "ext": {
+              "consent": "gdprConsentString"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 0.9,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                }
+              ],
+              "type": "video",
+              "seat": "bliink"
+            }
+          ],
+          "cur": "EUR"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 0.9,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 320,
+            "h": 50
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bliink/bliinktest/supplemental/multiple_format_request.json b/adapters/bliink/bliinktest/supplemental/multiple_format_request.json
new file mode 100644
index 00000000..43ee1e9d
--- /dev/null
+++ b/adapters/bliink/bliinktest/supplemental/multiple_format_request.json
@@ -0,0 +1,125 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123"
+    },
+    "user": {
+      "buyeruid": "awesome-user",
+      "ext": {
+        "consent": "gdprConsentString"
+      }
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "TAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        }
+      },
+      {
+        "id": "some-impression-id",
+        "tagid": "TAGID",
+        "native": {
+          "request": "{test json string}",
+          "ver": "1.2"
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "http://biddertest.url/bid",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123"
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "TAGID"
+            },
+            {
+              "id": "some-impression-id",
+              "tagid": "TAGID",
+              "native": {
+                "request": "{test json string}",
+                "ver": "1.2"
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user",
+            "ext": {
+              "consent": "gdprConsentString"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 0.9,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                }
+              ]
+            }
+          ],
+          "cur": "EUR"
+        }
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "unable to fetch mediaType in multi-format: some-impression-id",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bliink/bliinktest/supplemental/no_seat_bid_in_response.json b/adapters/bliink/bliinktest/supplemental/no_seat_bid_in_response.json
new file mode 100644
index 00000000..7482a6ff
--- /dev/null
+++ b/adapters/bliink/bliinktest/supplemental/no_seat_bid_in_response.json
@@ -0,0 +1,92 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123"
+    },
+    "user": {
+      "buyeruid": "awesome-user",
+      "ext": {
+        "consent": "gdprConsentString"
+      }
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "TAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "http://biddertest.url/bid",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123"
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "TAGID"
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user",
+            "ext": {
+              "consent": "gdprConsentString"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [],
+          "cur": "EUR"
+        }
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid array",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bliink/bliinktest/supplemental/status_bad_request.json b/adapters/bliink/bliinktest/supplemental/status_bad_request.json
new file mode 100644
index 00000000..2b0bf4e7
--- /dev/null
+++ b/adapters/bliink/bliinktest/supplemental/status_bad_request.json
@@ -0,0 +1,97 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123"
+    },
+    "user": {
+      "buyeruid": "awesome-user",
+      "ext": {
+        "consent": "gdprConsentString"
+      }
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "TAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "http://biddertest.url/bid",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123"
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "TAGID"
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user",
+            "ext": {
+              "consent": "gdprConsentString"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": {
+          "error": {
+            "message": "Validation failed",
+            "details": [
+              {
+                "message": "invalid consent"
+              }
+            ]
+          }
+        }
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bliink/bliinktest/supplemental/status_no_content.json b/adapters/bliink/bliinktest/supplemental/status_no_content.json
new file mode 100644
index 00000000..b696dc27
--- /dev/null
+++ b/adapters/bliink/bliinktest/supplemental/status_no_content.json
@@ -0,0 +1,92 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123"
+    },
+    "user": {
+      "buyeruid": "awesome-user",
+      "ext": {
+        "consent": "gdprConsentString"
+      }
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "TAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "http://biddertest.url/bid",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123"
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "TAGID"
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user",
+            "ext": {
+              "consent": "gdprConsentString"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 204,
+        "body": {
+          "error": {
+            "message": "No content",
+            "details": [
+              {
+                "message": "no content"
+              }
+            ]
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/bliink/bliinktest/supplemental/status_not_ok.json b/adapters/bliink/bliinktest/supplemental/status_not_ok.json
new file mode 100644
index 00000000..5560f830
--- /dev/null
+++ b/adapters/bliink/bliinktest/supplemental/status_not_ok.json
@@ -0,0 +1,92 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123"
+    },
+    "user": {
+      "buyeruid": "awesome-user",
+      "ext": {
+        "consent": "gdprConsentString"
+      }
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "TAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "http://biddertest.url/bid",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123"
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "TAGID"
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user",
+            "ext": {
+              "consent": "gdprConsentString"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 500,
+        "body": {
+          "error": {
+            "message": "Internal server error"
+          }
+        }
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 500. Run with request.debug = 1 for more info.",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json
new file mode 100644
index 00000000..dd9ee32d
--- /dev/null
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json
@@ -0,0 +1,90 @@
+{
+  "mockBidRequest": {
+    "id": "testid",
+    "imp": [
+      {
+        "id": "testimpid",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 250
+            },
+            {
+              "w": 320,
+              "h": 300
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "group_id": "",
+            "placement_id": "7819"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://pbs.nextmillmedia.com/openrtb2/auction",
+        "body":{
+          "id": "testid",
+          "ext": {
+            "prebid": {
+              "storedrequest": {
+                "id": "7819"
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "impid": "123654",
+                  "id": "7457329903666272789",
+                  "price": 0.5,
+                  "adm": "Hello! It\"s a test ad!",
+                  "adid": "96846035",
+                  "adomain": ["test.addomain.com"],
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7457329903666272789",
+            "impid": "123654",
+            "price": 0.5,
+            "adm": "Hello! It\"s a test ad!",
+            "adid": "96846035",
+            "adomain": ["test.addomain.com"],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json
new file mode 100644
index 00000000..72d22b28
--- /dev/null
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json
@@ -0,0 +1,101 @@
+{
+  "mockBidRequest": {
+    "id": "testid",
+    "imp": [
+      {
+        "id": "testimpid",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 250
+            },
+            {
+              "w": 320,
+              "h": 300
+            }
+          ],
+          "w": 320,
+          "h": 250
+        },
+        "ext": {
+          "bidder": {
+            "group_id": "7819"
+          }
+        }
+      }
+    ],
+    "site": {
+      "domain": "www.example.com",
+      "page": "http://www.example.com",
+      "publisher": {
+          "domain": "example.com"
+      },
+      "ext": {
+          "amp": 0
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://pbs.nextmillmedia.com/openrtb2/auction",
+        "body":{
+          "id": "testid",
+          "ext": {
+            "prebid": {
+              "storedrequest": {
+                "id": "g7819;320x250;www.example.com"
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "impid": "123654",
+                  "id": "7457329903666272789",
+                  "price": 0.5,
+                  "adm": "Hello! It\"s a test ad!",
+                  "adid": "96846035",
+                  "adomain": ["test.addomain.com"],
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7457329903666272789",
+            "impid": "123654",
+            "price": 0.5,
+            "adm": "Hello! It\"s a test ad!",
+            "adid": "96846035",
+            "adomain": ["test.addomain.com"],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json
new file mode 100644
index 00000000..6633a063
--- /dev/null
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json
@@ -0,0 +1,94 @@
+{
+  "mockBidRequest": {
+    "id": "testid",
+    "imp": [
+      {
+        "id": "testimpid",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 250
+            },
+            {
+              "w": 320,
+              "h": 300
+            }
+          ],
+          "w": 320,
+          "h": 250
+        },
+        "ext": {
+          "bidder": {
+            "group_id": "7819"
+          }
+        }
+      }
+    ],
+    "app": {
+      "domain": "www.example.com"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://pbs.nextmillmedia.com/openrtb2/auction",
+        "body":{
+          "id": "testid",
+          "ext": {
+            "prebid": {
+              "storedrequest": {
+                "id": "g7819;320x250;www.example.com"
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "impid": "123654",
+                  "id": "7457329903666272789",
+                  "price": 0.5,
+                  "adm": "Hello! It\"s a test ad!",
+                  "adid": "96846035",
+                  "adomain": ["test.addomain.com"],
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7457329903666272789",
+            "impid": "123654",
+            "price": 0.5,
+            "adm": "Hello! It\"s a test ad!",
+            "adid": "96846035",
+            "adomain": ["test.addomain.com"],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json
new file mode 100644
index 00000000..2dc1f3b6
--- /dev/null
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json
@@ -0,0 +1,83 @@
+{
+  "mockBidRequest": {
+    "id": "testid",
+    "imp": [
+      {
+        "id": "testimpid",
+        "banner": {
+          "w": 320
+        },
+        "ext": {
+          "bidder": {
+            "group_id": "7819"
+          }
+        }
+      }
+    ],
+    "app": {
+      "domain": "www.example.com"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://pbs.nextmillmedia.com/openrtb2/auction",
+        "body":{
+          "id": "testid",
+          "ext": {
+            "prebid": {
+              "storedrequest": {
+                "id": "g7819;;www.example.com"
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "impid": "123654",
+                  "id": "7457329903666272789",
+                  "price": 0.5,
+                  "adm": "Hello! It\"s a test ad!",
+                  "adid": "96846035",
+                  "adomain": ["test.addomain.com"],
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7457329903666272789",
+            "impid": "123654",
+            "price": 0.5,
+            "adm": "Hello! It\"s a test ad!",
+            "adid": "96846035",
+            "adomain": ["test.addomain.com"],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json
new file mode 100644
index 00000000..9e3385fd
--- /dev/null
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json
@@ -0,0 +1,84 @@
+{
+  "mockBidRequest": {
+    "id": "testid",
+    "imp": [
+      {
+        "id": "testimpid",
+        "banner": {
+          "w": 320,
+          "h": 250
+        },
+        "ext": {
+          "bidder": {
+            "group_id": "7819"
+          }
+        }
+      }
+    ],
+    "app": {
+      "domain": "www.example.com"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://pbs.nextmillmedia.com/openrtb2/auction",
+        "body":{
+          "id": "testid",
+          "ext": {
+            "prebid": {
+              "storedrequest": {
+                "id": "g7819;320x250;www.example.com"
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "impid": "123654",
+                  "id": "7457329903666272789",
+                  "price": 0.5,
+                  "adm": "Hello! It\"s a test ad!",
+                  "adid": "96846035",
+                  "adomain": ["test.addomain.com"],
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7457329903666272789",
+            "impid": "123654",
+            "price": 0.5,
+            "adm": "Hello! It\"s a test ad!",
+            "adid": "96846035",
+            "adomain": ["test.addomain.com"],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json
new file mode 100644
index 00000000..6a1694ba
--- /dev/null
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json
@@ -0,0 +1,91 @@
+{
+  "mockBidRequest": {
+    "id": "testid",
+    "imp": [
+      {
+        "id": "testimpid",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 250
+            },
+            {
+              "w": 320,
+              "h": 300
+            }
+          ],
+          "w": 320,
+          "h": 250
+        },
+        "ext": {
+          "bidder": {
+            "group_id": "7819"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://pbs.nextmillmedia.com/openrtb2/auction",
+        "body":{
+          "id": "testid",
+          "ext": {
+            "prebid": {
+              "storedrequest": {
+                "id": "g7819;320x250;"
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "impid": "123654",
+                  "id": "7457329903666272789",
+                  "price": 0.5,
+                  "adm": "Hello! It\"s a test ad!",
+                  "adid": "96846035",
+                  "adomain": ["test.addomain.com"],
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7457329903666272789",
+            "impid": "123654",
+            "price": 0.5,
+            "adm": "Hello! It\"s a test ad!",
+            "adid": "96846035",
+            "adomain": ["test.addomain.com"],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json
new file mode 100644
index 00000000..9da3ccf9
--- /dev/null
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json
@@ -0,0 +1,89 @@
+{
+  "mockBidRequest": {
+    "id": "testid",
+    "imp": [
+      {
+        "id": "testimpid",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 250
+            },
+            {
+              "w": 320,
+              "h": 300
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "group_id": "7819"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://pbs.nextmillmedia.com/openrtb2/auction",
+        "body":{
+          "id": "testid",
+          "ext": {
+            "prebid": {
+              "storedrequest": {
+                "id": "g7819;320x250;"
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "impid": "123654",
+                  "id": "7457329903666272789",
+                  "price": 0.5,
+                  "adm": "Hello! It\"s a test ad!",
+                  "adid": "96846035",
+                  "adomain": ["test.addomain.com"],
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7457329903666272789",
+            "impid": "123654",
+            "price": 0.5,
+            "adm": "Hello! It\"s a test ad!",
+            "adid": "96846035",
+            "adomain": ["test.addomain.com"],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json
new file mode 100644
index 00000000..52f53bdb
--- /dev/null
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json
@@ -0,0 +1,78 @@
+{
+  "mockBidRequest": {
+    "id": "testid",
+    "imp": [
+      {
+        "id": "testimpid",
+        "banner": {},
+        "ext": {
+          "bidder": {
+            "group_id": "7819"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://pbs.nextmillmedia.com/openrtb2/auction",
+        "body":{
+          "id": "testid",
+          "ext": {
+            "prebid": {
+              "storedrequest": {
+                "id": "g7819;;"
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "impid": "123654",
+                  "id": "7457329903666272789",
+                  "price": 0.5,
+                  "adm": "Hello! It\"s a test ad!",
+                  "adid": "96846035",
+                  "adomain": ["test.addomain.com"],
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7457329903666272789",
+            "impid": "123654",
+            "price": 0.5,
+            "adm": "Hello! It\"s a test ad!",
+            "adid": "96846035",
+            "adomain": ["test.addomain.com"],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/nextmillennium/params_test.go b/adapters/nextmillennium/params_test.go
index 286d80c6..50a9c377 100644
--- a/adapters/nextmillennium/params_test.go
+++ b/adapters/nextmillennium/params_test.go
@@ -35,6 +35,7 @@ func TestInvalidParams(t *testing.T) {
 
 var validParams = []string{
 	`{"placement_id": "123654"}`,
+	`{"group_id": "123"}`,
 }
 
 var invalidParams = []string{
diff --git a/adapters/stroeerCore/params_test.go b/adapters/stroeerCore/params_test.go
new file mode 100644
index 00000000..92586189
--- /dev/null
+++ b/adapters/stroeerCore/params_test.go
@@ -0,0 +1,49 @@
+package stroeerCore
+
+import (
+	"encoding/json"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"testing"
+)
+
+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.BidderStroeerCore, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected stroeerCore params: %s", validParam)
+		}
+	}
+}
+
+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.BidderStroeerCore, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"sid":"slot id"}`,
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`4.2`,
+	`[]`,
+	`{}`,
+	`{"something":"else"}`,
+	`{"sid":false}`,
+}
diff --git a/adapters/stroeerCore/stroeercore_test.go b/adapters/stroeerCore/stroeercore_test.go
new file mode 100644
index 00000000..be335003
--- /dev/null
+++ b/adapters/stroeerCore/stroeercore_test.go
@@ -0,0 +1,19 @@
+package stroeerCore
+
+import (
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"testing"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderStroeerCore, config.Adapter{
+		Endpoint: "http://localhost/s2sdsh"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "stroeercoretest", bidder)
+}
diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/mobile-banner-single.json b/adapters/stroeerCore/stroeercoretest/exemplary/mobile-banner-single.json
new file mode 100644
index 00000000..0abdbc8b
--- /dev/null
+++ b/adapters/stroeerCore/stroeercoretest/exemplary/mobile-banner-single.json
@@ -0,0 +1,188 @@
+{
+  "mockBidRequest": {
+    "id": "auction-id",
+    "cur": ["EUR"],
+    "imp": [
+      {
+        "id": "3",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 728,
+              "h": 90
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "sid": "123456"
+          }
+        }
+      }
+    ],
+    "device": {
+      "geo":{
+        "city":"Paris",
+        "country":"FRA",
+        "lat": 48.860757,
+        "lon": 2.337562,
+        "region":"IDF",
+        "zip":"75001"
+      },
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0,
+      "devicetype": 4,
+      "ifa": "e785543f-0be8-48f1-2c53-b4ae46a942d3",
+      "hwv": "6S",
+      "make": "Apple",
+      "model": "iPhone",
+      "os": "iOS",
+      "osv": "8.1"
+    },
+    "app": {
+      "id": "test-app-id",
+      "name": "test-app-name",
+      "bundle": "test-app-bundle",
+      "domain": "test-app-domain",
+      "storeurl": "test-app-storeurl",
+      "cat": [
+        "IAB9-30",
+        "IAB9-5"
+      ],
+      "ver": "1.0",
+      "privacypolicy": 1,
+      "paid": 2,
+      "publisher": {
+        "domain": "topleveldomain.com",
+        "id": "04241e0b1cc98976858ce16377c7eef4",
+        "name": "App Publisher"
+      },
+      "keywords": "game,puzzle"
+    },
+    "user": {
+      "buyeruid": "test-buyer-user-id"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": ["application/json"],
+          "Content-Type": ["application/json;charset=utf-8"]
+        },
+        "uri": "http://localhost/s2sdsh",
+        "body": {
+          "id": "auction-id",
+          "cur": ["EUR"],
+          "imp": [
+            {
+              "id": "3",
+              "tagid": "123456",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 728,
+                    "h": 90
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "123456"
+                }
+              }
+            }
+          ],
+          "device": {
+            "geo":{
+              "city":"Paris",
+              "country":"FRA",
+              "lat": 48.860757,
+              "lon": 2.337562,
+              "region":"IDF",
+              "zip":"75001"
+            },
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0,
+            "devicetype": 4,
+            "ifa": "e785543f-0be8-48f1-2c53-b4ae46a942d3",
+            "hwv": "6S",
+            "make": "Apple",
+            "model": "iPhone",
+            "os": "iOS",
+            "osv": "8.1"
+          },
+          "app": {
+            "id": "test-app-id",
+            "name": "test-app-name",
+            "bundle": "test-app-bundle",
+            "domain": "test-app-domain",
+            "storeurl": "test-app-storeurl",
+            "cat": [
+              "IAB9-30",
+              "IAB9-5"
+            ],
+            "ver": "1.0",
+            "privacypolicy": 1,
+            "paid": 2,
+            "publisher": {
+              "domain": "topleveldomain.com",
+              "id": "04241e0b1cc98976858ce16377c7eef4",
+              "name": "App Publisher"
+            },
+            "keywords": "game,puzzle"
+          },
+          "user": {
+            "buyeruid": "test-buyer-user-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "bids": [
+            {
+              "id": "4985939039393-04",
+              "bidId": "3",
+              "cpm": 0.24,
+              "width": 468,
+              "height": 60,
+              "ad": "advert",
+              "crid": "XYZijk"
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "EUR",
+      "bids" : [{
+        "bid": {
+          "id": "4985939039393-04",
+          "impid": "3",
+          "price": 0.24,
+          "adm": "advert",
+          "w": 468,
+          "h": 60,
+          "crid": "XYZijk"
+        },
+        "type": "banner"
+      }]
+    }
+  ]
+}
diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-multi.json b/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-multi.json
new file mode 100644
index 00000000..091f244c
--- /dev/null
+++ b/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-multi.json
@@ -0,0 +1,188 @@
+{
+  "mockBidRequest": {
+    "id": "auction-id",
+    "cur": ["EUR"],
+    "imp": [
+      {
+        "id": "3",
+        "banner": {
+          "format": [
+            {
+              "w": 468,
+              "h": 60
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "sid": "123456"
+          }
+        }
+      },
+      {
+        "id": "9",
+        "banner": {
+          "format": [
+            {
+              "w": 770,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "sid": "85310"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "site": {
+      "domain": "www.publisher.com",
+      "page": "http://www.publisher.com/some/path",
+      "ext": {
+        "amp": 1
+      }
+    },
+    "user": {
+      "buyeruid": "test-buyer-user-id"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": ["application/json"],
+          "Content-Type": ["application/json;charset=utf-8"]
+        },
+        "uri": "http://localhost/s2sdsh",
+        "body": {
+          "id": "auction-id",
+          "cur": ["EUR"],
+          "imp": [
+            {
+              "id": "3",
+              "tagid": "123456",
+              "banner": {
+                "format": [
+                  {
+                    "w": 468,
+                    "h": 60
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "123456"
+                }
+              }
+            },
+            {
+              "id": "9",
+              "tagid": "85310",
+              "banner": {
+                "format": [
+                  {
+                    "w": 770,
+                    "h": 250
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "85310"
+                }
+              }
+            }
+          ],
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "site": {
+            "domain": "www.publisher.com",
+            "page": "http://www.publisher.com/some/path",
+            "ext": {
+              "amp": 1
+            }
+          },
+          "user": {
+            "buyeruid": "test-buyer-user-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "bids": [
+            {
+              "id": "3929239282-01",
+              "bidId": "3",
+              "cpm": 2,
+              "width": 468,
+              "height": 60,
+              "ad": "advert",
+              "crid": "qwert"
+            },
+            {
+              "id": "3929239282-02",
+              "bidId": "9",
+              "cpm": 7.21,
+              "width": 770,
+              "height": 250,
+              "ad": "another advert",
+              "crid": "wasd"
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "EUR",
+      "bids": [
+        {
+          "bid": {
+            "id": "3929239282-01",
+            "impid": "3",
+            "price": 2,
+            "adm": "advert",
+            "w": 468,
+            "h": 60,
+            "crid": "qwert"
+          },
+          "type": "banner"
+        },
+        {
+          "bid": {
+            "id": "3929239282-02",
+            "impid": "9",
+            "price": 7.21,
+            "adm": "another advert",
+            "w": 770,
+            "h": 250,
+            "crid": "wasd"
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-single.json b/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-single.json
new file mode 100644
index 00000000..ca6ea0c2
--- /dev/null
+++ b/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-single.json
@@ -0,0 +1,132 @@
+{
+  "mockBidRequest": {
+    "id": "auction-id",
+    "cur": ["EUR"],
+    "imp": [
+      {
+        "id": "3",
+        "banner": {
+          "format": [
+            {
+              "w": 468,
+              "h": 60
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "sid": "123456"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "site": {
+      "domain": "www.publisher.com",
+      "page": "http://www.publisher.com/some/path",
+      "ext": {
+        "amp": 0
+      }
+    },
+    "user": {
+      "buyeruid": "test-buyer-user-id"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": ["application/json"],
+          "Content-Type": ["application/json;charset=utf-8"]
+        },
+        "uri": "http://localhost/s2sdsh",
+        "body": {
+          "id": "auction-id",
+          "cur": ["EUR"],
+          "imp": [
+            {
+              "id": "3",
+              "tagid": "123456",
+              "banner": {
+                "format": [
+                  {
+                    "w": 468,
+                    "h": 60
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "123456"
+                }
+              }
+            }
+          ],
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "site": {
+            "domain": "www.publisher.com",
+            "page": "http://www.publisher.com/some/path",
+            "ext": {
+              "amp": 0
+            }
+          },
+          "user": {
+            "buyeruid": "test-buyer-user-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "bids": [
+            {
+              "id": "8923356982838-09",
+              "bidId": "3",
+              "cpm": 2,
+              "width": 468,
+              "height": 60,
+              "ad": "advert",
+              "crid": "wasd"
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "EUR",
+      "bids" : [{
+        "bid": {
+          "id": "8923356982838-09",
+          "impid": "3",
+          "price": 2,
+          "adm": "advert",
+          "w": 468,
+          "h": 60,
+          "crid": "wasd"
+        },
+        "type": "banner"
+      }]
+    }
+  ]
+}
diff --git a/adapters/stroeerCore/stroeercoretest/supplemental/bad-server-response.json b/adapters/stroeerCore/stroeercoretest/supplemental/bad-server-response.json
new file mode 100644
index 00000000..48275916
--- /dev/null
+++ b/adapters/stroeerCore/stroeercoretest/supplemental/bad-server-response.json
@@ -0,0 +1,59 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [
+      {
+        "id": "id",
+        "banner": {
+          "w": 300,
+          "h": 200
+        },
+        "ext": {
+          "bidder": {
+            "sid": "tagid"
+          }
+        }
+      }
+    ],
+    "user": {
+      "buyeruid": "test-buyer-user-id"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://localhost/s2sdsh",
+        "body": {
+          "id": "id",
+          "imp": [
+            {
+              "id": "id",
+              "tagid": "tagid",
+              "banner": {
+                "w": 300,
+                "h": 200
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "tagid"
+                }
+              }
+            }
+          ],
+          "user": {
+            "buyeruid": "test-buyer-user-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 500
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected http status code: 500.",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/params_test.go b/adapters/trafficgate/params_test.go
new file mode 100644
index 00000000..4dc2c792
--- /dev/null
+++ b/adapters/trafficgate/params_test.go
@@ -0,0 +1,48 @@
+package trafficgate
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// TestValidParams makes sure that the trafficgate schema accepts all imp.ext fields which we intend to support.
+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.BidderTrafficGate, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected trafficgate params: %s", validParam)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the trafficgate schema rejects all the imp.ext fields we don't support.
+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.BidderTrafficGate, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"placementId": "11", "host": "example"}`,
+}
+
+var invalidParams = []string{
+	`{"id": "456"}`,
+	`{"placementid": "3456", "host": ""}`,
+	`{"placement_id": 346, "host": ""}`,
+	`{"placementID": "", "HOST": "example"}`,
+	`{"placementId": 234}`,
+}
diff --git a/adapters/trafficgate/trafficgate_test.go b/adapters/trafficgate/trafficgate_test.go
new file mode 100644
index 00000000..37cea770
--- /dev/null
+++ b/adapters/trafficgate/trafficgate_test.go
@@ -0,0 +1,28 @@
+package trafficgate
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderTrafficGate, config.Adapter{
+		Endpoint: "http://{{.Host}}.bc-plugin.com/?c=o&m=rtb"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "trafficgatetest", bidder)
+}
+
+func TestEndpointTemplateMalformed(t *testing.T) {
+	_, buildErr := Builder(openrtb_ext.BidderTrafficGate, config.Adapter{
+		Endpoint: "{{Malformed}}"})
+
+	assert.Error(t, buildErr)
+}
diff --git a/adapters/trafficgate/trafficgatetest/exemplary/multiple-imps.json b/adapters/trafficgate/trafficgatetest/exemplary/multiple-imps.json
new file mode 100644
index 00000000..14f77f62
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/exemplary/multiple-imps.json
@@ -0,0 +1,149 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "3",
+            "host": "example"
+          }
+        }
+      },
+      {
+        "id": "test-imp-id2",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1920,
+          "h": 1080
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "3",
+            "host": "example"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "3",
+                  "host": "example"
+                }
+              }
+            },
+            {
+              "id": "test-imp-id2",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1920,
+                "h": 1080
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "3",
+                  "host": "example"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "<VAST version=\"3.0\"></VAST>",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  }
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "<VAST version=\"3.0\"></VAST>",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type": "video"
+        }
+      ],
+      "currency": "USD"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/exemplary/simple-audio.json b/adapters/trafficgate/trafficgatetest/exemplary/simple-audio.json
new file mode 100644
index 00000000..4cbe9f63
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/exemplary/simple-audio.json
@@ -0,0 +1,111 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "audio": {
+          "mimes": ["audio/mp4"]
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "3",
+            "host": "example"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "audio": {
+                "mimes": ["audio/mp4"]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "3",
+                  "host": "example"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+          {
+            "bid": [
+              {
+                "id": "test_bid_id",
+                "impid": "test-imp-id",
+                "price": 0.27543,
+                "adm": "<VAST version=\"4.1\"></VAST>",
+                "cid": "test_cid",
+                "crid": "test_crid",
+                "dealid": "test_dealid",
+                "ext": {
+                  "prebid": {
+                    "type": "audio"
+                  }
+                }
+              }
+            ]
+          }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "<VAST version=\"4.1\"></VAST>",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "type": "audio"
+              }
+            }
+          },
+          "type": "audio"
+        }
+      ],
+      "currency": "USD"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/exemplary/simple-banner.json b/adapters/trafficgate/trafficgatetest/exemplary/simple-banner.json
new file mode 100644
index 00000000..7f3c7abf
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/exemplary/simple-banner.json
@@ -0,0 +1,134 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+        {
+            "id": "test-imp-id",
+            "banner": {
+                "format": [
+                    {
+                      "w": 300,
+                      "h": 250
+                    },
+                    {
+                      "w": 300,
+                      "h": 600
+                    }
+                ]
+            },
+            "ext": {
+                "bidder": {
+                  "placementId": "3",
+                  "host": "example"
+                }
+            }
+        }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+},
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+              {
+                "id": "test-imp-id",
+                "banner": {
+                  "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+                },
+              "ext": {
+                "bidder": {
+                  "placementId": "3",
+                  "host": "example"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+              {
+                "bid": [
+                  {
+                    "id": "test_bid_id",
+                    "impid": "test-imp-id",
+                    "price": 0.27543,
+                    "adm": "<iframe width=\"300\" height=\"250\"></iframe>",
+                    "cid": "test_cid",
+                    "crid": "test_crid",
+                    "dealid": "test_dealid",
+                    "w": 300,
+                    "h": 250,
+                    "ext": {
+                      "prebid": {
+                        "type": "banner"
+                      }
+                    }
+                  }
+                ]
+              }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "<iframe width=\"300\" height=\"250\"></iframe>",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "prebid": {
+                "type": "banner"
+              }
+            }
+          },
+          "type": "banner"
+        }
+      ],
+      "currency": "USD"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/exemplary/simple-native.json b/adapters/trafficgate/trafficgatetest/exemplary/simple-native.json
new file mode 100644
index 00000000..c2482c86
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/exemplary/simple-native.json
@@ -0,0 +1,118 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+        {
+            "id": "test-imp-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}}}"
+            },
+            "ext": {
+                "bidder": {
+                  "placementId": "5",
+                  "host": "example"
+                }
+            }
+        }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+},
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+              {
+                "id": "test-imp-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}}}"
+                },
+              "ext": {
+                "bidder": {
+                  "placementId": "5",
+                  "host": "example"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+              {
+                "bid": [
+                  {
+                    "id": "test_bid_id",
+                    "impid": "test-imp-id",
+                    "price": 0.97642,
+                    "adm": "awesome",
+                    "cid": "test_cid",
+                    "crid": "test_crid",
+                    "dealid": "test_dealid",
+                    "w": 300,
+                    "h": 250,
+                    "ext": {
+                      "prebid": {
+                        "type": "native"
+                      }
+                    }
+                  }
+                ]
+              }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.97642,
+            "adm": "awesome",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "prebid": {
+                "type": "native"
+              }
+            }
+          },
+          "type": "native"
+        }
+      ],
+      "currency": "USD"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/exemplary/simple-video.json b/adapters/trafficgate/trafficgatetest/exemplary/simple-video.json
new file mode 100644
index 00000000..61a6d6ef
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/exemplary/simple-video.json
@@ -0,0 +1,119 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "3",
+            "host": "example"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "3",
+                  "host": "example"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+          {
+            "bid": [
+              {
+                "id": "test_bid_id",
+                "impid": "test-imp-id",
+                "price": 0.27543,
+                "adm": "<VAST version=\"3.0\"></VAST>",
+                "cid": "test_cid",
+                "crid": "test_crid",
+                "dealid": "test_dealid",
+                "ext": {
+                  "prebid": {
+                    "type": "video"
+                  }
+                }
+              }
+            ]
+          }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "<VAST version=\"3.0\"></VAST>",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type": "video"
+        }
+      ],
+      "currency": "USD"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/exemplary/simple-web-banner.json b/adapters/trafficgate/trafficgatetest/exemplary/simple-web-banner.json
new file mode 100644
index 00000000..f46fde30
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/exemplary/simple-web-banner.json
@@ -0,0 +1,130 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "3",
+            "host": "example"
+          }
+        }
+      }
+    ],
+    "site": {
+      "id": "1",
+      "domain": "test.com"
+    },
+    "device": {
+      "ip": "123.123.123.123"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "3",
+                  "host": "example"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "1",
+            "domain": "test.com"
+          },
+          "device": {
+            "ip": "123.123.123.123"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "<iframe width=\"468\" height=\"60\"></iframe>",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "w": 468,
+                  "h": 60,
+                  "ext": {
+                    "prebid": {
+                      "type": "banner"
+                    }
+                  }
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "<iframe width=\"468\" height=\"60\"></iframe>",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "w": 468,
+            "h": 60,
+            "ext": {
+              "prebid": {
+                "type": "banner"
+              }
+            }
+          },
+          "type": "banner"
+        }
+      ],
+      "currency": "USD"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/supplemental/bad-imp-ext.json b/adapters/trafficgate/trafficgatetest/supplemental/bad-imp-ext.json
new file mode 100644
index 00000000..d244f329
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/supplemental/bad-imp-ext.json
@@ -0,0 +1,42 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "invalid": {
+            "placementId": "1",
+            "host": "example"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Bidder parameters required",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/supplemental/bad_bidtype_response.json b/adapters/trafficgate/trafficgatetest/supplemental/bad_bidtype_response.json
new file mode 100644
index 00000000..177a7cf2
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/supplemental/bad_bidtype_response.json
@@ -0,0 +1,108 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "1",
+            "host": "example"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "1",
+                  "host": "example"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "awesome",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "w": 300,
+                  "h": 250,
+                  "ext": ""
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Missing response ext",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/supplemental/bad_ext_response.json b/adapters/trafficgate/trafficgatetest/supplemental/bad_ext_response.json
new file mode 100644
index 00000000..caea968d
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/supplemental/bad_ext_response.json
@@ -0,0 +1,110 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "1",
+            "host": "example"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "1",
+                  "host": "example"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "awesome",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "w": 300,
+                  "h": 250,
+                  "ext": {
+                    "prebid": {}
+                  }
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unable to read bid.ext.prebid.type",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/supplemental/bad_response.json b/adapters/trafficgate/trafficgatetest/supplemental/bad_response.json
new file mode 100644
index 00000000..60c9a43e
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/supplemental/bad_response.json
@@ -0,0 +1,87 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "1",
+            "host": "example"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "1",
+                  "host": "example"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": ""
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "json: cannot unmarshal string into Go value of type openrtb2.BidResponse",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/supplemental/bad_status_code.json b/adapters/trafficgate/trafficgatetest/supplemental/bad_status_code.json
new file mode 100644
index 00000000..41207652
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/supplemental/bad_status_code.json
@@ -0,0 +1,81 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "1",
+            "host": "example"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {}
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "1",
+                  "host": "example"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {}
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Error response with status 400",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/supplemental/imp_ext_empty_object.json b/adapters/trafficgate/trafficgatetest/supplemental/imp_ext_empty_object.json
new file mode 100644
index 00000000..18d84b35
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/supplemental/imp_ext_empty_object.json
@@ -0,0 +1,37 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {}
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Bidder parameters required",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/supplemental/imp_ext_string.json b/adapters/trafficgate/trafficgatetest/supplemental/imp_ext_string.json
new file mode 100644
index 00000000..3037675a
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/supplemental/imp_ext_string.json
@@ -0,0 +1,37 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": ""
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Missing bidder ext",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/supplemental/status-204.json b/adapters/trafficgate/trafficgatetest/supplemental/status-204.json
new file mode 100644
index 00000000..79235df2
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/supplemental/status-204.json
@@ -0,0 +1,82 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "1",
+            "host": "example"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "1",
+                  "host": "example"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+          }
+        }
+      },
+      "expectedBidResponses": [],
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ]
+}
diff --git a/adapters/trafficgate/trafficgatetest/supplemental/status-404.json b/adapters/trafficgate/trafficgatetest/supplemental/status-404.json
new file mode 100644
index 00000000..90bbd764
--- /dev/null
+++ b/adapters/trafficgate/trafficgatetest/supplemental/status-404.json
@@ -0,0 +1,87 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "1",
+            "host": "example"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.bc-plugin.com/?c=o&m=rtb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "1",
+                  "host": "example"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 404,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Error response with status 404",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/config/config_test.go b/config/config_test.go
index 4f9bc44c..5a7d3899 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -137,6 +137,7 @@ func TestDefaults(t *testing.T) {
 	cmpBools(t, "account_required", cfg.AccountRequired, false)
 	cmpInts(t, "metrics.influxdb.collection_rate_seconds", cfg.Metrics.Influxdb.MetricSendInterval, 20)
 	cmpBools(t, "account_adapter_details", cfg.Metrics.Disabled.AccountAdapterDetails, false)
+	cmpBools(t, "account_debug", cfg.Metrics.Disabled.AccountDebug, true)
 	cmpBools(t, "adapter_connections_metrics", cfg.Metrics.Disabled.AdapterConnectionMetrics, true)
 	cmpBools(t, "adapter_gdpr_request_blocked", cfg.Metrics.Disabled.AdapterGDPRRequestBlocked, false)
 	cmpStrings(t, "certificates_file", cfg.PemCertsFile, "")
@@ -339,6 +340,7 @@ metrics:
     metric_send_interval: 30
   disabled_metrics:
     account_adapter_details: true
+    account_debug: false
     adapter_connections_metrics: true
     adapter_gdpr_request_blocked: true
 adapters:
@@ -611,6 +613,7 @@ func TestFullConfig(t *testing.T) {
 	cmpBools(t, "account_required", cfg.AccountRequired, true)
 	cmpBools(t, "auto_gen_source_tid", cfg.AutoGenSourceTID, false)
 	cmpBools(t, "account_adapter_details", cfg.Metrics.Disabled.AccountAdapterDetails, true)
+	cmpBools(t, "account_debug", cfg.Metrics.Disabled.AccountDebug, false)
 	cmpBools(t, "adapter_connections_metrics", cfg.Metrics.Disabled.AdapterConnectionMetrics, true)
 	cmpBools(t, "adapter_gdpr_request_blocked", cfg.Metrics.Disabled.AdapterGDPRRequestBlocked, true)
 	cmpStrings(t, "certificates_file", cfg.PemCertsFile, "/etc/ssl/cert.pem")
diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go
index 53f52a3e..efbb57a4 100644
--- a/endpoints/cookie_sync_test.go
+++ b/endpoints/cookie_sync_test.go
@@ -239,6 +239,8 @@ func TestCookieSyncHandle(t *testing.T) {
 		mockAnalytics := MockAnalytics{}
 		test.setAnalyticsExpectations(&mockAnalytics)
 
+		fakeAccountFetcher := FakeAccountsFetcher{}
+
 		request := httptest.NewRequest("POST", "/cookiesync", test.givenBody)
 		if test.givenCookie != nil {
 			request.AddCookie(test.givenCookie.ToHTTPCookie(24 * time.Hour))
@@ -256,8 +258,9 @@ func TestCookieSyncHandle(t *testing.T) {
 				},
 				ccpaEnforce: true,
 			},
-			metrics:      &mockMetrics,
-			pbsAnalytics: &mockAnalytics,
+			metrics:         &mockMetrics,
+			pbsAnalytics:    &mockAnalytics,
+			accountsFetcher: &fakeAccountFetcher,
 		}
 		endpoint.Handle(writer, request, nil)
 
@@ -787,122 +790,226 @@ func TestCookieSyncParseRequest(t *testing.T) {
 }
 
 func TestSetLimit(t *testing.T) {
-	coopSync := true
+	intNegative1 := -1
+	int20 := 20
+	int30 := 30
+	int40 := 40
 
 	testCases := []struct {
 		description     string
 		givenRequest    cookieSyncRequest
-		givenConfig     config.UserSync
-		expectedError   string
+		givenAccount    *config.Account
 		expectedRequest cookieSyncRequest
 	}{
 		{
-			description: "Test that Max Limit and Default Coop Sync are Applied",
+			description: "Default Limit is Applied (request limit = 0)",
 			givenRequest: cookieSyncRequest{
-				Account: "TestAccount",
-				Limit:   42,
+				Limit: 0,
 			},
-			givenConfig: config.UserSync{
-				Cooperative: config.UserSyncCooperative{
-					PriorityGroups: [][]string{{"a", "b", "c"}},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					DefaultLimit: &int20,
 				},
 			},
 			expectedRequest: cookieSyncRequest{
-				Account:         "TestAccount",
-				Limit:           30,
-				CooperativeSync: &coopSync,
+				Limit: 20,
 			},
-			expectedError: "",
 		},
 		{
-			description: "Test that Default Limit is Applied",
+			description: "Default Limit is Not Applied (default limit not set)",
 			givenRequest: cookieSyncRequest{
-				Account: "TestAccount",
+				Limit: 0,
 			},
-			givenConfig: config.UserSync{
-				Cooperative: config.UserSyncCooperative{
-					PriorityGroups: [][]string{{"a", "b", "c"}},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					DefaultLimit: nil,
 				},
 			},
 			expectedRequest: cookieSyncRequest{
-				Account:         "TestAccount",
-				Limit:           20,
-				CooperativeSync: &coopSync,
+				Limit: 0,
 			},
-			expectedError: "",
 		},
 		{
-			description: "Test that max limit is applied when given limit is zero",
+			description: "Default Limit is Not Applied (request limit > 0)",
 			givenRequest: cookieSyncRequest{
-				Account: "ZeroLimitAccount",
+				Limit: 10,
 			},
-			givenConfig: config.UserSync{
-				Cooperative: config.UserSyncCooperative{
-					PriorityGroups: [][]string{{"a", "b", "c"}},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					DefaultLimit: &int20,
 				},
 			},
 			expectedRequest: cookieSyncRequest{
-				Account:         "ZeroLimitAccount",
-				Limit:           30,
-				CooperativeSync: &coopSync,
+				Limit: 10,
 			},
-			expectedError: "",
 		},
 		{
-			description: "Negative Value Check",
+			description: "Max Limit is Applied (request limit <= 0)",
 			givenRequest: cookieSyncRequest{
-				Account: "NegativeLimitAccount",
+				Limit: 0,
 			},
-			givenConfig: config.UserSync{
-				Cooperative: config.UserSyncCooperative{
-					PriorityGroups: [][]string{{"a", "b", "c"}},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					MaxLimit: &int30,
 				},
 			},
 			expectedRequest: cookieSyncRequest{
-				Account:         "NegativeLimitAccount",
-				Limit:           0,
-				CooperativeSync: &coopSync,
+				Limit: 30,
 			},
-			expectedError: "",
 		},
 		{
-			description: "Error Handler",
+			description: "Max Limit is Applied (0 < max < limit)",
 			givenRequest: cookieSyncRequest{
-				Account: "DisabledAccount",
+				Limit: 40,
 			},
-			givenConfig: config.UserSync{
-				Cooperative: config.UserSyncCooperative{
-					PriorityGroups: [][]string{{"a", "b", "c"}},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					MaxLimit: &int30,
 				},
 			},
 			expectedRequest: cookieSyncRequest{
-				Account: "DisabledAccount",
+				Limit: 30,
+			},
+		},
+		{
+			description: "Max Limit is Not Applied (max not set)",
+			givenRequest: cookieSyncRequest{
+				Limit: 10,
+			},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					MaxLimit: nil,
+				},
+			},
+			expectedRequest: cookieSyncRequest{
+				Limit: 10,
+			},
+		},
+		{
+			description: "Max Limit is Not Applied (0 < limit < max)",
+			givenRequest: cookieSyncRequest{
+				Limit: 10,
+			},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					MaxLimit: &int30,
+				},
+			},
+			expectedRequest: cookieSyncRequest{
+				Limit: 10,
+			},
+		},
+		{
+			description: "Max Limit is Applied After applying the default",
+			givenRequest: cookieSyncRequest{
+				Limit: 0,
+			},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					DefaultLimit: &int40,
+					MaxLimit:     &int30,
+				},
+			},
+			expectedRequest: cookieSyncRequest{
+				Limit: 30,
+			},
+		},
+		{
+			description: "Negative Value Check",
+			givenRequest: cookieSyncRequest{
+				Limit: 0,
+			},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					DefaultLimit: &intNegative1,
+					MaxLimit:     &intNegative1,
+				},
+			},
+			expectedRequest: cookieSyncRequest{
+				Limit: 0,
 			},
-			expectedError: errCookieSyncAccountBlocked.Error(),
 		},
 	}
 
 	for _, test := range testCases {
-		endpoint := cookieSyncEndpoint{
-			config: &config.Configuration{
-				UserSync: test.givenConfig,
+		endpoint := cookieSyncEndpoint{}
+		request := endpoint.setLimit(test.givenRequest, test.givenAccount.CookieSync)
+		assert.Equal(t, test.expectedRequest, request, test.description)
+	}
+}
+
+func TestSetCooperativeSync(t *testing.T) {
+	coopSyncFalse := false
+	coopSyncTrue := true
+
+	testCases := []struct {
+		description     string
+		givenRequest    cookieSyncRequest
+		givenAccount    *config.Account
+		expectedRequest cookieSyncRequest
+	}{
+		{
+			description: "Request coop sync unmodified - request sync nil & default sync nil",
+			givenRequest: cookieSyncRequest{
+				CooperativeSync: nil,
 			},
-			accountsFetcher: FakeAccountsFetcher{AccountData: map[string]json.RawMessage{
-				"TestAccount":          json.RawMessage(`{"cookie_sync": {"default_limit": 20, "max_limit": 30, "default_coop_sync": true}}`),
-				"DisabledAccount":      json.RawMessage(`{"disabled":true}`),
-				"ZeroLimitAccount":     json.RawMessage(`{"cookie_sync": {"default_limit": 0, "max_limit": 30, "default_coop_sync": true}}`),
-				"NegativeLimitAccount": json.RawMessage(`{"cookie_sync": {"default_limit": -1, "max_limit": -1, "default_coop_sync": true}}`),
-			}},
-		}
-		assert.NoError(t, endpoint.config.MarshalAccountDefaults())
-		request, err := endpoint.setLimit(test.givenRequest)
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					DefaultCoopSync: nil,
+				},
+			},
+			expectedRequest: cookieSyncRequest{
+				CooperativeSync: nil,
+			},
+		},
+		{
+			description: "Request coop sync set to default - request sync nil & default sync not nil",
+			givenRequest: cookieSyncRequest{
+				CooperativeSync: nil,
+			},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					DefaultCoopSync: &coopSyncTrue,
+				},
+			},
+			expectedRequest: cookieSyncRequest{
+				CooperativeSync: &coopSyncTrue,
+			},
+		},
+		{
+			description: "Request coop sync unmodified - request sync not nil & default sync nil",
+			givenRequest: cookieSyncRequest{
+				CooperativeSync: &coopSyncTrue,
+			},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					DefaultCoopSync: nil,
+				},
+			},
+			expectedRequest: cookieSyncRequest{
+				CooperativeSync: &coopSyncTrue,
+			},
+		},
+		{
+			description: "Request coop sync unmodified - request sync not nil & default sync not nil",
+			givenRequest: cookieSyncRequest{
+				CooperativeSync: &coopSyncFalse,
+			},
+			givenAccount: &config.Account{
+				CookieSync: config.CookieSync{
+					DefaultCoopSync: &coopSyncTrue,
+				},
+			},
+			expectedRequest: cookieSyncRequest{
+				CooperativeSync: &coopSyncFalse,
+			},
+		},
+	}
 
-		if test.expectedError == "" {
-			assert.NoError(t, err, test.description)
-			assert.Equal(t, test.expectedRequest, request, test.description)
-		} else {
-			assert.EqualError(t, err, test.expectedError, test.description)
-		}
+	for _, test := range testCases {
+		endpoint := cookieSyncEndpoint{}
+		request := endpoint.setCooperativeSync(test.givenRequest, test.givenAccount.CookieSync)
+		assert.Equal(t, test.expectedRequest, request, test.description)
 	}
 }
 
@@ -1652,9 +1759,9 @@ func (m *MockGDPRPerms) BidderSyncAllowed(ctx context.Context, bidder openrtb_ex
 	return args.Bool(0), args.Error(1)
 }
 
-func (m *MockGDPRPerms) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal gdpr.Signal, consent string, aliasGVLIDs map[string]uint16) (allowBidReq bool, passGeo bool, passID bool, err error) {
+func (m *MockGDPRPerms) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal gdpr.Signal, consent string, aliasGVLIDs map[string]uint16) (permissions gdpr.AuctionPermissions, err error) {
 	args := m.Called(ctx, bidderCoreName, bidder, PublisherID, gdprSignal, consent, aliasGVLIDs)
-	return args.Bool(0), args.Bool(1), args.Bool(2), args.Error(3)
+	return args.Get(0).(gdpr.AuctionPermissions), args.Error(1)
 }
 
 type FakeAccountsFetcher struct {
diff --git a/endpoints/setuid_test.go b/endpoints/setuid_test.go
index afe6d612..b27fd20c 100644
--- a/endpoints/setuid_test.go
+++ b/endpoints/setuid_test.go
@@ -573,8 +573,12 @@ func (g *mockPermsSetUID) BidderSyncAllowed(ctx context.Context, bidder openrtb_
 	return false, nil
 }
 
-func (g *mockPermsSetUID) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal gdpr.Signal, consent string, aliasGVLIDs map[string]uint16) (allowBidReq bool, passGeo bool, passID bool, err error) {
-	return g.personalInfoAllowed, g.personalInfoAllowed, g.personalInfoAllowed, nil
+func (g *mockPermsSetUID) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal gdpr.Signal, consent string, aliasGVLIDs map[string]uint16) (permissions gdpr.AuctionPermissions, err error) {
+	return gdpr.AuctionPermissions{
+		AllowBidRequest: g.personalInfoAllowed,
+		PassGeo:         g.personalInfoAllowed,
+		PassID:          g.personalInfoAllowed,
+	}, nil
 }
 
 type fakeSyncer struct {
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index e06ec9d2..9beab5fe 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -3752,7 +3752,6 @@ func TestStoredAuctionResponses(t *testing.T) {
 			GDPRPermissionsBuilder: mockGDPRPermissionsBuilder,
 			TCF2ConfigBuilder:      mockTCF2ConfigBuilder,
 		}
-
 		// Run test
 		outBidResponse, err := e.HoldAuction(context.Background(), auctionRequest, &DebugLog{})
 		if test.errorExpected {
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 2ddafd67..f68223b2 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -35,18 +35,24 @@ func (p *permissionsMock) BidderSyncAllowed(ctx context.Context, bidder openrtb_
 	return true, nil
 }
 
-func (p *permissionsMock) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdpr gdpr.Signal, consent string, aliasGVLIDs map[string]uint16) (allowBidRequest bool, passGeo bool, passID bool, err error) {
+func (p *permissionsMock) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal gdpr.Signal, consent string, aliasGVLIDs map[string]uint16) (permissions gdpr.AuctionPermissions, err error) {
+	permissions = gdpr.AuctionPermissions{
+		PassGeo: p.passGeo,
+		PassID:  p.passID,
+	}
+
 	if p.allowAllBidders {
-		return true, p.passGeo, p.passID, p.activitiesError
+		permissions.AllowBidRequest = true
+		return permissions, p.activitiesError
 	}
 
 	for _, allowedBidder := range p.allowedBidders {
 		if bidder == allowedBidder {
-			allowBidRequest = true
+			permissions.AllowBidRequest = true
 		}
 	}
 
-	return allowBidRequest, p.passGeo, p.passID, p.activitiesError
+	return permissions, p.activitiesError
 }
 
 func assertReq(t *testing.T, bidderRequests []BidderRequest,
diff --git a/gdpr/impl_test.go b/gdpr/impl_test.go
index 025a8b76..b51c376f 100644
--- a/gdpr/impl_test.go
+++ b/gdpr/impl_test.go
@@ -334,10 +334,10 @@ func TestAllowActivities(t *testing.T) {
 	for _, tt := range tests {
 		perms.gdprDefaultValue = tt.gdprDefaultValue
 
-		_, _, passID, err := perms.AuctionActivitiesAllowed(context.Background(), tt.bidderCoreName, tt.bidderName, tt.publisherID, tt.gdpr, tt.consent, tt.aliasGVLIDs)
+		permissions, err := perms.AuctionActivitiesAllowed(context.Background(), tt.bidderCoreName, tt.bidderName, tt.publisherID, tt.gdpr, tt.consent, tt.aliasGVLIDs)
 
 		assert.Nil(t, err, tt.description)
-		assert.Equal(t, tt.passID, passID, tt.description)
+		assert.Equal(t, tt.passID, permissions.PassID, tt.description)
 	}
 }
 
@@ -430,7 +430,7 @@ type testDef struct {
 	description           string
 	bidder                openrtb_ext.BidderName
 	consent               string
-	allowBid              bool
+	allowBidRequest       bool
 	passGeo               bool
 	passID                bool
 	weakVendorEnforcement bool
@@ -460,30 +460,30 @@ func TestAllowActivitiesGeoAndID(t *testing.T) {
 	// COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA : full consents to purposes and vendors 2, 6, 8 and special feature 1 opt-in
 	testDefs := []testDef{
 		{
-			description:    "Appnexus vendor test, insufficient purposes claimed",
-			bidder:         openrtb_ext.BidderAppnexus,
-			bidderCoreName: openrtb_ext.BidderAppnexus,
-			consent:        "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
-			allowBid:       false,
-			passGeo:        false,
-			passID:         false,
+			description:     "Appnexus vendor test, insufficient purposes claimed",
+			bidder:          openrtb_ext.BidderAppnexus,
+			bidderCoreName:  openrtb_ext.BidderAppnexus,
+			consent:         "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
+			allowBidRequest: false,
+			passGeo:         false,
+			passID:          false,
 		},
 		{
-			description:    "Pubmatic Alias vendor test, insufficient purposes claimed",
-			bidder:         "pubmatic1",
-			bidderCoreName: openrtb_ext.BidderPubmatic,
-			consent:        "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
-			allowBid:       false,
-			passGeo:        false,
-			passID:         false,
-			aliasGVLIDs:    map[string]uint16{"pubmatic1": 1},
+			description:     "Pubmatic Alias vendor test, insufficient purposes claimed",
+			bidder:          "pubmatic1",
+			bidderCoreName:  openrtb_ext.BidderPubmatic,
+			consent:         "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
+			allowBidRequest: false,
+			passGeo:         false,
+			passID:          false,
+			aliasGVLIDs:     map[string]uint16{"pubmatic1": 1},
 		},
 		{
 			description:           "Appnexus vendor test, insufficient purposes claimed, basic enforcement",
 			bidder:                openrtb_ext.BidderAppnexus,
 			bidderCoreName:        openrtb_ext.BidderAppnexus,
 			consent:               "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
-			allowBid:              true,
+			allowBidRequest:       true,
 			passGeo:               true,
 			passID:                true,
 			weakVendorEnforcement: true,
@@ -493,50 +493,50 @@ func TestAllowActivitiesGeoAndID(t *testing.T) {
 			bidder:                openrtb_ext.BidderAudienceNetwork,
 			bidderCoreName:        openrtb_ext.BidderAudienceNetwork,
 			consent:               "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
-			allowBid:              true,
+			allowBidRequest:       true,
 			passGeo:               true,
 			passID:                true,
 			weakVendorEnforcement: true,
 		},
 		{
-			description:    "Pubmatic vendor test, flex purposes claimed",
-			bidder:         openrtb_ext.BidderPubmatic,
-			bidderCoreName: openrtb_ext.BidderPubmatic,
-			consent:        "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
-			allowBid:       true,
-			passGeo:        true,
-			passID:         true,
+			description:     "Pubmatic vendor test, flex purposes claimed",
+			bidder:          openrtb_ext.BidderPubmatic,
+			bidderCoreName:  openrtb_ext.BidderPubmatic,
+			consent:         "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
+			allowBidRequest: true,
+			passGeo:         true,
+			passID:          true,
 		},
 		{
-			description:    "Pubmatic Alias vendor test, flex purposes claimed",
-			bidder:         "pubmatic1",
-			bidderCoreName: openrtb_ext.BidderPubmatic,
-			consent:        "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
-			allowBid:       true,
-			passGeo:        true,
-			passID:         true,
-			aliasGVLIDs:    map[string]uint16{"pubmatic1": 6},
+			description:     "Pubmatic Alias vendor test, flex purposes claimed",
+			bidder:          "pubmatic1",
+			bidderCoreName:  openrtb_ext.BidderPubmatic,
+			consent:         "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
+			allowBidRequest: true,
+			passGeo:         true,
+			passID:          true,
+			aliasGVLIDs:     map[string]uint16{"pubmatic1": 6},
 		},
 		{
-			description:    "Rubicon vendor test, Specific purposes/LIs claimed, no geo claimed",
-			bidder:         openrtb_ext.BidderRubicon,
-			bidderCoreName: openrtb_ext.BidderRubicon,
-			consent:        "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
-			allowBid:       true,
-			passGeo:        false,
-			passID:         true,
+			description:     "Rubicon vendor test, Specific purposes/LIs claimed, no geo claimed",
+			bidder:          openrtb_ext.BidderRubicon,
+			bidderCoreName:  openrtb_ext.BidderRubicon,
+			consent:         "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
+			allowBidRequest: true,
+			passGeo:         false,
+			passID:          true,
 		},
 		{
 			// This requires publisher restrictions on any claimed purposes, 2-10. Vendor must declare all claimed purposes
 			// as flex with legit interest as primary.
 			// Using vendor 20 for this.
-			description:    "OpenX vendor test, Specific purposes/LIs claimed, no geo claimed, Publisher restrictions apply",
-			bidder:         openrtb_ext.BidderOpenx,
-			bidderCoreName: openrtb_ext.BidderOpenx,
-			consent:        "CPAavcCPAavcCAGABCFRBKCsAP_AAH_AAAqIHFNf_X_fb3_j-_59_9t0eY1f9_7_v-0zjgeds-8Nyd_X_L8X5mM7vB36pq4KuR4Eu3LBAQdlHOHcTUmw6IkVqTPsbk2Mr7NKJ7PEinMbe2dYGH9_n9XT_ZKY79_____7__-_____7_f__-__3_vp9V---wOJAIMBAUAgAEMAAQIFCIQAAQhiQAAAABBCIBQJIAEqgAWVwEdoIEACAxAQgQAgBBQgwCAAQAAJKAgBACwQCAAiAQAAgAEAIAAEIAILACQEAAAEAJCAAiACECAgiAAg5DAgIgCCAFABAAAuJDACAMooASBAPGQGAAKAAqACGAEwALgAjgBlgDUAHZAPsA_ACMAFLAK2AbwBMQCbAFogLYAYEAw8BkQDOQGeAM-EQHwAVABWAC4AIYAZAAywBqADZAHYAPwAgABGAClgFPANYAdUA-QCGwEOgIvASIAmwBOwCkQFyAMCAYSAw8Bk4DOQGfCQAYADgBzgN_CQTgAEAALgAoACoAGQAOAAeABAACIAFQAMIAaABqADyAIYAigBMgCqAKwAWAAuABvADmAHoAQ0AiACJgEsAS4AmgBSgC3AGGAMgAZcA1ADVAGyAO8AewA-IB9gH6AQAAjABQQClgFPAL8AYoA1gBtADcAG8AOIAegA-QCGwEOgIqAReAkQBMQCZQE2AJ2AUOApEBYoC2AFyALvAYEAwYBhIDDQGHgMiAZIAycBlwDOQGfANIAadA1gDWQoAEAYQaBIACoAKwAXABDADIAGWANQAbIA7AB-AEAAIKARgApYBT4C0ALSAawA3gB1QD5AIbAQ6Ai8BIgCbAE7AKRAXIAwIBhIDDwGMAMnAZyAzwBnwcAEAA4Bv4qA2ABQAFQAQwAmABcAEcAMsAagA7AB-AEYAKXAWgBaQDeAJBATEAmwBTYC2AFyAMCAYeAyIBnIDPAGfANyHQWQAFwAUABUADIAHAAQAAiABdADAAMYAaABqADwAH0AQwBFACZAFUAVgAsABcADEAGYAN4AcwA9ACGAERAJYAmABNACjAFKALEAW4AwwBkADKAGiANQAbIA3wB3gD2gH2AfoBGACVAFBAKeAWKAtAC0gFzALyAX4AxQBuADiQHTAdQA9ACGwEOgIiAReAkEBIgCbAE7AKHAU0AqwBYsC2ALZAXAAuQBdoC7wGEgMNAYeAxIBjADHgGSAMnAZUAywBlwDOQGfANEgaQBpIDSwGnANYAbGPABAIqAb-QgZgALAAoABkAEQALgAYgBDACYAFUALgAYgAzABvAD0AI4AWIAygBqADfAHfAPsA_ACMAFBAKGAU-AtAC0gF-AMUAdQA9ACQQEiAJsAU0AsUBaMC2ALaAXAAuQBdoDDwGJAMiAZOAzkBngDPgGiANJAaWA4AlAyAAQAAsACgAGQAOAAigBgAGIAPAAiABMACqAFwAMQAZgA2gCGgEQARIAowBSgC3AGEAMoAaoA2QB3gD8AIwAU-AtAC0gGKANwAcQA6gCHQEXgJEATYAsUBbAC7QGHgMiAZOAywBnIDPAGfANIAawA4AmACARUA38pBBAAXABQAFQAMgAcABAACKAGAAYwA0ADUAHkAQwBFACYAFIAKoAWAAuABiADMAHMAQwAiABRgClAFiALcAZQA0QBqgDZAHfAPsA_ACMAFBAKGAVsAuYBeQDaAG4APQAh0BF4CRAE2AJ2AUOApoBWwCxQFsALgAXIAu0BhoDDwGMAMiAZIAycBlwDOQGeAM-gaQBpMDWANZAbGVABAA-Ab-A.YAAAAAAAAAAA",
-			allowBid:       true,
-			passGeo:        false,
-			passID:         true,
+			description:     "OpenX vendor test, Specific purposes/LIs claimed, no geo claimed, Publisher restrictions apply",
+			bidder:          openrtb_ext.BidderOpenx,
+			bidderCoreName:  openrtb_ext.BidderOpenx,
+			consent:         "CPAavcCPAavcCAGABCFRBKCsAP_AAH_AAAqIHFNf_X_fb3_j-_59_9t0eY1f9_7_v-0zjgeds-8Nyd_X_L8X5mM7vB36pq4KuR4Eu3LBAQdlHOHcTUmw6IkVqTPsbk2Mr7NKJ7PEinMbe2dYGH9_n9XT_ZKY79_____7__-_____7_f__-__3_vp9V---wOJAIMBAUAgAEMAAQIFCIQAAQhiQAAAABBCIBQJIAEqgAWVwEdoIEACAxAQgQAgBBQgwCAAQAAJKAgBACwQCAAiAQAAgAEAIAAEIAILACQEAAAEAJCAAiACECAgiAAg5DAgIgCCAFABAAAuJDACAMooASBAPGQGAAKAAqACGAEwALgAjgBlgDUAHZAPsA_ACMAFLAK2AbwBMQCbAFogLYAYEAw8BkQDOQGeAM-EQHwAVABWAC4AIYAZAAywBqADZAHYAPwAgABGAClgFPANYAdUA-QCGwEOgIvASIAmwBOwCkQFyAMCAYSAw8Bk4DOQGfCQAYADgBzgN_CQTgAEAALgAoACoAGQAOAAeABAACIAFQAMIAaABqADyAIYAigBMgCqAKwAWAAuABvADmAHoAQ0AiACJgEsAS4AmgBSgC3AGGAMgAZcA1ADVAGyAO8AewA-IB9gH6AQAAjABQQClgFPAL8AYoA1gBtADcAG8AOIAegA-QCGwEOgIqAReAkQBMQCZQE2AJ2AUOApEBYoC2AFyALvAYEAwYBhIDDQGHgMiAZIAycBlwDOQGfANIAadA1gDWQoAEAYQaBIACoAKwAXABDADIAGWANQAbIA7AB-AEAAIKARgApYBT4C0ALSAawA3gB1QD5AIbAQ6Ai8BIgCbAE7AKRAXIAwIBhIDDwGMAMnAZyAzwBnwcAEAA4Bv4qA2ABQAFQAQwAmABcAEcAMsAagA7AB-AEYAKXAWgBaQDeAJBATEAmwBTYC2AFyAMCAYeAyIBnIDPAGfANyHQWQAFwAUABUADIAHAAQAAiABdADAAMYAaABqADwAH0AQwBFACZAFUAVgAsABcADEAGYAN4AcwA9ACGAERAJYAmABNACjAFKALEAW4AwwBkADKAGiANQAbIA3wB3gD2gH2AfoBGACVAFBAKeAWKAtAC0gFzALyAX4AxQBuADiQHTAdQA9ACGwEOgIiAReAkEBIgCbAE7AKHAU0AqwBYsC2ALZAXAAuQBdoC7wGEgMNAYeAxIBjADHgGSAMnAZUAywBlwDOQGfANEgaQBpIDSwGnANYAbGPABAIqAb-QgZgALAAoABkAEQALgAYgBDACYAFUALgAYgAzABvAD0AI4AWIAygBqADfAHfAPsA_ACMAFBAKGAU-AtAC0gF-AMUAdQA9ACQQEiAJsAU0AsUBaMC2ALaAXAAuQBdoDDwGJAMiAZOAzkBngDPgGiANJAaWA4AlAyAAQAAsACgAGQAOAAigBgAGIAPAAiABMACqAFwAMQAZgA2gCGgEQARIAowBSgC3AGEAMoAaoA2QB3gD8AIwAU-AtAC0gGKANwAcQA6gCHQEXgJEATYAsUBbAC7QGHgMiAZOAywBnIDPAGfANIAawA4AmACARUA38pBBAAXABQAFQAMgAcABAACKAGAAYwA0ADUAHkAQwBFACYAFIAKoAWAAuABiADMAHMAQwAiABRgClAFiALcAZQA0QBqgDZAHfAPsA_ACMAFBAKGAVsAuYBeQDaAG4APQAh0BF4CRAE2AJ2AUOApoBWwCxQFsALgAXIAu0BhoDDwGMAMiAZIAycBlwDOQGeAM-gaQBpMDWANZAbGVABAA-Ab-A.YAAAAAAAAAAA",
+			allowBidRequest: true,
+			passGeo:         false,
+			passID:          true,
 		},
 	}
 
@@ -548,11 +548,11 @@ func TestAllowActivitiesGeoAndID(t *testing.T) {
 		}
 		perms.cfg = &tcf2AggConfig
 
-		allowBid, passGeo, passID, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder, "", SignalYes, td.consent, td.aliasGVLIDs)
+		permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder, "", SignalYes, td.consent, td.aliasGVLIDs)
 		assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description)
-		assert.EqualValuesf(t, td.allowBid, allowBid, "AllowBid failure on %s", td.description)
-		assert.EqualValuesf(t, td.passGeo, passGeo, "PassGeo failure on %s", td.description)
-		assert.EqualValuesf(t, td.passID, passID, "PassID failure on %s", td.description)
+		assert.EqualValuesf(t, td.allowBidRequest, permissions.AllowBidRequest, "AllowBid failure on %s", td.description)
+		assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description)
+		assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description)
 	}
 }
 
@@ -575,10 +575,10 @@ func TestAllowActivitiesWhitelist(t *testing.T) {
 	}
 
 	// Assert that an item that otherwise would not be allowed PI access, gets approved because it is found in the GDPR.NonStandardPublishers array
-	_, passGeo, passID, err := perms.AuctionActivitiesAllowed(context.Background(), openrtb_ext.BidderAppnexus, openrtb_ext.BidderAppnexus, "appNexusAppID", SignalYes, "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", map[string]uint16{})
+	permissions, err := perms.AuctionActivitiesAllowed(context.Background(), openrtb_ext.BidderAppnexus, openrtb_ext.BidderAppnexus, "appNexusAppID", SignalYes, "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", map[string]uint16{})
 	assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed")
-	assert.EqualValuesf(t, true, passGeo, "PassGeo failure")
-	assert.EqualValuesf(t, true, passID, "PassID failure")
+	assert.EqualValuesf(t, true, permissions.PassGeo, "PassGeo failure")
+	assert.EqualValuesf(t, true, permissions.PassID, "PassID failure")
 }
 
 func TestAllowActivitiesPubRestrict(t *testing.T) {
@@ -640,10 +640,10 @@ func TestAllowActivitiesPubRestrict(t *testing.T) {
 	}
 
 	for _, td := range testDefs {
-		_, passGeo, passID, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder, "", SignalYes, td.consent, td.aliasGVLIDs)
+		permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder, "", SignalYes, td.consent, td.aliasGVLIDs)
 		assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description)
-		assert.EqualValuesf(t, td.passGeo, passGeo, "PassGeo failure on %s", td.description)
-		assert.EqualValuesf(t, td.passID, passID, "PassID failure on %s", td.description)
+		assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description)
+		assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description)
 	}
 }
 
@@ -795,7 +795,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 		bidder                 openrtb_ext.BidderName
 		bidderCoreName         openrtb_ext.BidderName
 		consent                string
-		allowBid               bool
+		allowBidRequest        bool
 		passGeo                bool
 		passID                 bool
 		aliasGVLIDs            map[string]uint16
@@ -807,7 +807,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 			bidder:                 openrtb_ext.BidderPubmatic,
 			bidderCoreName:         openrtb_ext.BidderPubmatic,
 			consent:                purpose2ConsentWithoutVendorConsent,
-			allowBid:               false,
+			allowBidRequest:        false,
 			passGeo:                false,
 			passID:                 false,
 		},
@@ -818,7 +818,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 			bidder:                 "pubmatic1",
 			bidderCoreName:         openrtb_ext.BidderPubmatic,
 			consent:                purpose2AndVendorConsent,
-			allowBid:               true,
+			allowBidRequest:        true,
 			passGeo:                false,
 			passID:                 true,
 			aliasGVLIDs:            map[string]uint16{"pubmatic1": 6},
@@ -830,7 +830,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 			bidder:                 "pubmatic1",
 			bidderCoreName:         openrtb_ext.BidderPubmatic,
 			consent:                purpose2AndVendorConsent,
-			allowBid:               false,
+			allowBidRequest:        false,
 			passGeo:                false,
 			passID:                 false,
 			aliasGVLIDs:            map[string]uint16{"pubmatic1": 1},
@@ -842,7 +842,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 			bidder:                 openrtb_ext.BidderPubmatic,
 			bidderCoreName:         openrtb_ext.BidderPubmatic,
 			consent:                purpose2ConsentWithoutVendorConsent,
-			allowBid:               true,
+			allowBidRequest:        true,
 			passGeo:                false,
 			passID:                 true,
 		},
@@ -853,7 +853,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 			bidder:                 openrtb_ext.BidderPubmatic,
 			bidderCoreName:         openrtb_ext.BidderPubmatic,
 			consent:                purpose2ConsentWithoutVendorConsent,
-			allowBid:               true,
+			allowBidRequest:        true,
 			passGeo:                false,
 			passID:                 false,
 		},
@@ -864,7 +864,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 			bidder:                 openrtb_ext.BidderPubmatic,
 			bidderCoreName:         openrtb_ext.BidderPubmatic,
 			consent:                purpose2AndVendorConsent,
-			allowBid:               true,
+			allowBidRequest:        true,
 			passGeo:                false,
 			passID:                 true,
 		},
@@ -875,7 +875,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 			bidder:                 openrtb_ext.BidderRubicon,
 			bidderCoreName:         openrtb_ext.BidderRubicon,
 			consent:                purpose2LIWithoutVendorLI,
-			allowBid:               false,
+			allowBidRequest:        false,
 			passGeo:                false,
 			passID:                 false,
 		},
@@ -886,7 +886,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 			bidder:                 openrtb_ext.BidderRubicon,
 			bidderCoreName:         openrtb_ext.BidderRubicon,
 			consent:                purpose2AndVendorLI,
-			allowBid:               true,
+			allowBidRequest:        true,
 			passGeo:                false,
 			passID:                 true,
 		},
@@ -897,7 +897,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 			bidder:                 openrtb_ext.BidderPubmatic,
 			bidderCoreName:         openrtb_ext.BidderPubmatic,
 			consent:                purpose2AndVendorLI,
-			allowBid:               true,
+			allowBidRequest:        true,
 			passGeo:                false,
 			passID:                 true,
 		},
@@ -927,11 +927,11 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 		tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(2)] = &tcf2AggConfig.HostConfig.Purpose2
 		perms.cfg = &tcf2AggConfig
 
-		allowBid, passGeo, passID, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder, "", SignalYes, td.consent, td.aliasGVLIDs)
+		permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder, "", SignalYes, td.consent, td.aliasGVLIDs)
 		assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description)
-		assert.EqualValuesf(t, td.allowBid, allowBid, "AllowBid failure on %s", td.description)
-		assert.EqualValuesf(t, td.passGeo, passGeo, "PassGeo failure on %s", td.description)
-		assert.EqualValuesf(t, td.passID, passID, "PassID failure on %s", td.description)
+		assert.EqualValuesf(t, td.allowBidRequest, permissions.AllowBidRequest, "AllowBid failure on %s", td.description)
+		assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description)
+		assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description)
 	}
 }
 
@@ -946,12 +946,12 @@ func TestTCF1Consent(t *testing.T) {
 		},
 	}
 
-	bidReq, passGeo, passID, err := perms.AuctionActivitiesAllowed(context.Background(), bidderAllowedByConsent, bidderAllowedByConsent, "", SignalYes, tcf1Consent, map[string]uint16{})
+	permissions, err := perms.AuctionActivitiesAllowed(context.Background(), bidderAllowedByConsent, bidderAllowedByConsent, "", SignalYes, tcf1Consent, map[string]uint16{})
 
 	assert.Nil(t, err, "TCF1 consent - no error returned")
-	assert.Equal(t, false, bidReq, "TCF1 consent - bid request not allowed")
-	assert.Equal(t, false, passGeo, "TCF1 consent - passing geo not allowed")
-	assert.Equal(t, false, passID, "TCF1 consent - passing id not allowed")
+	assert.Equal(t, false, permissions.AllowBidRequest, "TCF1 consent - bid request not allowed")
+	assert.Equal(t, false, permissions.PassGeo, "TCF1 consent - passing geo not allowed")
+	assert.Equal(t, false, permissions.PassID, "TCF1 consent - passing id not allowed")
 }
 
 func TestAllowActivitiesVendorException(t *testing.T) {
@@ -964,7 +964,7 @@ func TestAllowActivitiesVendorException(t *testing.T) {
 		sf1VendorExceptionMap map[openrtb_ext.BidderName]struct{}
 		bidder                openrtb_ext.BidderName
 		consent               string
-		allowBid              bool
+		allowBidRequest       bool
 		passGeo               bool
 		passID                bool
 		bidderCoreName        openrtb_ext.BidderName
@@ -975,7 +975,7 @@ func TestAllowActivitiesVendorException(t *testing.T) {
 			bidder:               openrtb_ext.BidderAppnexus,
 			bidderCoreName:       openrtb_ext.BidderAppnexus,
 			consent:              noPurposeOrVendorConsentAndPubRestrictsP2,
-			allowBid:             false,
+			allowBidRequest:      false,
 			passGeo:              false,
 			passID:               false,
 		},
@@ -986,7 +986,7 @@ func TestAllowActivitiesVendorException(t *testing.T) {
 			bidder:                openrtb_ext.BidderAppnexus,
 			bidderCoreName:        openrtb_ext.BidderAppnexus,
 			consent:               noPurposeOrVendorConsentAndPubRestrictsNone,
-			allowBid:              true,
+			allowBidRequest:       true,
 			passGeo:               false,
 			passID:                true,
 		},
@@ -997,7 +997,7 @@ func TestAllowActivitiesVendorException(t *testing.T) {
 			bidder:                openrtb_ext.BidderAppnexus,
 			bidderCoreName:        openrtb_ext.BidderAppnexus,
 			consent:               noPurposeOrVendorConsentAndPubRestrictsNone,
-			allowBid:              false,
+			allowBidRequest:       false,
 			passGeo:               false,
 			passID:                false,
 		},
@@ -1008,7 +1008,7 @@ func TestAllowActivitiesVendorException(t *testing.T) {
 			bidder:                openrtb_ext.BidderAppnexus,
 			bidderCoreName:        openrtb_ext.BidderAppnexus,
 			consent:               noPurposeOrVendorConsentAndPubRestrictsNone,
-			allowBid:              false,
+			allowBidRequest:       false,
 			passGeo:               true,
 			passID:                false,
 		},
@@ -1034,11 +1034,11 @@ func TestAllowActivitiesVendorException(t *testing.T) {
 		tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(3)] = &tcf2AggConfig.HostConfig.Purpose3
 		perms.cfg = &tcf2AggConfig
 
-		allowBid, passGeo, passID, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder, "", SignalYes, td.consent, map[string]uint16{})
+		permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder, "", SignalYes, td.consent, map[string]uint16{})
 		assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description)
-		assert.EqualValuesf(t, td.allowBid, allowBid, "AllowBid failure on %s", td.description)
-		assert.EqualValuesf(t, td.passGeo, passGeo, "PassGeo failure on %s", td.description)
-		assert.EqualValuesf(t, td.passID, passID, "PassID failure on %s", td.description)
+		assert.EqualValuesf(t, td.allowBidRequest, permissions.AllowBidRequest, "AllowBid failure on %s", td.description)
+		assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description)
+		assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description)
 	}
 }
 
diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go
index dd2430d6..60cd101f 100644
--- a/metrics/go_metrics_test.go
+++ b/metrics/go_metrics_test.go
@@ -16,6 +16,7 @@ func TestNewMetrics(t *testing.T) {
 	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{}, syncerKeys)
 
 	ensureContains(t, registry, "app_requests", m.AppRequestMeter)
+	ensureContains(t, registry, "debug_requests", m.DebugRequestMeter)
 	ensureContains(t, registry, "no_cookie_requests", m.NoCookieMeter)
 	ensureContains(t, registry, "request_time", m.RequestTimer)
 	ensureContains(t, registry, "amp_no_cookie_requests", m.AmpNoCookieMeter)
@@ -181,6 +182,72 @@ func TestRecordBidTypeDisabledConfig(t *testing.T) {
 	}
 }
 
+func TestRecordDebugRequest(t *testing.T) {
+	testCases := []struct {
+		description               string
+		givenDisabledMetrics      config.DisabledMetrics
+		givenDebugEnabledFlag     bool
+		givenPubID                string
+		expectedAccountDebugCount int64
+		expectedDebugCount        int64
+	}{
+		{
+			description: "Debug is enabled and account debug is enabled, both metrics should be updated",
+			givenDisabledMetrics: config.DisabledMetrics{
+				AccountAdapterDetails: true,
+				AccountDebug:          false,
+			},
+			givenDebugEnabledFlag:     true,
+			givenPubID:                "acct-id",
+			expectedAccountDebugCount: 1,
+			expectedDebugCount:        1,
+		},
+		{
+			description: "Debug and account debug are disabled, niether metrics should be updated",
+			givenDisabledMetrics: config.DisabledMetrics{
+				AccountAdapterDetails: true,
+				AccountDebug:          true,
+			},
+			givenDebugEnabledFlag:     false,
+			givenPubID:                "acct-id",
+			expectedAccountDebugCount: 0,
+			expectedDebugCount:        0,
+		},
+		{
+			description: "Debug is enabled and account debug is enabled, but unknown PubID leads to account debug being 0",
+			givenDisabledMetrics: config.DisabledMetrics{
+				AccountAdapterDetails: true,
+				AccountDebug:          false,
+			},
+			givenDebugEnabledFlag:     true,
+			givenPubID:                PublisherUnknown,
+			expectedAccountDebugCount: 0,
+			expectedDebugCount:        1,
+		},
+		{
+			description: "Debug is disabled, account debug is enabled, niether metric should update",
+			givenDisabledMetrics: config.DisabledMetrics{
+				AccountAdapterDetails: true,
+				AccountDebug:          false,
+			},
+			givenDebugEnabledFlag:     false,
+			givenPubID:                "acct-id",
+			expectedAccountDebugCount: 0,
+			expectedDebugCount:        0,
+		},
+	}
+	for _, test := range testCases {
+		registry := metrics.NewRegistry()
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, test.givenDisabledMetrics, nil)
+
+		m.RecordDebugRequest(test.givenDebugEnabledFlag, test.givenPubID)
+		am := m.getAccountMetrics(test.givenPubID)
+
+		assert.Equal(t, test.expectedDebugCount, m.DebugRequestMeter.Count())
+		assert.Equal(t, test.expectedAccountDebugCount, am.debugRequestMeter.Count())
+	}
+}
+
 func TestRecordDNSTime(t *testing.T) {
 	testCases := []struct {
 		description         string
diff --git a/metrics/prometheus/prometheus_test.go b/metrics/prometheus/prometheus_test.go
index c7b293da..f8f6cc7d 100644
--- a/metrics/prometheus/prometheus_test.go
+++ b/metrics/prometheus/prometheus_test.go
@@ -156,6 +156,54 @@ func TestRequestMetric(t *testing.T) {
 		})
 }
 
+func TestDebugRequestMetric(t *testing.T) {
+	testCases := []struct {
+		description                      string
+		givenDebugEnabledFlag            bool
+		givenAccountDebugMetricsDisabled bool
+		expectedAccountDebugCount        float64
+		expectedDebugCount               float64
+	}{
+		{
+			description:                      "Debug is enabled and account debug is enabled, both metrics should be updated",
+			givenDebugEnabledFlag:            true,
+			givenAccountDebugMetricsDisabled: false,
+			expectedDebugCount:               1,
+			expectedAccountDebugCount:        1,
+		},
+		{
+			description:                      "Debug and account debug are disabled, niether metrics should be updated",
+			givenDebugEnabledFlag:            false,
+			givenAccountDebugMetricsDisabled: true,
+			expectedDebugCount:               0,
+			expectedAccountDebugCount:        0,
+		},
+		{
+			description:                      "Debug is enabled but account debug is disabled, only non-account debug count should increment",
+			givenDebugEnabledFlag:            true,
+			givenAccountDebugMetricsDisabled: true,
+			expectedDebugCount:               1,
+			expectedAccountDebugCount:        0,
+		},
+		{
+			description:                      "Debug is disabled and account debug is enabled, niether metrics should increment",
+			givenDebugEnabledFlag:            false,
+			givenAccountDebugMetricsDisabled: false,
+			expectedDebugCount:               0,
+			expectedAccountDebugCount:        0,
+		},
+	}
+
+	for _, test := range testCases {
+		m := createMetricsForTesting()
+		m.metricsDisabled.AccountDebug = test.givenAccountDebugMetricsDisabled
+		m.RecordDebugRequest(test.givenDebugEnabledFlag, "acct-id")
+
+		assertCounterVecValue(t, "", "account debug requests", m.accountDebugRequests, test.expectedAccountDebugCount, prometheus.Labels{accountLabel: "acct-id"})
+		assertCounterValue(t, "", "debug requests", m.debugRequests, test.expectedDebugCount)
+	}
+}
+
 func TestRequestMetricWithoutCookie(t *testing.T) {
 	requestType := metrics.ReqTypeORTB2Web
 	performTest := func(m *Metrics, cookieFlag metrics.CookieFlag) {