Repository: prebid/prebid-server
Pull request #3425 (2024-01-23 21:15:30)

Update Go-GPP Library
Update to the latest version of the https://github.com/prebid/go-gpp library. There were pending changes included in this release, such as encoding and updated error handling, which altered some of the public methods. I hadn't realized that, so the version is just a minor release but includes some relatively small breaking changes.


Patch:
diff --git a/adapters/adelement/adelement.go b/adapters/adelement/adelement.go
new file mode 100644
index 00000000..2203aa6d
--- /dev/null
+++ b/adapters/adelement/adelement.go
@@ -0,0 +1,139 @@
+package adelement
+
+import (
+	"encoding/json"
+	"fmt"
+	"text/template"
+
+	"github.com/prebid/openrtb/v20/openrtb2"
+	"github.com/prebid/prebid-server/v2/adapters"
+	"github.com/prebid/prebid-server/v2/config"
+	"github.com/prebid/prebid-server/v2/errortypes"
+	"github.com/prebid/prebid-server/v2/macros"
+	"github.com/prebid/prebid-server/v2/openrtb_ext"
+)
+
+type adapter struct {
+	endpoint *template.Template
+}
+
+// Builder builds a new instance of the Adelement adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
+	template, err := template.New("endpointTemplate").Parse(config.Endpoint)
+	if err != nil {
+		return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
+	}
+
+	bidder := &adapter{
+		endpoint: template,
+	}
+	return bidder, nil
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	adelementExt, err := getImpressionExt(&request.Imp[0])
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	url, err := a.buildEndpointURL(adelementExt)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	requestJSON, err := json.Marshal(request)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	requestData := &adapters.RequestData{
+		Method: "POST",
+		Uri:    url,
+		Body:   requestJSON,
+	}
+
+	return []*adapters.RequestData{requestData}, nil
+}
+
+func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtAdelement, error) {
+	var bidderExt adapters.ExtImpBidder
+	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: "ext.bidder not provided",
+		}
+	}
+	var adelementExt openrtb_ext.ExtAdelement
+	if err := json.Unmarshal(bidderExt.Bidder, &adelementExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: "ext.bidder not provided",
+		}
+	}
+	imp.Ext = nil
+	return &adelementExt, nil
+}
+
+func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtAdelement) (string, error) {
+	endpointParams := macros.EndpointTemplateParams{SupplyId: params.SupplyId}
+	return macros.ResolveMacros(a.endpoint, endpointParams)
+}
+
+func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if adapters.IsResponseStatusCodeNoContent(responseData) {
+		return nil, nil
+	}
+
+	if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil {
+		return nil, []error{err}
+	}
+
+	var response openrtb2.BidResponse
+	if err := json.Unmarshal(responseData.Body, &response); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Bad Server Response",
+		}}
+	}
+
+	if len(response.SeatBid) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid array",
+		}}
+	}
+
+	var bidErrs []error
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
+	bidResponse.Currency = response.Cur
+	for _, seatBid := range response.SeatBid {
+		for i := range seatBid.Bid {
+			bid := seatBid.Bid[i]
+			bidType, err := getBidType(bid)
+			if err != nil {
+				// could not determinate media type, append an error and continue with the next bid.
+				bidErrs = append(bidErrs, err)
+				continue
+			}
+			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+				Bid:     &bid,
+				BidType: bidType,
+			})
+		}
+	}
+	return bidResponse, bidErrs
+}
+
+func getBidType(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+	// determinate media type by bid response field mtype
+	switch bid.MType {
+	case openrtb2.MarkupBanner:
+		return openrtb_ext.BidTypeBanner, nil
+	case openrtb2.MarkupVideo:
+		return openrtb_ext.BidTypeVideo, nil
+	case openrtb2.MarkupAudio:
+		return openrtb_ext.BidTypeAudio, nil
+	case openrtb2.MarkupNative:
+		return openrtb_ext.BidTypeNative, nil
+	}
+
+	return "", &errortypes.BadInput{
+		Message: fmt.Sprintf("Could not define media type for impression: %s", bid.ImpID),
+	}
+}
diff --git a/adapters/nextmillennium/nextmillennium.go b/adapters/nextmillennium/nextmillennium.go
index ad266e5e..608b0b5b 100644
--- a/adapters/nextmillennium/nextmillennium.go
+++ b/adapters/nextmillennium/nextmillennium.go
@@ -15,13 +15,21 @@ import (
 type adapter struct {
 	endpoint string
 	nmmFlags []string
+	server   config.Server
 }
 
 type nmExtPrebidStoredRequest struct {
 	ID string `json:"id"`
 }
+
+type server struct {
+	ExternalUrl string `json:"externalurl"`
+	GvlID       int    `json:"gvlid"`
+	DataCenter  string `json:"datacenter"`
+}
 type nmExtPrebid struct {
 	StoredRequest nmExtPrebidStoredRequest `json:"storedrequest"`
+	Server        *server                  `json:"server,omitempty"`
 }
 type nmExtNMM struct {
 	NmmFlags []string `json:"nmmFlags,omitempty"`
@@ -82,7 +90,7 @@ func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ImpExtNextMillennium, err
 }
 
 func (adapter *adapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ImpExtNextMillennium) (*adapters.RequestData, error) {
-	newBidRequest := createBidRequest(prebidBidRequest, params, adapter.nmmFlags)
+	newBidRequest := createBidRequest(prebidBidRequest, params, adapter.nmmFlags, adapter.server)
 
 	reqJSON, err := json.Marshal(newBidRequest)
 	if err != nil {
@@ -101,7 +109,7 @@ func (adapter *adapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidReques
 		Headers: headers}, nil
 }
 
-func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ImpExtNextMillennium, flags []string) *openrtb2.BidRequest {
+func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ImpExtNextMillennium, flags []string, serverParams config.Server) *openrtb2.BidRequest {
 	placementID := params.PlacementID
 
 	if params.GroupID != "" {
@@ -128,13 +136,22 @@ func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext
 	ext := nextMillJsonExt{}
 	ext.Prebid.StoredRequest.ID = placementID
 	ext.NextMillennium.NmmFlags = flags
-	jsonExt, err := json.Marshal(ext)
+	bidRequest := *prebidBidRequest
+	jsonExtCommon, err := json.Marshal(ext)
 	if err != nil {
 		return prebidBidRequest
 	}
-	bidRequest := *prebidBidRequest
+	bidRequest.Imp[0].Ext = jsonExtCommon
+	ext.Prebid.Server = &server{
+		GvlID:       serverParams.GvlID,
+		DataCenter:  serverParams.DataCenter,
+		ExternalUrl: serverParams.ExternalUrl,
+	}
+	jsonExt, err := json.Marshal(ext)
+	if err != nil {
+		return &bidRequest
+	}
 	bidRequest.Ext = jsonExt
-	bidRequest.Imp[0].Ext = jsonExt
 	return &bidRequest
 }
 
@@ -161,16 +178,21 @@ func (adapter *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalR
 	}
 
 	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
-
+	var errors []error
 	for _, sb := range bidResp.SeatBid {
 		for i := range sb.Bid {
+			bidType, err := getBidType(sb.Bid[i].MType)
+			if err != nil {
+				errors = append(errors, err)
+				continue
+			}
 			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
 				Bid:     &sb.Bid[i],
-				BidType: openrtb_ext.BidTypeBanner,
+				BidType: bidType,
 			})
 		}
 	}
-	return bidResponse, nil
+	return bidResponse, errors
 }
 
 // Builder builds a new instance of the NextMillennium adapter for the given bidder with the given config.
@@ -185,5 +207,17 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co
 	return &adapter{
 		endpoint: config.Endpoint,
 		nmmFlags: info.NmmFlags,
+		server:   server,
 	}, nil
 }
+
+func getBidType(mType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
+	switch mType {
+	case openrtb2.MarkupBanner:
+		return openrtb_ext.BidTypeBanner, nil
+	case openrtb2.MarkupVideo:
+		return openrtb_ext.BidTypeVideo, nil
+	default:
+		return "", &errortypes.BadServerResponse{Message: fmt.Sprintf("Unsupported return mType: %v", mType)}
+	}
+}
diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go
index ef32e404..84d6d784 100644
--- a/endpoints/cookie_sync.go
+++ b/endpoints/cookie_sync.go
@@ -202,10 +202,10 @@ func extractPrivacyPolicies(request cookieSyncRequest, usersyncDefaultGDPRValue
 
 	var gpp gpplib.GppContainer
 	if len(request.GPP) > 0 {
-		var err error
-		gpp, err = gpplib.Parse(request.GPP)
-		if err != nil {
-			return macros.UserSyncPrivacy{}, gdpr.SignalNo, privacy.Policies{}, err
+		var errs []error
+		gpp, errs = gpplib.Parse(request.GPP)
+		if len(errs) > 0 {
+			return macros.UserSyncPrivacy{}, gdpr.SignalNo, privacy.Policies{}, errs[0]
 		}
 	}
 
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 47a402e6..c7beceb1 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -844,10 +844,11 @@ func (deps *endpointDeps) validateRequest(req *openrtb_ext.RequestWrapper, isAmp
 	}
 	var gpp gpplib.GppContainer
 	if req.BidRequest.Regs != nil && len(req.BidRequest.Regs.GPP) > 0 {
-		gpp, err = gpplib.Parse(req.BidRequest.Regs.GPP)
-		if err != nil {
+		var errs []error
+		gpp, errs = gpplib.Parse(req.BidRequest.Regs.GPP)
+		if len(errs) > 0 {
 			errL = append(errL, &errortypes.Warning{
-				Message:     fmt.Sprintf("GPP consent string is invalid and will be ignored. (%v)", err),
+				Message:     fmt.Sprintf("GPP consent string is invalid and will be ignored. (%v)", errs[0]),
 				WarningCode: errortypes.InvalidPrivacyConsentWarningCode})
 		}
 	}
diff --git a/endpoints/setuid.go b/endpoints/setuid.go
index 0f4d36d3..5d91b3c8 100644
--- a/endpoints/setuid.go
+++ b/endpoints/setuid.go
@@ -222,18 +222,14 @@ func extractGDPRInfo(query url.Values) (reqInfo gdpr.RequestInfo, err error) {
 
 // parseGDPRFromGPP parses and validates the "gpp_sid" and "gpp" query fields.
 func parseGDPRFromGPP(query url.Values) (gdpr.RequestInfo, error) {
-	var gdprSignal gdpr.Signal = gdpr.SignalAmbiguous
-	var gdprConsent string = ""
-	var err error
-
-	gdprSignal, err = parseSignalFromGppSidStr(query.Get("gpp_sid"))
+	gdprSignal, err := parseSignalFromGppSidStr(query.Get("gpp_sid"))
 	if err != nil {
 		return gdpr.RequestInfo{GDPRSignal: gdpr.SignalAmbiguous}, err
 	}
 
-	gdprConsent, err = parseConsentFromGppStr(query.Get("gpp"))
-	if err != nil {
-		return gdpr.RequestInfo{GDPRSignal: gdpr.SignalAmbiguous}, err
+	gdprConsent, errs := parseConsentFromGppStr(query.Get("gpp"))
+	if len(errs) > 0 {
+		return gdpr.RequestInfo{GDPRSignal: gdpr.SignalAmbiguous}, errs[0]
 	}
 
 	return gdpr.RequestInfo{
@@ -305,13 +301,13 @@ func parseSignalFromGppSidStr(strSID string) (gdpr.Signal, error) {
 	return gdprSignal, nil
 }
 
-func parseConsentFromGppStr(gppQueryValue string) (string, error) {
+func parseConsentFromGppStr(gppQueryValue string) (string, []error) {
 	var gdprConsent string
 
 	if len(gppQueryValue) > 0 {
-		gpp, err := gpplib.Parse(gppQueryValue)
-		if err != nil {
-			return "", err
+		gpp, errs := gpplib.Parse(gppQueryValue)
+		if len(errs) > 0 {
+			return "", errs
 		}
 
 		if i := gppPrivacy.IndexOfSID(gpp, gppConstants.SectionTCFEU2); i >= 0 {
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 7d998a77..639ea93a 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -6,6 +6,7 @@ import (
 	"github.com/prebid/prebid-server/v2/adapters/aax"
 	"github.com/prebid/prebid-server/v2/adapters/aceex"
 	"github.com/prebid/prebid-server/v2/adapters/acuityads"
+	"github.com/prebid/prebid-server/v2/adapters/adelement"
 	"github.com/prebid/prebid-server/v2/adapters/adf"
 	"github.com/prebid/prebid-server/v2/adapters/adgeneration"
 	"github.com/prebid/prebid-server/v2/adapters/adhese"
@@ -206,6 +207,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderAax:               aax.Builder,
 		openrtb_ext.BidderAceex:             aceex.Builder,
 		openrtb_ext.BidderAcuityAds:         acuityads.Builder,
+		openrtb_ext.BidderAdelement:         adelement.Builder,
 		openrtb_ext.BidderAdf:               adf.Builder,
 		openrtb_ext.BidderAdgeneration:      adgeneration.Builder,
 		openrtb_ext.BidderAdhese:            adhese.Builder,
diff --git a/exchange/bidder.go b/exchange/bidder.go
index baab39b6..96f8ac9b 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -71,6 +71,7 @@ type bidRequestOptions struct {
 	bidAdjustments         map[string]float64
 	tmaxAdjustments        *TmaxAdjustmentsPreprocessed
 	bidderRequestStartTime time.Time
+	responseDebugAllowed   bool
 }
 
 type extraBidderRespInfo struct {
diff --git a/exchange/bidder_validate_bids.go b/exchange/bidder_validate_bids.go
index 9c22475a..0afa32a3 100644
--- a/exchange/bidder_validate_bids.go
+++ b/exchange/bidder_validate_bids.go
@@ -34,7 +34,7 @@ type validatedBidder struct {
 func (v *validatedBidder) requestBid(ctx context.Context, bidderRequest BidderRequest, conversions currency.Conversions, reqInfo *adapters.ExtraRequestInfo, adsCertSigner adscert.Signer, bidRequestOptions bidRequestOptions, alternateBidderCodes openrtb_ext.ExtAlternateBidderCodes, hookExecutor hookexecution.StageExecutor, ruleToAdjustments openrtb_ext.AdjustmentsByDealID) ([]*entities.PbsOrtbSeatBid, extraBidderRespInfo, []error) {
 	seatBids, extraBidderRespInfo, errs := v.bidder.requestBid(ctx, bidderRequest, conversions, reqInfo, adsCertSigner, bidRequestOptions, alternateBidderCodes, hookExecutor, ruleToAdjustments)
 	for _, seatBid := range seatBids {
-		if validationErrors := removeInvalidBids(bidderRequest.BidRequest, seatBid); len(validationErrors) > 0 {
+		if validationErrors := removeInvalidBids(bidderRequest.BidRequest, seatBid, bidRequestOptions.responseDebugAllowed); len(validationErrors) > 0 {
 			errs = append(errs, validationErrors...)
 		}
 	}
@@ -42,7 +42,7 @@ func (v *validatedBidder) requestBid(ctx context.Context, bidderRequest BidderRe
 }
 
 // validateBids will run some validation checks on the returned bids and excise any invalid bids
-func removeInvalidBids(request *openrtb2.BidRequest, seatBid *entities.PbsOrtbSeatBid) []error {
+func removeInvalidBids(request *openrtb2.BidRequest, seatBid *entities.PbsOrtbSeatBid, debug bool) []error {
 	// Exit early if there is nothing to do.
 	if seatBid == nil || len(seatBid.Bids) == 0 {
 		return nil
@@ -57,10 +57,10 @@ func removeInvalidBids(request *openrtb2.BidRequest, seatBid *entities.PbsOrtbSe
 	errs := make([]error, 0, len(seatBid.Bids))
 	validBids := make([]*entities.PbsOrtbBid, 0, len(seatBid.Bids))
 	for _, bid := range seatBid.Bids {
-		if ok, berr := validateBid(bid); ok {
+		if ok, err := validateBid(bid, debug); ok {
 			validBids = append(validBids, bid)
-		} else {
-			errs = append(errs, berr)
+		} else if err != nil {
+			errs = append(errs, err)
 		}
 	}
 	seatBid.Bids = validBids
@@ -104,7 +104,7 @@ func validateCurrency(requestAllowedCurrencies []string, bidCurrency string) err
 }
 
 // validateBid will run the supplied bid through validation checks and return true if it passes, false otherwise.
-func validateBid(bid *entities.PbsOrtbBid) (bool, error) {
+func validateBid(bid *entities.PbsOrtbBid, debug bool) (bool, error) {
 	if bid.Bid == nil {
 		return false, errors.New("Empty bid object submitted.")
 	}
@@ -116,10 +116,16 @@ func validateBid(bid *entities.PbsOrtbBid) (bool, error) {
 		return false, fmt.Errorf("Bid \"%s\" missing required field 'impid'", bid.Bid.ID)
 	}
 	if bid.Bid.Price < 0.0 {
-		return false, fmt.Errorf("Bid \"%s\" does not contain a positive (or zero if there is a deal) 'price'", bid.Bid.ID)
+		if debug {
+			return false, fmt.Errorf("Bid \"%s\" does not contain a positive (or zero if there is a deal) 'price'", bid.Bid.ID)
+		}
+		return false, nil
 	}
 	if bid.Bid.Price == 0.0 && bid.Bid.DealID == "" {
-		return false, fmt.Errorf("Bid \"%s\" does not contain positive 'price' which is required since there is no deal set for this bid", bid.Bid.ID)
+		if debug {
+			return false, fmt.Errorf("Bid \"%s\" does not contain positive 'price' which is required since there is no deal set for this bid", bid.Bid.ID)
+		}
+		return false, nil
 	}
 	if bid.Bid.CrID == "" {
 		return false, fmt.Errorf("Bid \"%s\" missing creative ID", bid.Bid.ID)
diff --git a/exchange/exchange.go b/exchange/exchange.go
index a5f4eb44..349611e8 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -374,7 +374,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog
 			alternateBidderCodes = *r.Account.AlternateBidderCodes
 		}
 		var extraRespInfo extraAuctionResponseInfo
-		adapterBids, adapterExtra, extraRespInfo = e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions, accountDebugAllow, r.GlobalPrivacyControlHeader, debugLog.DebugOverride, alternateBidderCodes, requestExtLegacy.Prebid.Experiment, r.HookExecutor, r.StartTime, bidAdjustmentRules, r.TmaxAdjustments)
+		adapterBids, adapterExtra, extraRespInfo = e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions, accountDebugAllow, r.GlobalPrivacyControlHeader, debugLog.DebugOverride, alternateBidderCodes, requestExtLegacy.Prebid.Experiment, r.HookExecutor, r.StartTime, bidAdjustmentRules, r.TmaxAdjustments, responseDebugAllow)
 		fledge = extraRespInfo.fledge
 		anyBidsReturned = extraRespInfo.bidsFound
 		r.BidderResponseStartTime = extraRespInfo.bidderResponseStartTime
@@ -672,7 +672,8 @@ func (e *exchange) getAllBids(
 	hookExecutor hookexecution.StageExecutor,
 	pbsRequestStartTime time.Time,
 	bidAdjustmentRules map[string][]openrtb_ext.Adjustment,
-	tmaxAdjustments *TmaxAdjustmentsPreprocessed) (
+	tmaxAdjustments *TmaxAdjustmentsPreprocessed,
+	responseDebugAllowed bool) (
 	map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid,
 	map[openrtb_ext.BidderName]*seatResponseExtra,
 	extraAuctionResponseInfo) {
@@ -712,6 +713,7 @@ func (e *exchange) getAllBids(
 				bidAdjustments:         bidAdjustments,
 				tmaxAdjustments:        tmaxAdjustments,
 				bidderRequestStartTime: start,
+				responseDebugAllowed:   responseDebugAllowed,
 			}
 			seatBids, extraBidderRespInfo, err := e.adapterMap[bidderRequest.BidderCoreName].requestBid(ctx, bidderRequest, conversions, &reqInfo, e.adsCertSigner, bidReqOptions, alternateBidderCodes, hookExecutor, bidAdjustmentRules)
 			brw.bidderResponseStartTime = extraBidderRespInfo.respProcessingStartTime
diff --git a/exchange/utils.go b/exchange/utils.go
index ab2cac7e..87358068 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -91,9 +91,10 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context,
 
 	var gpp gpplib.GppContainer
 	if req.BidRequest.Regs != nil && len(req.BidRequest.Regs.GPP) > 0 {
-		gpp, err = gpplib.Parse(req.BidRequest.Regs.GPP)
-		if err != nil {
-			errs = append(errs, err)
+		var gppErrs []error
+		gpp, gppErrs = gpplib.Parse(req.BidRequest.Regs.GPP)
+		if len(gppErrs) > 0 {
+			errs = append(errs, gppErrs[0])
 		}
 	}
 
diff --git a/go.mod b/go.mod
index 708a24d9..94e2a2a4 100644
--- a/go.mod
+++ b/go.mod
@@ -22,7 +22,7 @@ require (
 	github.com/mitchellh/copystructure v1.2.0
 	github.com/pkg/errors v0.9.1
 	github.com/prebid/go-gdpr v1.12.0
-	github.com/prebid/go-gpp v0.1.1
+	github.com/prebid/go-gpp v0.2.0
 	github.com/prebid/openrtb/v20 v20.1.0
 	github.com/prometheus/client_golang v1.12.1
 	github.com/prometheus/client_model v0.2.0
diff --git a/go.sum b/go.sum
index 066ea784..bed61945 100644
--- a/go.sum
+++ b/go.sum
@@ -400,8 +400,8 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr
 github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
 github.com/prebid/go-gdpr v1.12.0 h1:OrjQ7Uc+lCRYaOirQ48jjG/PBMvZsKNAaRTgzxN6iZ0=
 github.com/prebid/go-gdpr v1.12.0/go.mod h1:mPZAdkRxn+iuSjaUuJAi9+0SppBOdM1PCzv/55UH3pY=
-github.com/prebid/go-gpp v0.1.1 h1:uTMJ+eHmKWL9WvDuxFT4LDoOeJW1yOsfWITqi49ZuY0=
-github.com/prebid/go-gpp v0.1.1/go.mod h1:b0TLoVln+HXFD9L9xeimxIH3FN8WDKPJ42auslxEkow=
+github.com/prebid/go-gpp v0.2.0 h1:41Ssxd4Zxr50WgwG1q/1+6awGU3pFnwV7FR4XCLQSuM=
+github.com/prebid/go-gpp v0.2.0/go.mod h1:b0TLoVln+HXFD9L9xeimxIH3FN8WDKPJ42auslxEkow=
 github.com/prebid/openrtb/v20 v20.1.0 h1:Rb+Z3H3UxiqqnjgJK3R9Wt73ibrh7HPzG7ikBckQNqc=
 github.com/prebid/openrtb/v20 v20.1.0/go.mod h1:hLBrA/APkSrxs5MaW639l+y/EAHivDfRagO2TX/wbSc=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
diff --git a/macros/macros.go b/macros/macros.go
index bbee7271..bde843c3 100644
--- a/macros/macros.go
+++ b/macros/macros.go
@@ -16,6 +16,7 @@ type EndpointTemplateParams struct {
 	MediaType   string
 	GvlID       string
 	PageID      string
+	SupplyId    string
 }
 
 // UserSyncPrivacy specifies privacy policy macros, represented as strings, for user sync urls.
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 438d2281..91217f18 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -22,6 +22,7 @@ var coreBidderNames []BidderName = []BidderName{
 	BidderAax,
 	BidderAceex,
 	BidderAcuityAds,
+	BidderAdelement,
 	BidderAdf,
 	BidderAdgeneration,
 	BidderAdhese,
@@ -300,6 +301,7 @@ const (
 	BidderAax               BidderName = "aax"
 	BidderAceex             BidderName = "aceex"
 	BidderAcuityAds         BidderName = "acuityads"
+	BidderAdelement         BidderName = "adelement"
 	BidderAdf               BidderName = "adf"
 	BidderAdgeneration      BidderName = "adgeneration"
 	BidderAdhese            BidderName = "adhese"
diff --git a/openrtb_ext/imp_adelement.go b/openrtb_ext/imp_adelement.go
new file mode 100644
index 00000000..7f5316c9
--- /dev/null
+++ b/openrtb_ext/imp_adelement.go
@@ -0,0 +1,5 @@
+package openrtb_ext
+
+type ExtAdelement struct {
+	SupplyId string `json:"supply_id"`
+}
diff --git a/static/bidder-info/adelement.yaml b/static/bidder-info/adelement.yaml
new file mode 100644
index 00000000..3b852283
--- /dev/null
+++ b/static/bidder-info/adelement.yaml
@@ -0,0 +1,18 @@
+endpoint: "https://amp.adelement.com/openrtb2/auction?supply_id={{.SupplyId}}"
+endpointCompression: gzip
+maintainer:
+  email: "tech@adelement.com"
+gvlVendorID: 196
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - native
+      - video
+      - audio
+  site:
+    mediaTypes:
+      - banner
+      - native
+      - video
+      - audio
\ No newline at end of file
diff --git a/static/bidder-info/nextmillennium.yaml b/static/bidder-info/nextmillennium.yaml
index a6712846..11182ac2 100644
--- a/static/bidder-info/nextmillennium.yaml
+++ b/static/bidder-info/nextmillennium.yaml
@@ -1,13 +1,16 @@
 endpoint: "https://pbs.nextmillmedia.com/openrtb2/auction"
 maintainer:
   email: "accountmanagers@nextmillennium.io"
+gvlVendorID: 1060
 capabilities:
   app:
     mediaTypes:
       - banner
+      - video
   site:
     mediaTypes:
       - banner
+      - video
 userSync:
   iframe:
     url: "https://cookies.nextmillmedia.com/sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}"
diff --git a/static/bidder-params/adelement.json b/static/bidder-params/adelement.json
new file mode 100644
index 00000000..d293fb6d
--- /dev/null
+++ b/static/bidder-params/adelement.json
@@ -0,0 +1,14 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "Adelement Params",
+    "description": "A schema which validates params accepted by the Adelement",
+    "type": "object",
+    "properties": {
+        "supply_id": {
+          "type": "string",
+          "description": "Supply id",
+          "minLength": 1
+        }
+      },
+      "required": ["supply_id"]
+}


Test patch:
diff --git a/adapters/adelement/adelement_test.go b/adapters/adelement/adelement_test.go
new file mode 100644
index 00000000..d1c58bbe
--- /dev/null
+++ b/adapters/adelement/adelement_test.go
@@ -0,0 +1,28 @@
+package adelement
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/v2/adapters/adapterstest"
+	"github.com/prebid/prebid-server/v2/config"
+	"github.com/prebid/prebid-server/v2/openrtb_ext"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderAdelement, config.Adapter{
+		Endpoint: "http://test.adelement.com/openrtb2/auction?supply_id={{.SupplyId}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 196})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "adelementtest", bidder)
+}
+
+func TestEndpointTemplateMalformed(t *testing.T) {
+	_, buildErr := Builder(openrtb_ext.BidderAdelement, config.Adapter{
+		Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 196})
+
+	assert.Error(t, buildErr)
+}
diff --git a/adapters/adelement/adelementtest/exemplary/audio-app.json b/adapters/adelement/adelementtest/exemplary/audio-app.json
new file mode 100644
index 00000000..5384c847
--- /dev/null
+++ b/adapters/adelement/adelementtest/exemplary/audio-app.json
@@ -0,0 +1,90 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "app": {
+      "bundle": "com.prebid"
+    },
+    "device": {
+      "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3"
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "audio": {
+          "mimes": ["audio/mp4"],
+          "protocols": [9,10]
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+        "body": {
+          "id": "test-request-id",
+          "app": {
+            "bundle": "com.prebid"
+          },
+          "device": {
+            "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "audio": {
+                "mimes": ["audio/mp4"],
+                "protocols": [9,10]
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "adelement",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "test-crid",
+                "mtype": 3
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "test-crid",
+            "mtype": 3
+          },
+          "type": "audio"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adelement/adelementtest/exemplary/audio-web.json b/adapters/adelement/adelementtest/exemplary/audio-web.json
new file mode 100644
index 00000000..39d1b9ab
--- /dev/null
+++ b/adapters/adelement/adelementtest/exemplary/audio-web.json
@@ -0,0 +1,90 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "site": {
+      "page": "prebid.org"
+    },
+    "user": {
+      "buyeruid": "be5e209ad46927520000000000000000"
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "audio": {
+          "mimes": ["audio/mp4"],
+          "protocols": [9,10]
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+        "body": {
+          "id": "test-request-id",
+          "site": {
+            "page": "prebid.org"
+          },
+          "user": {
+            "buyeruid": "be5e209ad46927520000000000000000"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "audio": {
+                "mimes": ["audio/mp4"],
+                "protocols": [9,10]
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "adelement",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "test-crid",
+                "mtype": 3
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "test-crid",
+            "mtype": 3
+          },
+          "type": "audio"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adelement/adelementtest/exemplary/banner-app.json b/adapters/adelement/adelementtest/exemplary/banner-app.json
new file mode 100644
index 00000000..2f2b18ff
--- /dev/null
+++ b/adapters/adelement/adelementtest/exemplary/banner-app.json
@@ -0,0 +1,139 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "1",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50,
+                  "mtype": 1
+                }
+              ],
+              "seat": "adelement"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adelement": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "1",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 320,
+            "h": 50,
+            "mtype": 1       
+          },
+          "type": "banner" 
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/adelement/adelementtest/exemplary/banner-web.json b/adapters/adelement/adelementtest/exemplary/banner-web.json
new file mode 100644
index 00000000..fc731fbe
--- /dev/null
+++ b/adapters/adelement/adelementtest/exemplary/banner-web.json
@@ -0,0 +1,127 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w":320,
+          "h":50
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "banner": {
+                "w":320,
+                "h":50
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "1",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50,
+                  "mtype": 1
+                }
+              ],
+              "seat": "adelement"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adelement": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "1",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 320,
+            "h": 50,
+            "mtype": 1
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adelement/adelementtest/exemplary/native-app.json b/adapters/adelement/adelementtest/exemplary/native-app.json
new file mode 100644
index 00000000..4ced9789
--- /dev/null
+++ b/adapters/adelement/adelementtest/exemplary/native-app.json
@@ -0,0 +1,136 @@
+{
+    "mockBidRequest": {
+      "id": "some-request-id",
+      "device": {
+        "ua": "test-user-agent",
+        "ip": "123.123.123.123",
+        "language": "en",
+        "dnt": 0
+      },
+      "tmax": 1000,
+      "user": {
+        "buyeruid": "awesome-user"
+      },
+      "app": {
+        "publisher": {
+          "id": "123456789"
+        },
+        "cat": [
+          "IAB22-1"
+        ],
+        "bundle": "com.app.awesome",
+        "name": "Awesome App",
+        "domain": "awesomeapp.com",
+        "id": "123456789"
+      },
+      "imp": [
+        {
+          "id": "some-impression-id",
+          "tagid": "ogTAGID",
+          "native": {
+            "ver":"1.1",
+            "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+          },
+          "ext": {
+            "bidder": {
+              "supply_id": "1"
+            }
+          }
+        }
+      ]
+    },
+    "httpCalls": [
+      {
+        "expectedRequest": {
+          "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+          "body": {
+            "id": "some-request-id",
+            "device": {
+              "ua": "test-user-agent",
+              "ip": "123.123.123.123",
+              "language": "en",
+              "dnt": 0
+            },
+            "imp": [
+              {
+                "id": "some-impression-id",
+                "native": {
+                  "ver":"1.1",
+                  "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+                },
+                "tagid": "ogTAGID"
+              }
+            ],
+            "app": {
+              "id": "123456789",
+              "name": "Awesome App",
+              "bundle": "com.app.awesome",
+              "domain": "awesomeapp.com",
+              "cat": [
+                "IAB22-1"
+              ],
+              "publisher": {
+                "id": "123456789"
+              }
+            },
+            "user": {
+              "buyeruid": "awesome-user"
+            },
+            "tmax": 1000
+          }
+        },
+        "mockResponse": {
+          "status": 200,
+          "body": {
+            "id": "awesome-resp-id",
+            "seatbid": [
+              {
+                "bid": [
+                  {
+                    "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                    "impid": "some-impression-id",
+                    "price": 3.5,
+                    "adm": "awesome-markup",
+                    "adomain": [
+                      "awesome.com"
+                    ],
+                    "crid": "20",
+                    "mtype": 4
+                  }
+                ],
+                "seat": "adelement"
+              }
+            ],
+            "cur": "USD",
+            "ext": {
+              "responsetimemillis": {
+                "adelement": 154
+              },
+              "tmaxrequest": 1000
+            }
+          }
+        }
+      }
+    ],
+    "expectedBidResponses": [
+      {
+        "bids":[
+          {
+            "bid":  {
+              "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+              "impid": "some-impression-id",
+              "price": 3.5,
+              "adm": "awesome-markup",
+              "crid": "20",
+              "adomain": [
+                "awesome.com"
+              ],
+              "mtype": 4
+            },
+            "type": "native"
+          }
+        ]
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/adapters/adelement/adelementtest/exemplary/native-web.json b/adapters/adelement/adelementtest/exemplary/native-web.json
new file mode 100644
index 00000000..7c9faad7
--- /dev/null
+++ b/adapters/adelement/adelementtest/exemplary/native-web.json
@@ -0,0 +1,124 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "native": {
+          "ver":"1.1",
+          "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+        },
+        "ext": {
+          "bidder": {
+            "host": "ep1",
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "native": {
+                "ver":"1.1",
+                "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "mtype": 4
+                }
+              ],
+              "seat": "acuityads"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "acuityads": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "mtype": 4
+          },
+          "type": "native"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adelement/adelementtest/exemplary/video-app.json b/adapters/adelement/adelementtest/exemplary/video-app.json
new file mode 100644
index 00000000..c53f2391
--- /dev/null
+++ b/adapters/adelement/adelementtest/exemplary/video-app.json
@@ -0,0 +1,149 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 1280,
+                  "h": 720,
+                  "mtype": 2
+                }
+              ],
+              "seat": "adelement"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adelement": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 1280,
+            "h": 720,
+            "mtype": 2
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adelement/adelementtest/exemplary/video-web.json b/adapters/adelement/adelementtest/exemplary/video-web.json
new file mode 100644
index 00000000..7248d0ac
--- /dev/null
+++ b/adapters/adelement/adelementtest/exemplary/video-web.json
@@ -0,0 +1,147 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 1280,
+                  "h": 720,
+                  "mtype": 2,
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  }
+                }
+              ],
+              "seat": "adelement"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adelement": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 1280,
+            "h": 720,
+            "mtype": 2,
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type":"video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/adelement/adelementtest/supplemental/empty-seatbid-array.json b/adapters/adelement/adelementtest/supplemental/empty-seatbid-array.json
new file mode 100644
index 00000000..64fdde7e
--- /dev/null
+++ b/adapters/adelement/adelementtest/supplemental/empty-seatbid-array.json
@@ -0,0 +1,119 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adelement": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+    "mockResponse": {
+      "status": 200,
+      "body": "invalid response"
+    },
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid array",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/adelement/adelementtest/supplemental/invalid-aceex-ext-object.json b/adapters/adelement/adelementtest/supplemental/invalid-aceex-ext-object.json
new file mode 100644
index 00000000..77752d01
--- /dev/null
+++ b/adapters/adelement/adelementtest/supplemental/invalid-aceex-ext-object.json
@@ -0,0 +1,29 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "ext.bidder not provided",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "my-adcode",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": "Awesome"
+      }
+    ],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
diff --git a/adapters/adelement/adelementtest/supplemental/invalid-response.json b/adapters/adelement/adelementtest/supplemental/invalid-response.json
new file mode 100644
index 00000000..b44dcaf4
--- /dev/null
+++ b/adapters/adelement/adelementtest/supplemental/invalid-response.json
@@ -0,0 +1,94 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w":320,
+          "h":50
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+      "body": {
+        "id": "some-request-id",
+        "device": {
+          "ua": "test-user-agent",
+          "ip": "123.123.123.123",
+          "language": "en",
+          "dnt": 0
+        },
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "banner": {
+                "w":320,
+                "h":50
+            },
+            "tagid": "ogTAGID"
+          }
+        ],
+        "app": {
+          "id": "123456789",
+          "name": "Awesome App",
+          "bundle": "com.app.awesome",
+          "domain": "awesomeapp.com",
+          "cat": [
+            "IAB22-1"
+          ],
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": "invalid response"
+    }
+  }],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bad Server Response",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/adelement/adelementtest/supplemental/status-code-bad-request.json b/adapters/adelement/adelementtest/supplemental/status-code-bad-request.json
new file mode 100644
index 00000000..d2db8338
--- /dev/null
+++ b/adapters/adelement/adelementtest/supplemental/status-code-bad-request.json
@@ -0,0 +1,92 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "tagid": "ogTAGID"
+          }
+        ],
+        "app":  {
+          "publisher": {
+            "id": "123456789"
+          },
+          "cat": [
+            "IAB22-1"
+          ],
+          "bundle": "com.app.awesome",
+          "name": "Awesome App",
+          "domain": "awesomeapp.com",
+          "id": "123456789"
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 400
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/adelement/adelementtest/supplemental/status-code-no-content.json b/adapters/adelement/adelementtest/supplemental/status-code-no-content.json
new file mode 100644
index 00000000..a830cbcf
--- /dev/null
+++ b/adapters/adelement/adelementtest/supplemental/status-code-no-content.json
@@ -0,0 +1,68 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [{
+      "id": "some-impression-id",
+      "tagid": "ogTAGID",
+      "video": {
+        "mimes": ["video/mp4"],
+        "w": 640,
+        "h": 480,
+        "minduration": 120,
+        "maxduration": 150
+      },
+      "ext": {
+        "bidder": {
+          "supply_id": "1"
+        }
+      }
+    }]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+      "body": {
+        "id": "some-request-id",
+        "imp": [{
+          "id": "some-impression-id",
+          "tagid": "ogTAGID",
+          "video": {
+            "mimes": [
+              "video/mp4"
+            ],
+            "minduration": 120,
+            "maxduration": 150,
+            "w": 640,
+            "h": 480
+          }
+        }],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 204
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": []
+}
\ No newline at end of file
diff --git a/adapters/adelement/adelementtest/supplemental/status-code-other-error.json b/adapters/adelement/adelementtest/supplemental/status-code-other-error.json
new file mode 100644
index 00000000..f5a383d1
--- /dev/null
+++ b/adapters/adelement/adelementtest/supplemental/status-code-other-error.json
@@ -0,0 +1,78 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "ogTAGID",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 306
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 306. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/adelement/adelementtest/supplemental/status-code-service-unavailable.json b/adapters/adelement/adelementtest/supplemental/status-code-service-unavailable.json
new file mode 100644
index 00000000..abec808b
--- /dev/null
+++ b/adapters/adelement/adelementtest/supplemental/status-code-service-unavailable.json
@@ -0,0 +1,78 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "supply_id": "1"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://test.adelement.com/openrtb2/auction?supply_id=1",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "ogTAGID",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 503
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 503. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json
index 19212134..4db813f5 100644
--- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json
@@ -3,7 +3,7 @@
     "id": "testid",
     "imp": [
       {
-        "id": "testimpid",
+        "id": "123654",
         "banner": {
           "format": [
             {
@@ -37,6 +37,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "7819"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
@@ -62,7 +67,7 @@
                   }
                 }
               },
-              "id": "testimpid"
+              "id": "123654"
             }
           ]
         }
@@ -82,7 +87,8 @@
                   "adid": "96846035",
                   "adomain": ["test.addomain.com"],
                   "w": 300,
-                  "h": 250
+                  "h": 250,
+                  "mtype":1
                 }
               ]
             }
@@ -106,7 +112,8 @@
             "adid": "96846035",
             "adomain": ["test.addomain.com"],
             "w": 300,
-            "h": 250
+            "h": 250,
+            "mtype":1
           },
           "type": "banner"
         }
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json
index 129c025e..ef46dba6 100644
--- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json
@@ -3,7 +3,7 @@
     "id": "testid",
     "imp": [
       {
-        "id": "testimpid",
+        "id": "123654",
         "banner": {
           "format": [
             {
@@ -48,6 +48,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "g7819;320x250;www.example.com"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
@@ -75,7 +80,7 @@
                   }
                 }
               },
-              "id": "testimpid"
+              "id": "123654"
             }
           ],
           "site": {
@@ -105,7 +110,8 @@
                   "adid": "96846035",
                   "adomain": ["test.addomain.com"],
                   "w": 300,
-                  "h": 250
+                  "h": 250,
+                  "mtype":1
                 }
               ]
             }
@@ -129,7 +135,8 @@
             "adid": "96846035",
             "adomain": ["test.addomain.com"],
             "w": 300,
-            "h": 250
+            "h": 250,
+            "mtype":1
           },
           "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
index 2ddf9bee..5b23888e 100644
--- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json
@@ -3,7 +3,7 @@
     "id": "testid",
     "imp": [
       {
-        "id": "testimpid",
+        "id": "123654",
         "banner": {
           "format": [
             {
@@ -44,6 +44,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "g7819;320x250;www.example.com"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
@@ -71,7 +76,7 @@
                   }
                 }
               },
-              "id": "testimpid"
+              "id": "123654"
             }
           ]
         }
@@ -91,7 +96,8 @@
                   "adid": "96846035",
                   "adomain": ["test.addomain.com"],
                   "w": 300,
-                  "h": 250
+                  "h": 250,
+                  "mtype":1
                 }
               ]
             }
@@ -115,7 +121,8 @@
             "adid": "96846035",
             "adomain": ["test.addomain.com"],
             "w": 300,
-            "h": 250
+            "h": 250,
+            "mtype":1
           },
           "type": "banner"
         }
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json
index 4db65ec4..f18aae21 100644
--- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json
@@ -3,7 +3,7 @@
     "id": "testid",
     "imp": [
       {
-        "id": "testimpid",
+        "id": "123654",
         "banner": {
           "w": 320
         },
@@ -33,6 +33,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "g7819;;www.example.com"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
@@ -49,7 +54,7 @@
                   }
                 }
               },
-              "id": "testimpid"
+              "id": "123654"
             }
           ]
         }
@@ -69,7 +74,8 @@
                   "adid": "96846035",
                   "adomain": ["test.addomain.com"],
                   "w": 300,
-                  "h": 250
+                  "h": 250,
+                  "mtype":1
                 }
               ]
             }
@@ -93,7 +99,8 @@
             "adid": "96846035",
             "adomain": ["test.addomain.com"],
             "w": 300,
-            "h": 250
+            "h": 250,
+            "mtype":1
           },
           "type": "banner"
         }
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json
index f7da0784..29d3ce8d 100644
--- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json
@@ -3,7 +3,7 @@
     "id": "testid",
     "imp": [
       {
-        "id": "testimpid",
+        "id": "123654",
         "banner": {
           "w": 320,
           "h": 250
@@ -34,6 +34,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "g7819;320x250;www.example.com"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
@@ -51,7 +56,7 @@
                   }
                 }
               },
-              "id": "testimpid"
+              "id": "123654"
             }
           ]
         }
@@ -71,7 +76,8 @@
                   "adid": "96846035",
                   "adomain": ["test.addomain.com"],
                   "w": 300,
-                  "h": 250
+                  "h": 250,
+                  "mtype":1
                 }
               ]
             }
@@ -95,7 +101,8 @@
             "adid": "96846035",
             "adomain": ["test.addomain.com"],
             "w": 300,
-            "h": 250
+            "h": 250,
+            "mtype":1
           },
           "type": "banner"
         }
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json
index d27dffaf..8ff3f454 100644
--- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json
@@ -3,7 +3,7 @@
     "id": "testid",
     "imp": [
       {
-        "id": "testimpid",
+        "id": "123654",
         "banner": {
           "format": [
             {
@@ -38,6 +38,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "g7819;320x250;"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
@@ -65,7 +70,7 @@
                   }
                 }
               },
-              "id": "testimpid"
+              "id": "123654"
             }
           ]
         }
@@ -85,7 +90,8 @@
                   "adid": "96846035",
                   "adomain": ["test.addomain.com"],
                   "w": 300,
-                  "h": 250
+                  "h": 250,
+                  "mtype":1
                 }
               ]
             }
@@ -109,7 +115,8 @@
             "adid": "96846035",
             "adomain": ["test.addomain.com"],
             "w": 300,
-            "h": 250
+            "h": 250,
+            "mtype":1
           },
           "type": "banner"
         }
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json
index c5b92767..de6a8cde 100644
--- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json
@@ -3,7 +3,7 @@
     "id": "testid",
     "imp": [
       {
-        "id": "testimpid",
+        "id": "123654",
         "banner": {
           "format": [
             {
@@ -36,6 +36,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "g7819;320x250;"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
@@ -61,7 +66,7 @@
                   }
                 }
               },
-              "id": "testimpid"
+              "id": "123654"
             }
           ]
         }
@@ -81,7 +86,8 @@
                   "adid": "96846035",
                   "adomain": ["test.addomain.com"],
                   "w": 300,
-                  "h": 250
+                  "h": 250,
+                  "mtype":1
                 }
               ]
             }
@@ -105,7 +111,8 @@
             "adid": "96846035",
             "adomain": ["test.addomain.com"],
             "w": 300,
-            "h": 250
+            "h": 250,
+            "mtype":1
           },
           "type": "banner"
         }
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json
index df736d79..d992a5af 100644
--- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json
@@ -3,7 +3,7 @@
     "id": "testid",
     "imp": [
       {
-        "id": "testimpid",
+        "id": "123654",
         "banner": {
           "format": [
             {
@@ -38,6 +38,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "7819"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
@@ -65,7 +70,7 @@
                   }
                 }
               },
-              "id": "testimpid"
+              "id": "123654"
             }
           ]
         }
@@ -85,7 +90,8 @@
                   "adid": "96846035",
                   "adomain": ["test.addomain.com"],
                   "w": 300,
-                  "h": 250
+                  "h": 250,
+                  "mtype":1
                 }
               ]
             }
@@ -109,7 +115,8 @@
             "adid": "96846035",
             "adomain": ["test.addomain.com"],
             "w": 300,
-            "h": 250
+            "h": 250,
+            "mtype":1
           },
           "type": "banner"
         }
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json
index 2d357ffb..70755fe6 100644
--- a/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json
@@ -3,7 +3,7 @@
     "id": "testid",
     "imp": [
       {
-        "id": "testimpid",
+        "id": "123654",
         "banner": {},
         "ext": {
           "bidder": {
@@ -25,6 +25,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "g7819;;"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
@@ -39,7 +44,7 @@
                   }
                 }
               },
-              "id": "testimpid"
+              "id": "123654"
             }
           ]
         }
@@ -59,7 +64,8 @@
                   "adid": "96846035",
                   "adomain": ["test.addomain.com"],
                   "w": 300,
-                  "h": 250
+                  "h": 250,
+                  "mtype":1
                 }
               ]
             }
@@ -83,7 +89,8 @@
             "adid": "96846035",
             "adomain": ["test.addomain.com"],
             "w": 300,
-            "h": 250
+            "h": 250,
+            "mtype":1
           },
           "type": "banner"
         }
diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json
new file mode 100644
index 00000000..442f8ea9
--- /dev/null
+++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json
@@ -0,0 +1,118 @@
+{
+    "mockBidRequest": {
+      "id": "testid",
+      "imp": [
+        {
+          "id": "123654",
+          "video": {
+            "mimes": [
+                "video/mp4"
+            ],
+            "protocols": [
+                2
+            ],
+            "w": 1024,
+            "h": 576
+            },
+            "ext": {
+                "bidder": {
+                "placement_id": "7819"
+                }
+          }
+        }
+      ]
+    },
+  
+    "httpCalls": [
+      {
+        "expectedRequest": {
+          "uri": "https://pbs.nextmillmedia.com/openrtb2/auction",
+          "body":{
+            "id": "testid",
+            "ext": {
+              "nextMillennium": {},
+              "prebid": {
+                "storedrequest": {
+                  "id": "7819"
+                },
+                "server": {
+                  "datacenter": "2",
+                  "externalurl": "http://hosturl.com",
+                 "gvlid": 1
+                }
+              }
+            },
+            "imp": [
+              {
+                "video": {
+                    "mimes": [
+                        "video/mp4"
+                    ],
+                    "protocols": [
+                        2
+                    ],
+                    "w": 1024,
+                    "h": 576
+                },
+                "ext": {
+                  "nextMillennium": {},
+                  "prebid": {
+                    "storedrequest": {
+                      "id": "7819"
+                    }
+                  }
+                },
+                "id": "123654"
+              }
+            ]
+          }
+        },
+        "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,
+                    "mtype":2
+                  }
+                ]
+              }
+            ],
+            "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,
+              "mtype":2
+            },
+            "type": "video"
+          }
+        ]
+      }
+    ]
+  }
diff --git a/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json b/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json
index 8f3588de..bc976492 100644
--- a/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json
+++ b/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json
@@ -37,6 +37,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "7819"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
diff --git a/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json b/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json
index f7b23ac9..f846fd70 100644
--- a/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json
+++ b/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json
@@ -33,6 +33,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "7819"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
diff --git a/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json b/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json
index 699be4e9..3df21fd5 100644
--- a/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json
+++ b/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json
@@ -33,6 +33,11 @@
             "prebid": {
               "storedrequest": {
                 "id": "7819"
+              },
+              "server": {
+                "datacenter": "2",
+                "externalurl": "http://hosturl.com",
+               "gvlid": 1
               }
             }
           },
diff --git a/endpoints/setuid_test.go b/endpoints/setuid_test.go
index ded528ab..d576b8a0 100644
--- a/endpoints/setuid_test.go
+++ b/endpoints/setuid_test.go
@@ -575,7 +575,7 @@ func TestParseSignalFromGPPSID(t *testing.T) {
 func TestParseConsentFromGppStr(t *testing.T) {
 	type testOutput struct {
 		gdprConsent string
-		err         error
+		err         []error
 	}
 	testCases := []struct {
 		desc       string
@@ -595,7 +595,7 @@ func TestParseConsentFromGppStr(t *testing.T) {
 			inGppQuery: "malformed",
 			expected: testOutput{
 				gdprConsent: "",
-				err:         errors.New(`error parsing GPP header, base64 decoding: illegal base64 data at input byte 8`),
+				err:         []error{errors.New(`error parsing GPP header, header must have type=3`)},
 			},
 		},
 		{
@@ -619,7 +619,7 @@ func TestParseConsentFromGppStr(t *testing.T) {
 		outConsent, outErr := parseConsentFromGppStr(tc.inGppQuery)
 
 		assert.Equal(t, tc.expected.gdprConsent, outConsent, tc.desc)
-		assert.Equal(t, tc.expected.err, outErr, tc.desc)
+		assert.ElementsMatch(t, tc.expected.err, outErr, tc.desc)
 	}
 }
 
@@ -658,7 +658,7 @@ func TestParseGDPRFromGPP(t *testing.T) {
 					inUri: "/setuid?gpp=malformed",
 					expected: testOutput{
 						reqInfo: gdpr.RequestInfo{GDPRSignal: gdpr.SignalAmbiguous},
-						err:     errors.New("error parsing GPP header, base64 decoding: illegal base64 data at input byte 8"),
+						err:     errors.New("error parsing GPP header, header must have type=3"),
 					},
 				},
 				{
@@ -933,7 +933,7 @@ func TestExtractGDPRInfo(t *testing.T) {
 					inUri: "/setuid?gpp=malformed&gpp_sid=2",
 					expected: testOutput{
 						requestInfo: gdpr.RequestInfo{GDPRSignal: gdpr.SignalAmbiguous},
-						err:         errors.New("error parsing GPP header, base64 decoding: illegal base64 data at input byte 8"),
+						err:         errors.New("error parsing GPP header, header must have type=3"),
 					},
 				},
 				{
diff --git a/exchange/bidder_validate_bids_test.go b/exchange/bidder_validate_bids_test.go
index 805eba9a..a488bf81 100644
--- a/exchange/bidder_validate_bids_test.go
+++ b/exchange/bidder_validate_bids_test.go
@@ -130,10 +130,11 @@ func TestAllBadBids(t *testing.T) {
 	}
 	bidAdjustments := map[string]float64{string(openrtb_ext.BidderAppnexus): 1.0}
 	bidReqOptions := bidRequestOptions{
-		accountDebugAllowed: true,
-		headerDebugAllowed:  false,
-		addCallSignHeader:   false,
-		bidAdjustments:      bidAdjustments,
+		accountDebugAllowed:  true,
+		headerDebugAllowed:   false,
+		addCallSignHeader:    false,
+		bidAdjustments:       bidAdjustments,
+		responseDebugAllowed: true,
 	}
 	seatBids, _, errs := bidder.requestBid(context.Background(), bidderReq, currency.NewConstantRates(), &adapters.ExtraRequestInfo{}, &adscert.NilSigner{}, bidReqOptions, openrtb_ext.ExtAlternateBidderCodes{}, &hookexecution.EmptyHookExecutor{}, nil)
 	assert.Len(t, seatBids, 1)
@@ -211,15 +212,16 @@ func TestMixedBids(t *testing.T) {
 	}
 	bidAdjustments := map[string]float64{string(openrtb_ext.BidderAppnexus): 1.0}
 	bidReqOptions := bidRequestOptions{
-		accountDebugAllowed: true,
-		headerDebugAllowed:  false,
-		addCallSignHeader:   false,
-		bidAdjustments:      bidAdjustments,
+		accountDebugAllowed:  true,
+		headerDebugAllowed:   false,
+		addCallSignHeader:    false,
+		bidAdjustments:       bidAdjustments,
+		responseDebugAllowed: false,
 	}
 	seatBids, _, errs := bidder.requestBid(context.Background(), bidderReq, currency.NewConstantRates(), &adapters.ExtraRequestInfo{}, &adscert.NilSigner{}, bidReqOptions, openrtb_ext.ExtAlternateBidderCodes{}, &hookexecution.EmptyHookExecutor{}, nil)
 	assert.Len(t, seatBids, 1)
 	assert.Len(t, seatBids[0].Bids, 3)
-	assert.Len(t, errs, 5)
+	assert.Len(t, errs, 2)
 }
 
 func TestCurrencyBids(t *testing.T) {
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index fc7c7064..839c2f6b 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -5344,7 +5344,7 @@ func TestGetAllBids(t *testing.T) {
 
 			adapterBids, adapterExtra, extraRespInfo := e.getAllBids(context.Background(), test.in.bidderRequests, test.in.bidAdjustments,
 				test.in.conversions, test.in.accountDebugAllowed, test.in.globalPrivacyControlHeader, test.in.headerDebugAllowed, test.in.alternateBidderCodes, test.in.experiment,
-				test.in.hookExecutor, test.in.pbsRequestStartTime, test.in.bidAdjustmentRules, test.in.tmaxAdjustments)
+				test.in.hookExecutor, test.in.pbsRequestStartTime, test.in.bidAdjustmentRules, test.in.tmaxAdjustments, false)
 
 			assert.Equalf(t, test.expected.extraRespInfo.bidsFound, extraRespInfo.bidsFound, "extraRespInfo.bidsFound mismatch")
 			assert.Equalf(t, test.expected.adapterBids, adapterBids, "adapterBids mismatch")
diff --git a/exchange/gdpr_test.go b/exchange/gdpr_test.go
index e9b11cc2..c73112be 100644
--- a/exchange/gdpr_test.go
+++ b/exchange/gdpr_test.go
@@ -185,3 +185,7 @@ func (ms mockGPPSection) GetID() gppConstants.SectionID {
 func (ms mockGPPSection) GetValue() string {
 	return ms.value
 }
+
+func (ms mockGPPSection) Encode(bool) []byte {
+	return nil
+}
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index a6a7217d..0c8153b6 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -3685,6 +3685,10 @@ func (gs GPPMockSection) GetValue() string {
 	return gs.value
 }
 
+func (gs GPPMockSection) Encode(bool) []byte {
+	return nil
+}
+
 func TestGdprFromGPP(t *testing.T) {
 	testCases := []struct {
 		name            string
diff --git a/privacy/ccpa/policy_test.go b/privacy/ccpa/policy_test.go
index 0ea2b8cd..20d9f680 100644
--- a/privacy/ccpa/policy_test.go
+++ b/privacy/ccpa/policy_test.go
@@ -922,3 +922,7 @@ func (ms mockGPPSection) GetID() gppConstants.SectionID {
 func (ms mockGPPSection) GetValue() string {
 	return ms.value
 }
+
+func (ms mockGPPSection) Encode(bool) []byte {
+	return nil
+}