Repository: prebid/prebid-server
Pull request #1635 (2020-12-24 10:32:23)

MediaFuse adapter
Adding Mediafuse alias to Adtelligent adapter

Doc update: https://github.com/prebid/prebid.github.io/pull/2597


Test curl: 
`curl 'http://localhost:8000/openrtb2/auction' \
  -H 'Connection: keep-alive' \
  -H 'Pragma: no-cache' \
  -H 'Cache-Control: no-cache' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36' \
  -H 'Content-Type: text/plain' \
  -H 'Accept: */*' \
  -H 'Origin: http://localhost:63342' \
  -H 'Sec-Fetch-Site: same-site' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Referer: http://localhost:63342/' \
  --data-binary '{"id":"eff6682a-e801-4fdc-9de1-705e39f90863","source":{"tid":"eff6682a-e801-4fdc-9de1-705e39f90863"},"tmax":3000,"imp":[{"id":"div1","ext":{"mediafuse":{"aid":529317}},"banner":{"format":[{"w":300,"h":250}]}}],"test":1,"ext":{"prebid":{"auctiontimestamp":1608805985477,"targeting":{"includewinners":true,"includebidderkeys":false}}},"site":{"publisher":{"id":"111"},"page":"http://localhost:63342/prebid_latest/pbs.html?_ijt=hrmual57hmcfrjo2vmnarenjoc"},"device":{"w":508,"h":677}}' \
  --compressed`


Related PR: https://github.com/prebid/Prebid.js/pull/6150

GeneGenie: Interesting that userSyncer has no alias workarounds
SyntaxNode: > Interesting that userSyncer has no easy-going alias workarounds

... also interesting that the user syncer framework is code when it really could just be config. I've had it on my short list of things to refactor for a while now. Since this dovetails with https://github.com/prebid/prebid-server/issues/1554 and https://github.com/prebid/prebid-server/issues/1429, I'll get started on it soon.

I like that you're using the builders to create an alias. That is the intended end goal of that work. The remaining work to finish https://github.com/prebid/prebid-server/issues/1429 may very well eliminate the need for anything except config for aliases. If so, mind if I refactor this later on?
GeneGenie: Later refactoring is ok. 

Patch:
diff --git a/adapters/adot/adot.go b/adapters/adot/adot.go
new file mode 100644
index 00000000..c58c4a1e
--- /dev/null
+++ b/adapters/adot/adot.go
@@ -0,0 +1,117 @@
+package adot
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/mxmCherry/openrtb"
+	"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
+}
+
+type adotBidExt struct {
+	Adot bidExt `json:"adot"`
+}
+
+type bidExt struct {
+	MediaType string `json:"media_type"`
+}
+
+// Builder builds a new instance of the Adot adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+	return bidder, nil
+}
+
+// MakeRequests makes the HTTP requests which should be made to fetch bids.
+func (a *adapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	var reqJSON []byte
+	var err error
+
+	if reqJSON, err = json.Marshal(request); err != nil {
+		return nil, []error{fmt.Errorf("unable to marshal openrtb request (%v)", err)}
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+
+	return []*adapters.RequestData{{
+		Method:  "POST",
+		Uri:     a.endpoint,
+		Body:    reqJSON,
+		Headers: headers,
+	}}, nil
+}
+
+// MakeBids unpacks the server's response into Bids.
+// The bidder return a status code 204 when it cannot delivery an ad.
+func (a *adapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if response.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if response.StatusCode == http.StatusBadRequest {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}}
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}}
+	}
+
+	var bidResp openrtb.BidResponse
+	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
+		return nil, []error{err}
+	}
+
+	bidsCapacity := 1
+	if len(bidResp.SeatBid) > 0 {
+		bidsCapacity = len(bidResp.SeatBid[0].Bid)
+	}
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(bidsCapacity)
+
+	for _, sb := range bidResp.SeatBid {
+		for i := range sb.Bid {
+			if bidType, err := getMediaTypeForBid(&sb.Bid[i]); err == nil {
+				bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+					Bid:     &sb.Bid[i],
+					BidType: bidType,
+				})
+			}
+		}
+	}
+
+	return bidResponse, nil
+}
+
+// getMediaTypeForBid determines which type of bid.
+func getMediaTypeForBid(bid *openrtb.Bid) (openrtb_ext.BidType, error) {
+	if bid == nil {
+		return "", fmt.Errorf("the bid request object is nil")
+	}
+
+	var impExt adotBidExt
+	if err := json.Unmarshal(bid.Ext, &impExt); err == nil {
+		switch impExt.Adot.MediaType {
+		case string(openrtb_ext.BidTypeBanner):
+			return openrtb_ext.BidTypeBanner, nil
+		case string(openrtb_ext.BidTypeVideo):
+			return openrtb_ext.BidTypeVideo, nil
+		case string(openrtb_ext.BidTypeNative):
+			return openrtb_ext.BidTypeNative, nil
+		}
+	}
+
+	return "", fmt.Errorf("unrecognized bid type in response from adot")
+}
diff --git a/adapters/appnexus/appnexus.go b/adapters/appnexus/appnexus.go
index e6398b4a..0a8146fd 100644
--- a/adapters/appnexus/appnexus.go
+++ b/adapters/appnexus/appnexus.go
@@ -604,6 +604,9 @@ func (a *AppNexusAdapter) MakeBids(internalRequest *openrtb.BidRequest, external
 			}
 		}
 	}
+	if bidResp.Cur != "" {
+		bidResponse.Currency = bidResp.Cur
+	}
 	return bidResponse, errs
 }
 
diff --git a/adapters/ix/ix.go b/adapters/ix/ix.go
index 7052d5ac..96cd988d 100644
--- a/adapters/ix/ix.go
+++ b/adapters/ix/ix.go
@@ -8,26 +8,22 @@ import (
 	"io/ioutil"
 	"net/http"
 
-	"github.com/prebid/prebid-server/openrtb_ext"
-
-	"github.com/prebid/prebid-server/pbs"
-
 	"golang.org/x/net/context/ctxhttp"
 
 	"github.com/mxmCherry/openrtb"
 	"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"
+	"github.com/prebid/prebid-server/pbs"
 )
 
-// maximum number of bid requests
-const requestLimit = 20
-
 type IxAdapter struct {
-	http *adapters.HTTPAdapter
-	URI  string
+	http        *adapters.HTTPAdapter
+	URI         string
+	maxRequests int
 }
 
-// Name is used for cookies and such
 func (a *IxAdapter) Name() string {
 	return string(openrtb_ext.BidderIx)
 }
@@ -52,34 +48,21 @@ type callOneObject struct {
 	requestJSON bytes.Buffer
 	width       uint64
 	height      uint64
-}
-
-func isValidIXSize(f openrtb.Format, s [2]uint64) bool {
-	if f.W != s[0] || f.H != s[1] {
-		return false
-	}
-	return true
+	bidType     string
 }
 
 func (a *IxAdapter) Call(ctx context.Context, req *pbs.PBSRequest, bidder *pbs.PBSBidder) (pbs.PBSBidSlice, error) {
 	var prioritizedRequests, requests []callOneObject
 
-	if req.App != nil {
-		return nil, &errortypes.BadInput{
-			Message: "Index doesn't support apps",
-		}
-	}
-	mediaTypes := []pbs.MediaType{pbs.MEDIA_TYPE_BANNER}
+	mediaTypes := []pbs.MediaType{pbs.MEDIA_TYPE_BANNER, pbs.MEDIA_TYPE_VIDEO}
 	indexReq, err := adapters.MakeOpenRTBGeneric(req, bidder, a.Name(), mediaTypes)
-
 	if err != nil {
 		return nil, err
 	}
 
 	indexReqImp := indexReq.Imp
 	for i, unit := range bidder.AdUnits {
-
-		// Fixes some segfaults. Since this is legacy code, I'm not looking into it too deeply
+		// Supposedly fixes some segfaults
 		if len(indexReqImp) <= i {
 			break
 		}
@@ -99,29 +82,35 @@ func (a *IxAdapter) Call(ctx context.Context, req *pbs.PBSRequest, bidder *pbs.P
 		}
 
 		for sizeIndex, format := range unit.Sizes {
-			// Only grab this ad unit
-			// Not supporting multi-media-type adunit yet
+			// Only grab this ad unit. Not supporting multi-media-type adunit yet.
 			thisImp := indexReqImp[i]
 
 			thisImp.TagID = unit.Code
-			thisImp.Banner.Format = []openrtb.Format{format}
-			thisImp.Banner.W = &format.W
-			thisImp.Banner.H = &format.H
+			if thisImp.Banner != nil {
+				thisImp.Banner.Format = []openrtb.Format{format}
+				thisImp.Banner.W = &format.W
+				thisImp.Banner.H = &format.H
+			}
 			indexReq.Imp = []openrtb.Imp{thisImp}
 			// Index spec says "adunit path representing ad server inventory" but we don't have this
 			// ext is DFP div ID and KV pairs if avail
 			//indexReq.Imp[i].Ext = json.RawMessage("{}")
 
-			// Any objects pointed to by indexReq *must not be mutated*, or we will get race conditions.
-			siteCopy := *indexReq.Site
-			siteCopy.Publisher = &openrtb.Publisher{ID: params.SiteID}
-			indexReq.Site = &siteCopy
+			if indexReq.Site != nil {
+				// Any objects pointed to by indexReq *must not be mutated*, or we will get race conditions.
+				siteCopy := *indexReq.Site
+				siteCopy.Publisher = &openrtb.Publisher{ID: params.SiteID}
+				indexReq.Site = &siteCopy
+			}
 
-			// spec also asks for publisher id if set
-			// ext object on request for prefetch
+			bidType := ""
+			if thisImp.Banner != nil {
+				bidType = string(openrtb_ext.BidTypeBanner)
+			} else if thisImp.Video != nil {
+				bidType = string(openrtb_ext.BidTypeVideo)
+			}
 			j, _ := json.Marshal(indexReq)
-
-			request := callOneObject{requestJSON: *bytes.NewBuffer(j), width: format.W, height: format.H}
+			request := callOneObject{requestJSON: *bytes.NewBuffer(j), width: format.W, height: format.H, bidType: bidType}
 
 			// prioritize slots over sizes
 			if sizeIndex == 0 {
@@ -132,10 +121,10 @@ func (a *IxAdapter) Call(ctx context.Context, req *pbs.PBSRequest, bidder *pbs.P
 		}
 	}
 
-	// cap the number of requests to requestLimit
+	// cap the number of requests to maxRequests
 	requests = append(prioritizedRequests, requests...)
-	if len(requests) > requestLimit {
-		requests = requests[:requestLimit]
+	if len(requests) > a.maxRequests {
+		requests = requests[:a.maxRequests]
 	}
 
 	if len(requests) == 0 {
@@ -155,6 +144,7 @@ func (a *IxAdapter) Call(ctx context.Context, req *pbs.PBSRequest, bidder *pbs.P
 				result.Bid.BidID = bidder.LookupBidID(result.Bid.AdUnitCode)
 				result.Bid.Width = request.width
 				result.Bid.Height = request.height
+				result.Bid.CreativeMediaType = request.bidType
 
 				if result.Bid.BidID == "" {
 					result.Error = &errortypes.BadServerResponse{
@@ -247,23 +237,195 @@ func (a *IxAdapter) callOne(ctx context.Context, reqJSON bytes.Buffer) (ixBidRes
 	}
 	bid := bidResp.SeatBid[0].Bid[0]
 
-	result.Bid = &pbs.PBSBid{
-		AdUnitCode:        bid.ImpID,
-		Price:             bid.Price,
-		Adm:               bid.AdM,
-		Creative_id:       bid.CrID,
-		Width:             bid.W,
-		Height:            bid.H,
-		DealId:            bid.DealID,
-		CreativeMediaType: string(openrtb_ext.BidTypeBanner),
+	pbid := pbs.PBSBid{
+		AdUnitCode:  bid.ImpID,
+		Price:       bid.Price,
+		Adm:         bid.AdM,
+		Creative_id: bid.CrID,
+		Width:       bid.W,
+		Height:      bid.H,
+		DealId:      bid.DealID,
 	}
+
+	result.Bid = &pbid
 	return result, nil
 }
 
-func NewIxLegacyAdapter(config *adapters.HTTPAdapterConfig, uri string) *IxAdapter {
-	a := adapters.NewHTTPAdapter(config)
+func (a *IxAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	nImp := len(request.Imp)
+	if nImp > a.maxRequests {
+		request.Imp = request.Imp[:a.maxRequests]
+		nImp = a.maxRequests
+	}
+
+	// Multi-size banner imps are split into single-size requests.
+	// The first size imp requests are added to the first slice.
+	// Additional size requests are added to the second slice and are merged with the first at the end.
+	// Preallocate the max possible size to avoid reallocating arrays.
+	requests := make([]*adapters.RequestData, 0, a.maxRequests)
+	multiSizeRequests := make([]*adapters.RequestData, 0, a.maxRequests-nImp)
+	errs := make([]error, 0, 1)
+
+	headers := http.Header{
+		"Content-Type": {"application/json;charset=utf-8"},
+		"Accept":       {"application/json"}}
+
+	imps := request.Imp
+	for iImp := range imps {
+		request.Imp = imps[iImp : iImp+1]
+		if request.Site != nil {
+			if err := setSitePublisherId(request, iImp); err != nil {
+				errs = append(errs, err)
+				continue
+			}
+		}
+
+		if request.Imp[0].Banner != nil {
+			banner := *request.Imp[0].Banner
+			request.Imp[0].Banner = &banner
+			formats := getBannerFormats(&banner)
+			for iFmt := range formats {
+				banner.Format = formats[iFmt : iFmt+1]
+				banner.W = openrtb.Uint64Ptr(banner.Format[0].W)
+				banner.H = openrtb.Uint64Ptr(banner.Format[0].H)
+				if requestData, err := createRequestData(a, request, &headers); err == nil {
+					if iFmt == 0 {
+						requests = append(requests, requestData)
+					} else {
+						multiSizeRequests = append(multiSizeRequests, requestData)
+					}
+				} else {
+					errs = append(errs, err)
+				}
+				if len(multiSizeRequests) == cap(multiSizeRequests) {
+					break
+				}
+			}
+		} else if requestData, err := createRequestData(a, request, &headers); err == nil {
+			requests = append(requests, requestData)
+		} else {
+			errs = append(errs, err)
+		}
+	}
+	request.Imp = imps
+
+	return append(requests, multiSizeRequests...), errs
+}
+
+func setSitePublisherId(request *openrtb.BidRequest, iImp int) error {
+	if iImp == 0 {
+		// first impression - create a site and pub copy
+		site := *request.Site
+		if site.Publisher == nil {
+			site.Publisher = &openrtb.Publisher{}
+		} else {
+			publisher := *site.Publisher
+			site.Publisher = &publisher
+		}
+		request.Site = &site
+	}
+
+	var bidderExt adapters.ExtImpBidder
+	if err := json.Unmarshal(request.Imp[0].Ext, &bidderExt); err != nil {
+		return err
+	}
+
+	var ixExt openrtb_ext.ExtImpIx
+	if err := json.Unmarshal(bidderExt.Bidder, &ixExt); err != nil {
+		return err
+	}
+
+	request.Site.Publisher.ID = ixExt.SiteId
+	return nil
+}
+
+func getBannerFormats(banner *openrtb.Banner) []openrtb.Format {
+	if len(banner.Format) == 0 && banner.W != nil && banner.H != nil {
+		banner.Format = []openrtb.Format{{W: *banner.W, H: *banner.H}}
+	}
+	return banner.Format
+}
+
+func createRequestData(a *IxAdapter, request *openrtb.BidRequest, headers *http.Header) (*adapters.RequestData, error) {
+	body, err := json.Marshal(request)
+	return &adapters.RequestData{
+		Method:  "POST",
+		Uri:     a.URI,
+		Body:    body,
+		Headers: *headers,
+	}, err
+}
+
+func (a *IxAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	switch {
+	case response.StatusCode == http.StatusNoContent:
+		return nil, nil
+	case response.StatusCode == http.StatusBadRequest:
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}}
+	case response.StatusCode != http.StatusOK:
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}}
+	}
+
+	var bidResponse openrtb.BidResponse
+	if err := json.Unmarshal(response.Body, &bidResponse); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("JSON parsing error: %v", err),
+		}}
+	}
+
+	// Until the time we support multi-format ad units, we'll use a bid request impression media type
+	// as a bid response bid type. They are linked by the impression id.
+	impMediaType := map[string]openrtb_ext.BidType{}
+	for _, imp := range internalRequest.Imp {
+		if imp.Banner != nil {
+			impMediaType[imp.ID] = openrtb_ext.BidTypeBanner
+		} else if imp.Video != nil {
+			impMediaType[imp.ID] = openrtb_ext.BidTypeVideo
+		} else if imp.Native != nil {
+			impMediaType[imp.ID] = openrtb_ext.BidTypeNative
+		} else if imp.Audio != nil {
+			impMediaType[imp.ID] = openrtb_ext.BidTypeAudio
+		}
+	}
+
+	bidderResponse := adapters.NewBidderResponseWithBidsCapacity(5)
+	bidderResponse.Currency = bidResponse.Cur
+
+	var errs []error
+
+	for _, seatBid := range bidResponse.SeatBid {
+		for _, bid := range seatBid.Bid {
+			bidType, ok := impMediaType[bid.ImpID]
+			if !ok {
+				errs = append(errs, fmt.Errorf("Unmatched impression id: %s.", bid.ImpID))
+			}
+			bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
+				Bid:     &bid,
+				BidType: bidType,
+			})
+		}
+	}
+
+	return bidderResponse, errs
+}
+
+func NewIxLegacyAdapter(config *adapters.HTTPAdapterConfig, endpoint string) *IxAdapter {
 	return &IxAdapter{
-		http: a,
-		URI:  uri,
+		http:        adapters.NewHTTPAdapter(config),
+		URI:         endpoint,
+		maxRequests: 20,
+	}
+}
+
+// Builder builds a new instance of the Ix adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &IxAdapter{
+		URI:         config.Endpoint,
+		maxRequests: 20,
 	}
+	return bidder, nil
 }
diff --git a/adapters/mediafuse/usersync.go b/adapters/mediafuse/usersync.go
new file mode 100644
index 00000000..5381bf36
--- /dev/null
+++ b/adapters/mediafuse/usersync.go
@@ -0,0 +1,12 @@
+package mediafuse
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewMediafuseSyncer(temp *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("mediafuse", 411, temp, adapters.SyncTypeRedirect)
+}
diff --git a/adapters/mobfoxpb/mobfoxpb.go b/adapters/mobfoxpb/mobfoxpb.go
new file mode 100644
index 00000000..5369c082
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpb.go
@@ -0,0 +1,131 @@
+package mobfoxpb
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+
+	"github.com/buger/jsonparser"
+	"github.com/mxmCherry/openrtb"
+	"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"
+)
+
+type adapter struct {
+	URI string
+}
+
+// Builder builds a new instance of the Mobfox adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		URI: config.Endpoint,
+	}
+	return bidder, nil
+}
+
+// MakeRequests create bid request for mobfoxpb demand
+func (a *adapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	var errs []error
+	var err error
+	var tagID string
+
+	var adapterRequests []*adapters.RequestData
+
+	reqCopy := *request
+	imp := request.Imp[0]
+	tagID, err = jsonparser.GetString(imp.Ext, "bidder", "TagID")
+	if err != nil {
+		errs = append(errs, err)
+		return nil, errs
+	}
+	imp.TagID = tagID
+	reqCopy.Imp = []openrtb.Imp{imp}
+	adapterReq, err := a.makeRequest(&reqCopy)
+	if err != nil {
+		errs = append(errs, err)
+	}
+	if adapterReq != nil {
+		adapterRequests = append(adapterRequests, adapterReq)
+	}
+	return adapterRequests, errs
+}
+
+func (a *adapter) makeRequest(request *openrtb.BidRequest) (*adapters.RequestData, error) {
+	reqJSON, err := json.Marshal(request)
+
+	if err != nil {
+		return nil, err
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	return &adapters.RequestData{
+		Method:  "POST",
+		Uri:     a.URI,
+		Body:    reqJSON,
+		Headers: headers,
+	}, nil
+}
+
+// MakeBids makes the bids
+func (a *adapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	var errs []error
+
+	if response.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}}
+	}
+
+	var bidResp openrtb.BidResponse
+
+	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+
+	for _, sb := range bidResp.SeatBid {
+		for _, bid := range sb.Bid {
+			bidType, err := getMediaTypeForImp(bid.ImpID, internalRequest.Imp)
+			if err != nil {
+				errs = append(errs, err)
+			} else {
+				b := &adapters.TypedBid{
+					Bid:     &bid,
+					BidType: bidType,
+				}
+				bidResponse.Bids = append(bidResponse.Bids, b)
+			}
+		}
+	}
+	return bidResponse, errs
+}
+
+func getMediaTypeForImp(impID string, imps []openrtb.Imp) (openrtb_ext.BidType, error) {
+	mediaType := openrtb_ext.BidTypeBanner
+	for _, imp := range imps {
+		if imp.ID == impID {
+			if imp.Banner != nil {
+				mediaType = openrtb_ext.BidTypeBanner
+			} else if imp.Video != nil {
+				mediaType = openrtb_ext.BidTypeVideo
+			} else if imp.Native != nil {
+				mediaType = openrtb_ext.BidTypeNative
+			}
+			return mediaType, nil
+		}
+	}
+
+	// This shouldnt happen. Lets handle it just incase by returning an error.
+	return "", &errortypes.BadServerResponse{
+		Message: fmt.Sprintf("Failed to find impression \"%s\" ", impID),
+	}
+}
diff --git a/amp/parse.go b/amp/parse.go
new file mode 100644
index 00000000..9e0e019f
--- /dev/null
+++ b/amp/parse.go
@@ -0,0 +1,110 @@
+package amp
+
+import (
+	"errors"
+	"net/http"
+	"strconv"
+	"strings"
+
+	"github.com/mxmCherry/openrtb"
+)
+
+// Params defines the paramters of an AMP request.
+type Params struct {
+	Account         string
+	CanonicalURL    string
+	Consent         string
+	Debug           bool
+	Origin          string
+	Size            Size
+	Slot            string
+	StoredRequestID string
+	Timeout         *uint64
+}
+
+// Size defines size information of an AMP request.
+type Size struct {
+	Height         uint64
+	Multisize      []openrtb.Format
+	OverrideHeight uint64
+	OverrideWidth  uint64
+	Width          uint64
+}
+
+// ParseParams parses the AMP paramters from a HTTP request.
+func ParseParams(httpRequest *http.Request) (Params, error) {
+	query := httpRequest.URL.Query()
+
+	tagID := query.Get("tag_id")
+	if len(tagID) == 0 {
+		return Params{}, errors.New("AMP requests require an AMP tag_id")
+	}
+
+	params := Params{
+		Account:      query.Get("account"),
+		CanonicalURL: query.Get("curl"),
+		Consent:      chooseConsent(query.Get("consent_string"), query.Get("gdpr_consent")),
+		Debug:        query.Get("debug") == "1",
+		Origin:       query.Get("__amp_source_origin"),
+		Size: Size{
+			Height:         parseInt(query.Get("h")),
+			Multisize:      parseMultisize(query.Get("ms")),
+			OverrideHeight: parseInt(query.Get("oh")),
+			OverrideWidth:  parseInt(query.Get("ow")),
+			Width:          parseInt(query.Get("w")),
+		},
+		Slot:            query.Get("slot"),
+		StoredRequestID: tagID,
+		Timeout:         parseIntPtr(query.Get("timeout")),
+	}
+	return params, nil
+}
+
+func parseIntPtr(value string) *uint64 {
+	if parsed, err := strconv.ParseUint(value, 10, 64); err == nil {
+		return &parsed
+	}
+	return nil
+}
+
+func parseInt(value string) uint64 {
+	if parsed, err := strconv.ParseUint(value, 10, 64); err == nil {
+		return parsed
+	}
+	return 0
+}
+
+func parseMultisize(multisize string) []openrtb.Format {
+	if multisize == "" {
+		return nil
+	}
+
+	sizeStrings := strings.Split(multisize, ",")
+	sizes := make([]openrtb.Format, 0, len(sizeStrings))
+	for _, sizeString := range sizeStrings {
+		wh := strings.Split(sizeString, "x")
+		if len(wh) != 2 {
+			return nil
+		}
+		f := openrtb.Format{
+			W: parseInt(wh[0]),
+			H: parseInt(wh[1]),
+		}
+		if f.W == 0 && f.H == 0 {
+			return nil
+		}
+
+		sizes = append(sizes, f)
+	}
+	return sizes
+}
+
+func chooseConsent(consent, gdprConsent string) string {
+	if len(consent) > 0 {
+		return consent
+	}
+
+	// Fallback to 'gdpr_consent' for compatability until it's no longer used. This was our original
+	// implementation before the same AMP macro was reused for CCPA.
+	return gdprConsent
+}
diff --git a/config/config.go b/config/config.go
index db9adf4f..ed3c6e96 100755
--- a/config/config.go
+++ b/config/config.go
@@ -214,7 +214,7 @@ func (cfg *GDPR) validate(errs []error) []error {
 		glog.Warning("gdpr.host_vendor_id was not specified. Host company GDPR checks will be skipped.")
 	}
 	if cfg.AMPException == true {
-		glog.Warning("gdpr.amp_exception is deprecated and will be removed in a future version. If you need to disable GDPR for AMP, you may do so per-account (gdpr.integration_enabled.amp) or at the host level for the default account (account_defaults.gdpr.integration_enabled.amp).")
+		errs = append(errs, fmt.Errorf("gdpr.amp_exception has been discontinued and must be removed from your config. If you need to disable GDPR for AMP, you may do so per-account (gdpr.integration_enabled.amp) or at the host level for the default account (account_defaults.gdpr.integration_enabled.amp)"))
 	}
 	return errs
 }
@@ -606,6 +606,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderLogicad, "https://cr-p31.ladsp.jp/cookiesender/31?r=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ru="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dlogicad%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderLunaMedia, "https://api.lunamedia.io/xp/user-sync?redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dlunamedia%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderMarsmedia, "https://dmp.rtbsrv.com/dmp/profiles/cm?p_id=179&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dmarsmedia%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUUID%7D")
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderMediafuse, "https://sync.hbmp.mediafuse.com/csync?t=p&ep=0&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dmediafuse%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7Buid%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderMgid, "https://cm.mgid.com/m?cdsp=363893&adu="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dmgid%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7Bmuidn%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderNanoInteractive, "https://ad.audiencemanager.de/hbs/cookie_sync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirectUri="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dnanointeractive%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderNinthDecimal, "https://rtb.ninthdecimal.com/xp/user-sync?acctid={aid}&&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dninthdecimal%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
@@ -799,6 +800,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.admixer.endpoint", "http://inv-nets.admixer.net/pbs.aspx")
 	v.SetDefault("adapters.adocean.endpoint", "https://{{.Host}}")
 	v.SetDefault("adapters.adoppler.endpoint", "http://{{.AccountID}}.trustedmarketplace.io/ads/processHeaderBid/{{.AdUnit}}")
+	v.SetDefault("adapters.adot.endpoint", "https://dsp.adotmob.com/headerbidding/bidrequest")
 	v.SetDefault("adapters.adpone.endpoint", "http://rtb.adpone.com/bid-request?src=prebid_server")
 	v.SetDefault("adapters.adprime.endpoint", "http://delta.adprime.com/?c=o&m=ortb")
 	v.SetDefault("adapters.adtarget.endpoint", "http://ghb.console.adtarget.com.tr/pbs/ortb")
@@ -834,7 +836,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.gumgum.endpoint", "https://g2.gumgum.com/providers/prbds2s/bid")
 	v.SetDefault("adapters.improvedigital.endpoint", "http://ad.360yield.com/pbs")
 	v.SetDefault("adapters.inmobi.endpoint", "https://api.w.inmobi.com/showad/openrtb/bidder/prebid")
-	v.SetDefault("adapters.ix.endpoint", "http://appnexus-us-east.lb.indexww.com/transbidder?p=184932")
+	v.SetDefault("adapters.ix.endpoint", "http://exchange.indexww.com/pbs?p=192919")
 	v.SetDefault("adapters.krushmedia.endpoint", "http://ads4.krushmedia.com/?c=rtb&m=req&key={{.AccountID}}")
 	v.SetDefault("adapters.invibes.endpoint", "https://{{.Host}}/bid/ServerBidAdContent")
 	v.SetDefault("adapters.kidoz.endpoint", "http://prebid-adapter.kidoz.net/openrtb2/auction?src=prebid-server")
@@ -844,8 +846,10 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.logicad.endpoint", "https://pbs.ladsp.com/adrequest/prebidserver")
 	v.SetDefault("adapters.lunamedia.endpoint", "http://api.lunamedia.io/xp/get?pubid={{.PublisherID}}")
 	v.SetDefault("adapters.marsmedia.endpoint", "https://bid306.rtbsrv.com/bidder/?bid=f3xtet")
+	v.SetDefault("adapters.mediafuse.endpoint", "http://ghb.hbmp.mediafuse.com/pbs/ortb")
 	v.SetDefault("adapters.mgid.endpoint", "https://prebid.mgid.com/prebid/")
 	v.SetDefault("adapters.mobilefuse.endpoint", "http://mfx.mobilefuse.com/openrtb?pub_id={{.PublisherID}}")
+	v.SetDefault("adapters.mobfoxpb.endpoint", "http://bes.mobfox.com/?c=o&m=ortb")
 	v.SetDefault("adapters.nanointeractive.endpoint", "https://ad.audiencemanager.de/hbs")
 	v.SetDefault("adapters.ninthdecimal.endpoint", "http://rtb.ninthdecimal.com/xp/get?pubid={{.PublisherID}}")
 	v.SetDefault("adapters.nobid.endpoint", "https://ads.servenobid.com/ortb_adreq?tek=pbs&ver=1")
@@ -873,7 +877,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	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")
-	v.SetDefault("adapters.ucfunnel.endpoint", "http://pbs.aralego.com/prebid")
+	v.SetDefault("adapters.ucfunnel.endpoint", "https://pbs.aralego.com/prebid")
 	v.SetDefault("adapters.unruly.endpoint", "http://targeting.unrulymedia.com/openrtb/2.2")
 	v.SetDefault("adapters.valueimpression.endpoint", "https://rtb.valueimpression.com/endpoint")
 	v.SetDefault("adapters.verizonmedia.disabled", true)
diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go
index afc32e5e..dc66163a 100644
--- a/endpoints/openrtb2/amp_auction.go
+++ b/endpoints/openrtb2/amp_auction.go
@@ -8,7 +8,6 @@ import (
 	"fmt"
 	"net/http"
 	"net/url"
-	"strconv"
 	"strings"
 	"time"
 
@@ -17,6 +16,7 @@ import (
 	"github.com/julienschmidt/httprouter"
 	"github.com/mxmCherry/openrtb"
 	accountService "github.com/prebid/prebid-server/account"
+	"github.com/prebid/prebid-server/amp"
 	"github.com/prebid/prebid-server/analytics"
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/errortypes"
@@ -314,43 +314,41 @@ func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request) (req
 	req = &openrtb.BidRequest{}
 	errs = nil
 
-	ampID := httpRequest.FormValue("tag_id")
-	if ampID == "" {
-		errs = []error{errors.New("AMP requests require an AMP tag_id")}
-		return
+	ampParams, err := amp.ParseParams(httpRequest)
+	if err != nil {
+		return nil, []error{err}
 	}
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(storedRequestTimeoutMillis)*time.Millisecond)
 	defer cancel()
 
-	storedRequests, _, errs := deps.storedReqFetcher.FetchRequests(ctx, []string{ampID}, nil)
+	storedRequests, _, errs := deps.storedReqFetcher.FetchRequests(ctx, []string{ampParams.StoredRequestID}, nil)
 	if len(errs) > 0 {
 		return nil, errs
 	}
 	if len(storedRequests) == 0 {
-		errs = []error{fmt.Errorf("No AMP config found for tag_id '%s'", ampID)}
+		errs = []error{fmt.Errorf("No AMP config found for tag_id '%s'", ampParams.StoredRequestID)}
 		return
 	}
 
 	// The fetched config becomes the entire OpenRTB request
-	requestJSON := storedRequests[ampID]
+	requestJSON := storedRequests[ampParams.StoredRequestID]
 	if err := json.Unmarshal(requestJSON, req); err != nil {
 		errs = []error{err}
 		return
 	}
 
-	debugParam := httpRequest.FormValue("debug")
-	if debugParam == "1" {
+	if ampParams.Debug {
 		req.Test = 1
 	}
 
 	// Two checks so users know which way the Imp check failed.
 	if len(req.Imp) == 0 {
-		errs = []error{fmt.Errorf("data for tag_id='%s' does not define the required imp array", ampID)}
+		errs = []error{fmt.Errorf("data for tag_id='%s' does not define the required imp array", ampParams.StoredRequestID)}
 		return
 	}
 	if len(req.Imp) > 1 {
-		errs = []error{fmt.Errorf("data for tag_id '%s' includes %d imp elements. Only one is allowed", ampID, len(req.Imp))}
+		errs = []error{fmt.Errorf("data for tag_id '%s' includes %d imp elements. Only one is allowed", ampParams.StoredRequestID, len(req.Imp))}
 		return
 	}
 
@@ -367,35 +365,30 @@ func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request) (req
 		*req.Imp[0].Secure = 1
 	}
 
-	errs = deps.overrideWithParams(httpRequest, req)
+	errs = deps.overrideWithParams(ampParams, req)
 	return
 }
 
-func (deps *endpointDeps) overrideWithParams(httpRequest *http.Request, req *openrtb.BidRequest) []error {
+func (deps *endpointDeps) overrideWithParams(ampParams amp.Params, req *openrtb.BidRequest) []error {
 	if req.Site == nil {
 		req.Site = &openrtb.Site{}
 	}
 
 	// Override the stored request sizes with AMP ones, if they exist.
 	if req.Imp[0].Banner != nil {
-		width := parseFormInt(httpRequest, "w", 0)
-		height := parseFormInt(httpRequest, "h", 0)
-		overrideWidth := parseFormInt(httpRequest, "ow", 0)
-		overrideHeight := parseFormInt(httpRequest, "oh", 0)
-		if format := makeFormatReplacement(overrideWidth, overrideHeight, width, height, httpRequest.FormValue("ms")); len(format) != 0 {
+		if format := makeFormatReplacement(ampParams.Size); len(format) != 0 {
 			req.Imp[0].Banner.Format = format
-		} else if width != 0 {
-			setWidths(req.Imp[0].Banner.Format, width)
-		} else if height != 0 {
-			setHeights(req.Imp[0].Banner.Format, height)
+		} else if ampParams.Size.Width != 0 {
+			setWidths(req.Imp[0].Banner.Format, ampParams.Size.Width)
+		} else if ampParams.Size.Height != 0 {
+			setHeights(req.Imp[0].Banner.Format, ampParams.Size.Height)
 		}
 	}
 
-	canonicalURL := httpRequest.FormValue("curl")
-	if canonicalURL != "" {
-		req.Site.Page = canonicalURL
+	if ampParams.CanonicalURL != "" {
+		req.Site.Page = ampParams.CanonicalURL
 		// Fixes #683
-		if parsedURL, err := url.Parse(canonicalURL); err == nil {
+		if parsedURL, err := url.Parse(ampParams.CanonicalURL); err == nil {
 			domain := parsedURL.Host
 			if colonIndex := strings.LastIndex(domain, ":"); colonIndex != -1 {
 				domain = domain[:colonIndex]
@@ -406,14 +399,13 @@ func (deps *endpointDeps) overrideWithParams(httpRequest *http.Request, req *ope
 
 	setAmpExt(req.Site, "1")
 
-	setEffectiveAmpPubID(req, httpRequest.URL.Query())
+	setEffectiveAmpPubID(req, ampParams.Account)
 
-	slot := httpRequest.FormValue("slot")
-	if slot != "" {
-		req.Imp[0].TagID = slot
+	if ampParams.Slot != "" {
+		req.Imp[0].TagID = ampParams.Slot
 	}
 
-	policyWriter, policyWriterErr := readPolicyFromUrl(httpRequest.URL)
+	policyWriter, policyWriterErr := readPolicy(ampParams.Consent)
 	if policyWriterErr != nil {
 		return []error{policyWriterErr}
 	}
@@ -421,42 +413,38 @@ func (deps *endpointDeps) overrideWithParams(httpRequest *http.Request, req *ope
 		return []error{err}
 	}
 
-	if timeout, err := strconv.ParseInt(httpRequest.FormValue("timeout"), 10, 64); err == nil {
-		req.TMax = timeout - deps.cfg.AMPTimeoutAdjustment
+	if ampParams.Timeout != nil {
+		req.TMax = int64(*ampParams.Timeout) - deps.cfg.AMPTimeoutAdjustment
 	}
 
 	return nil
 }
 
-func makeFormatReplacement(overrideWidth uint64, overrideHeight uint64, width uint64, height uint64, multisize string) []openrtb.Format {
+func makeFormatReplacement(size amp.Size) []openrtb.Format {
 	var formats []openrtb.Format
-	if overrideWidth != 0 && overrideHeight != 0 {
+	if size.OverrideWidth != 0 && size.OverrideHeight != 0 {
 		formats = []openrtb.Format{{
-			W: overrideWidth,
-			H: overrideHeight,
+			W: size.OverrideWidth,
+			H: size.OverrideHeight,
 		}}
-	} else if overrideWidth != 0 && height != 0 {
+	} else if size.OverrideWidth != 0 && size.Height != 0 {
 		formats = []openrtb.Format{{
-			W: overrideWidth,
-			H: height,
+			W: size.OverrideWidth,
+			H: size.Height,
 		}}
-	} else if width != 0 && overrideHeight != 0 {
+	} else if size.Width != 0 && size.OverrideHeight != 0 {
 		formats = []openrtb.Format{{
-			W: width,
-			H: overrideHeight,
+			W: size.Width,
+			H: size.OverrideHeight,
 		}}
-	} else if width != 0 && height != 0 {
+	} else if size.Width != 0 && size.Height != 0 {
 		formats = []openrtb.Format{{
-			W: width,
-			H: height,
+			W: size.Width,
+			H: size.Height,
 		}}
 	}
 
-	if parsedSizes := parseMultisize(multisize); len(parsedSizes) != 0 {
-		formats = append(formats, parsedSizes...)
-	}
-
-	return formats
+	return append(formats, size.Multisize...)
 }
 
 func setWidths(formats []openrtb.Format, width uint64) {
@@ -471,42 +459,6 @@ func setHeights(formats []openrtb.Format, height uint64) {
 	}
 }
 
-func parseMultisize(multisize string) []openrtb.Format {
-	if multisize == "" {
-		return nil
-	}
-
-	sizeStrings := strings.Split(multisize, ",")
-	sizes := make([]openrtb.Format, 0, len(sizeStrings))
-	for _, sizeString := range sizeStrings {
-		wh := strings.Split(sizeString, "x")
-		if len(wh) != 2 {
-			return nil
-		}
-		f := openrtb.Format{
-			W: parseIntErrorless(wh[0], 0),
-			H: parseIntErrorless(wh[1], 0),
-		}
-		if f.W == 0 && f.H == 0 {
-			return nil
-		}
-
-		sizes = append(sizes, f)
-	}
-	return sizes
-}
-
-func parseFormInt(req *http.Request, value string, defaultTo uint64) uint64 {
-	return parseIntErrorless(req.FormValue(value), defaultTo)
-}
-
-func parseIntErrorless(value string, defaultTo uint64) uint64 {
-	if parsed, err := strconv.ParseUint(value, 10, 64); err == nil {
-		return parsed
-	}
-	return defaultTo
-}
-
 // AMP won't function unless ext.prebid.targeting and ext.prebid.cache.bids are defined.
 // If the user didn't include them, default those here.
 func defaultRequestExt(req *openrtb.BidRequest) (errs []error) {
@@ -563,9 +515,7 @@ func setAmpExt(site *openrtb.Site, value string) {
 	}
 }
 
-func readPolicyFromUrl(url *url.URL) (privacy.PolicyWriter, error) {
-	consent := readConsentFromURL(url)
-
+func readPolicy(consent string) (privacy.PolicyWriter, error) {
 	if len(consent) == 0 {
 		return privacy.NilPolicyWriter{}, nil
 	}
@@ -583,17 +533,8 @@ func readPolicyFromUrl(url *url.URL) (privacy.PolicyWriter, error) {
 	}
 }
 
-func readConsentFromURL(url *url.URL) string {
-	if v := url.Query().Get("consent_string"); v != "" {
-		return v
-	}
-
-	// Fallback to 'gdpr_consent' for compatability until it's no longer used by AMP.
-	return url.Query().Get("gdpr_consent")
-}
-
 // Sets the effective publisher ID for amp request
-func setEffectiveAmpPubID(req *openrtb.BidRequest, urlQueryParams url.Values) {
+func setEffectiveAmpPubID(req *openrtb.BidRequest, account string) {
 	var pub *openrtb.Publisher
 	if req.App != nil {
 		if req.App.Publisher == nil {
@@ -608,10 +549,9 @@ func setEffectiveAmpPubID(req *openrtb.BidRequest, urlQueryParams url.Values) {
 	}
 
 	if pub.ID == "" {
-		// For amp requests, the publisher ID could be sent via the account
-		// query string
-		if acc := urlQueryParams.Get("account"); acc != "" && acc != "ACCOUNT_ID" {
-			pub.ID = acc
+		// ACCOUNT_ID is the unresolved macro name and should be ignored.
+		if account != "" && account != "ACCOUNT_ID" {
+			pub.ID = account
 		}
 	}
 }
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 2d73b823..5e950381 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -13,6 +13,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/admixer"
 	"github.com/prebid/prebid-server/adapters/adocean"
 	"github.com/prebid/prebid-server/adapters/adoppler"
+	"github.com/prebid/prebid-server/adapters/adot"
 	"github.com/prebid/prebid-server/adapters/adpone"
 	"github.com/prebid/prebid-server/adapters/adprime"
 	"github.com/prebid/prebid-server/adapters/adtarget"
@@ -46,6 +47,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/improvedigital"
 	"github.com/prebid/prebid-server/adapters/inmobi"
 	"github.com/prebid/prebid-server/adapters/invibes"
+	"github.com/prebid/prebid-server/adapters/ix"
 	"github.com/prebid/prebid-server/adapters/kidoz"
 	"github.com/prebid/prebid-server/adapters/krushmedia"
 	"github.com/prebid/prebid-server/adapters/kubient"
@@ -54,6 +56,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/lunamedia"
 	"github.com/prebid/prebid-server/adapters/marsmedia"
 	"github.com/prebid/prebid-server/adapters/mgid"
+	"github.com/prebid/prebid-server/adapters/mobfoxpb"
 	"github.com/prebid/prebid-server/adapters/mobilefuse"
 	"github.com/prebid/prebid-server/adapters/nanointeractive"
 	"github.com/prebid/prebid-server/adapters/ninthdecimal"
@@ -110,6 +113,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderAdOcean:          adocean.Builder,
 		openrtb_ext.BidderAdoppler:         adoppler.Builder,
 		openrtb_ext.BidderAdpone:           adpone.Builder,
+		openrtb_ext.BidderAdot:             adot.Builder,
 		openrtb_ext.BidderAdprime:          adprime.Builder,
 		openrtb_ext.BidderAdtarget:         adtarget.Builder,
 		openrtb_ext.BidderAdtelligent:      adtelligent.Builder,
@@ -142,6 +146,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderImprovedigital:   improvedigital.Builder,
 		openrtb_ext.BidderInMobi:           inmobi.Builder,
 		openrtb_ext.BidderInvibes:          invibes.Builder,
+		openrtb_ext.BidderIx:               ix.Builder,
 		openrtb_ext.BidderKidoz:            kidoz.Builder,
 		openrtb_ext.BidderKrushmedia:       krushmedia.Builder,
 		openrtb_ext.BidderKubient:          kubient.Builder,
@@ -149,7 +154,9 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderLogicad:          logicad.Builder,
 		openrtb_ext.BidderLunaMedia:        lunamedia.Builder,
 		openrtb_ext.BidderMarsmedia:        marsmedia.Builder,
+		openrtb_ext.BidderMediafuse:        adtelligent.Builder,
 		openrtb_ext.BidderMgid:             mgid.Builder,
+		openrtb_ext.BidderMobfoxpb:         mobfoxpb.Builder,
 		openrtb_ext.BidderMobileFuse:       mobilefuse.Builder,
 		openrtb_ext.BidderNanoInteractive:  nanointeractive.Builder,
 		openrtb_ext.BidderNinthDecimal:     ninthdecimal.Builder,
diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go
index f361508e..6e12ed00 100644
--- a/exchange/adapter_util.go
+++ b/exchange/adapter_util.go
@@ -7,7 +7,6 @@ import (
 	"github.com/prebid/prebid-server/metrics"
 
 	"github.com/prebid/prebid-server/adapters"
-	"github.com/prebid/prebid-server/adapters/ix"
 	"github.com/prebid/prebid-server/adapters/lifestreet"
 	"github.com/prebid/prebid-server/adapters/pulsepoint"
 	"github.com/prebid/prebid-server/config"
@@ -59,7 +58,7 @@ func buildBidders(adapterConfig map[string]config.Adapter, infos adapters.Bidder
 		}
 
 		// Ignore Legacy Bidders
-		if bidderName == openrtb_ext.BidderIx || bidderName == openrtb_ext.BidderLifestreet || bidderName == openrtb_ext.BidderPulsepoint {
+		if bidderName == openrtb_ext.BidderLifestreet || bidderName == openrtb_ext.BidderPulsepoint {
 			continue
 		}
 
@@ -92,13 +91,7 @@ func buildBidders(adapterConfig map[string]config.Adapter, infos adapters.Bidder
 }
 
 func buildExchangeBiddersLegacy(adapterConfig map[string]config.Adapter, infos adapters.BidderInfos) map[openrtb_ext.BidderName]adaptedBidder {
-	bidders := make(map[openrtb_ext.BidderName]adaptedBidder, 3)
-
-	// Index
-	if infos[string(openrtb_ext.BidderIx)].Status == adapters.StatusActive {
-		adapter := ix.NewIxLegacyAdapter(adapters.DefaultHTTPAdapterConfig, adapterConfig[string(openrtb_ext.BidderIx)].Endpoint)
-		bidders[openrtb_ext.BidderIx] = adaptLegacyAdapter(adapter)
-	}
+	bidders := make(map[openrtb_ext.BidderName]adaptedBidder, 2)
 
 	// Lifestreet
 	if infos[string(openrtb_ext.BidderLifestreet)].Status == adapters.StatusActive {
diff --git a/exchange/gdpr.go b/exchange/gdpr.go
index 2e2343d6..f464cac2 100644
--- a/exchange/gdpr.go
+++ b/exchange/gdpr.go
@@ -4,25 +4,21 @@ import (
 	"encoding/json"
 
 	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/gdpr"
 )
 
 // ExtractGDPR will pull the gdpr flag from an openrtb request
-func extractGDPR(bidRequest *openrtb.BidRequest, usersyncIfAmbiguous bool) (gdpr int) {
+func extractGDPR(bidRequest *openrtb.BidRequest) gdpr.Signal {
 	var re regsExt
 	var err error
 	if bidRequest.Regs != nil {
 		err = json.Unmarshal(bidRequest.Regs.Ext, &re)
 	}
 	if re.GDPR == nil || err != nil {
-		if usersyncIfAmbiguous {
-			gdpr = 0
-		} else {
-			gdpr = 1
-		}
+		return gdpr.SignalAmbiguous
 	} else {
-		gdpr = *re.GDPR
+		return gdpr.Signal(*re.GDPR)
 	}
-	return
 }
 
 // ExtractConsent will pull the consent string from an openrtb request
diff --git a/exchange/utils.go b/exchange/utils.go
index d70829ff..d574c2a6 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -75,9 +75,9 @@ func cleanOpenRTBRequests(ctx context.Context,
 		return
 	}
 
-	gdpr := extractGDPR(req.BidRequest, usersyncIfAmbiguous)
+	gdprSignal := extractGDPR(req.BidRequest)
 	consent := extractConsent(req.BidRequest)
-	ampGDPRException := (req.LegacyLabels.RType == metrics.ReqTypeAMP) && gDPR.AMPException()
+	gdprEnforced := gdprSignal == gdpr.SignalYes || (gdprSignal == gdpr.SignalAmbiguous && !usersyncIfAmbiguous)
 
 	ccpaEnforcer, err := extractCCPA(req.BidRequest, privacyConfig, &req.Account, aliases, integrationTypeMap[req.LegacyLabels.RType])
 	if err != nil {
@@ -98,9 +98,9 @@ func cleanOpenRTBRequests(ctx context.Context,
 	privacyLabels.COPPAEnforced = privacyEnforcement.COPPA
 	privacyLabels.LMTEnforced = lmtEnforcer.ShouldEnforce(unknownBidder)
 
-	gdprEnabled := gdprEnabled(&req.Account, privacyConfig, integrationTypeMap[req.LegacyLabels.RType])
+	gdprEnforced = gdprEnforced && gdprEnabled(&req.Account, privacyConfig, integrationTypeMap[req.LegacyLabels.RType])
 
-	if gdpr == 1 && gdprEnabled {
+	if gdprEnforced {
 		privacyLabels.GDPREnforced = true
 		parsedConsent, err := vendorconsent.ParseString(consent)
 		if err == nil {
@@ -115,17 +115,19 @@ func cleanOpenRTBRequests(ctx context.Context,
 		privacyEnforcement.CCPA = ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String())
 
 		// GDPR
-		if gdpr == 1 && gdprEnabled {
+		if gdprEnforced {
 			var publisherID = req.LegacyLabels.PubID
-			_, geo, id, err := gDPR.PersonalInfoAllowed(ctx, bidderRequest.BidderCoreName, publisherID, consent)
-			privacyEnforcement.GDPRGeo = !geo && err == nil
-			privacyEnforcement.GDPRID = !id && err == nil
-		} else {
-			privacyEnforcement.GDPRGeo = false
-			privacyEnforcement.GDPRID = false
+			_, geo, id, err := gDPR.PersonalInfoAllowed(ctx, bidderRequest.BidderCoreName, publisherID, gdprSignal, consent)
+			if err == nil {
+				privacyEnforcement.GDPRGeo = !geo
+				privacyEnforcement.GDPRID = !id
+			} else {
+				privacyEnforcement.GDPRGeo = true
+				privacyEnforcement.GDPRID = true
+			}
 		}
 
-		privacyEnforcement.Apply(bidderRequest.BidRequest, ampGDPRException)
+		privacyEnforcement.Apply(bidderRequest.BidRequest)
 	}
 
 	return
diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go
index 6d447beb..eea7fa5a 100644
--- a/gdpr/gdpr.go
+++ b/gdpr/gdpr.go
@@ -23,10 +23,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.
-	PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, bool, bool, error)
-
-	// Exposes the AMP execption flag
-	AMPException() bool
+	PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string) (bool, bool, bool, error)
 }
 
 // Versions of the GDPR TCF technical specification.
diff --git a/gdpr/impl.go b/gdpr/impl.go
index 2fbd9c5a..e1822ece 100644
--- a/gdpr/impl.go
+++ b/gdpr/impl.go
@@ -19,6 +19,14 @@ import (
 //
 // Nothing in this file is exported. Public APIs can be found in gdpr.go
 
+type Signal int
+
+const (
+	SignalAmbiguous Signal = -1
+	SignalNo        Signal = 0
+	SignalYes       Signal = 1
+)
+
 type permissionsImpl struct {
 	cfg             config.GDPR
 	vendorIDs       map[openrtb_ext.BidderName]uint16
@@ -42,26 +50,36 @@ func (p *permissionsImpl) BidderSyncAllowed(ctx context.Context, bidder openrtb_
 	return false, nil
 }
 
-func (p *permissionsImpl) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, bool, bool, error) {
-	_, ok := p.cfg.NonStandardPublisherMap[PublisherID]
-	if ok {
+func (p *permissionsImpl) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string) (allowPI bool, allowGeo bool, allowID bool, err error) {
+	if _, ok := p.cfg.NonStandardPublisherMap[PublisherID]; ok {
 		return true, true, true, nil
 	}
 
-	id, ok := p.vendorIDs[bidder]
-	if ok {
-		return p.allowPI(ctx, id, consent)
+	if gdprSignal == SignalAmbiguous {
+		if p.cfg.UsersyncIfAmbiguous {
+			gdprSignal = SignalNo
+		} else {
+			gdprSignal = SignalYes
+		}
 	}
 
-	if consent == "" {
-		return p.cfg.UsersyncIfAmbiguous, p.cfg.UsersyncIfAmbiguous, p.cfg.UsersyncIfAmbiguous, nil
+	if gdprSignal == SignalNo {
+		return true, true, true, nil
 	}
 
-	return false, false, false, nil
+	if consent == "" && gdprSignal == SignalYes {
+		return false, false, false, nil
+	}
+
+	if id, ok := p.vendorIDs[bidder]; ok {
+		return p.allowPI(ctx, id, consent)
+	}
+
+	return p.defaultVendorPermissions()
 }
 
-func (p *permissionsImpl) AMPException() bool {
-	return p.cfg.AMPException
+func (p *permissionsImpl) defaultVendorPermissions() (allowPI bool, allowGeo bool, allowID bool, err error) {
+	return false, false, false, nil
 }
 
 func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, consent string) (bool, error) {
@@ -99,11 +117,6 @@ func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, consen
 }
 
 func (p *permissionsImpl) allowPI(ctx context.Context, vendorID uint16, consent string) (bool, bool, bool, error) {
-	// If we're not given a consent string, respect the preferences in the app config.
-	if consent == "" {
-		return p.cfg.UsersyncIfAmbiguous, p.cfg.UsersyncIfAmbiguous, p.cfg.UsersyncIfAmbiguous, nil
-	}
-
 	parsedConsent, vendor, err := p.parseVendor(ctx, vendorID, consent)
 	if err != nil {
 		return false, false, false, err
@@ -221,14 +234,10 @@ func (a AlwaysAllow) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.B
 	return true, nil
 }
 
-func (a AlwaysAllow) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, bool, bool, error) {
+func (a AlwaysAllow) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string) (bool, bool, bool, error) {
 	return true, true, true, nil
 }
 
-func (a AlwaysAllow) AMPException() bool {
-	return false
-}
-
 // Exporting to allow for easy test setups
 type AlwaysFail struct{}
 
@@ -240,10 +249,6 @@ func (a AlwaysFail) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.Bi
 	return false, nil
 }
 
-func (a AlwaysFail) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, bool, bool, error) {
+func (a AlwaysFail) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string) (bool, bool, bool, error) {
 	return false, false, false, nil
 }
-
-func (a AlwaysFail) AMPException() bool {
-	return false
-}
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 6f426c52..e412a6f9 100755
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -51,6 +51,7 @@ const (
 	BidderAdmixer          BidderName = "admixer"
 	BidderAdOcean          BidderName = "adocean"
 	BidderAdoppler         BidderName = "adoppler"
+	BidderAdot             BidderName = "adot"
 	BidderAdpone           BidderName = "adpone"
 	BidderAdprime          BidderName = "adprime"
 	BidderAdtarget         BidderName = "adtarget"
@@ -93,7 +94,9 @@ const (
 	BidderLogicad          BidderName = "logicad"
 	BidderLunaMedia        BidderName = "lunamedia"
 	BidderMarsmedia        BidderName = "marsmedia"
+	BidderMediafuse        BidderName = "mediafuse"
 	BidderMgid             BidderName = "mgid"
+	BidderMobfoxpb         BidderName = "mobfoxpb"
 	BidderMobileFuse       BidderName = "mobilefuse"
 	BidderNanoInteractive  BidderName = "nanointeractive"
 	BidderNinthDecimal     BidderName = "ninthdecimal"
@@ -147,6 +150,7 @@ func CoreBidderNames() []BidderName {
 		BidderAdmixer,
 		BidderAdOcean,
 		BidderAdoppler,
+		BidderAdot,
 		BidderAdpone,
 		BidderAdprime,
 		BidderAdtarget,
@@ -189,7 +193,9 @@ func CoreBidderNames() []BidderName {
 		BidderLogicad,
 		BidderLunaMedia,
 		BidderMarsmedia,
+		BidderMediafuse,
 		BidderMgid,
+		BidderMobfoxpb,
 		BidderMobileFuse,
 		BidderNanoInteractive,
 		BidderNinthDecimal,
diff --git a/openrtb_ext/imp_adot.go b/openrtb_ext/imp_adot.go
new file mode 100644
index 00000000..5d741589
--- /dev/null
+++ b/openrtb_ext/imp_adot.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ExtImpAdot struct {
+	Parallax    bool   `json:"parallax,omitempty"`
+	PlacementId string `json:"placementId,omitempty"`
+}
diff --git a/openrtb_ext/imp_ix.go b/openrtb_ext/imp_ix.go
new file mode 100644
index 00000000..99cd3a21
--- /dev/null
+++ b/openrtb_ext/imp_ix.go
@@ -0,0 +1,7 @@
+package openrtb_ext
+
+// ExtImpIx defines the contract for bidrequest.imp[i].ext.ix
+type ExtImpIx struct {
+	SiteId string `json:"siteId"`
+	Size   []int  `json:"size"`
+}
diff --git a/privacy/enforcement.go b/privacy/enforcement.go
index 3f157329..64070ae3 100644
--- a/privacy/enforcement.go
+++ b/privacy/enforcement.go
@@ -19,14 +19,14 @@ func (e Enforcement) Any() bool {
 }
 
 // Apply cleans personally identifiable information from an OpenRTB bid request.
-func (e Enforcement) Apply(bidRequest *openrtb.BidRequest, ampGDPRException bool) {
-	e.apply(bidRequest, ampGDPRException, NewScrubber())
+func (e Enforcement) Apply(bidRequest *openrtb.BidRequest) {
+	e.apply(bidRequest, NewScrubber())
 }
 
-func (e Enforcement) apply(bidRequest *openrtb.BidRequest, ampGDPRException bool, scrubber Scrubber) {
+func (e Enforcement) apply(bidRequest *openrtb.BidRequest, scrubber Scrubber) {
 	if bidRequest != nil && e.Any() {
 		bidRequest.Device = scrubber.ScrubDevice(bidRequest.Device, e.getDeviceIDScrubStrategy(), e.getIPv4ScrubStrategy(), e.getIPv6ScrubStrategy(), e.getGeoScrubStrategy())
-		bidRequest.User = scrubber.ScrubUser(bidRequest.User, e.getUserScrubStrategy(ampGDPRException), e.getGeoScrubStrategy())
+		bidRequest.User = scrubber.ScrubUser(bidRequest.User, e.getUserScrubStrategy(), e.getGeoScrubStrategy())
 	}
 }
 
@@ -70,7 +70,7 @@ func (e Enforcement) getGeoScrubStrategy() ScrubStrategyGeo {
 	return ScrubStrategyGeoNone
 }
 
-func (e Enforcement) getUserScrubStrategy(ampGDPRException bool) ScrubStrategyUser {
+func (e Enforcement) getUserScrubStrategy() ScrubStrategyUser {
 	if e.COPPA {
 		return ScrubStrategyUserIDAndDemographic
 	}
@@ -79,7 +79,7 @@ func (e Enforcement) getUserScrubStrategy(ampGDPRException bool) ScrubStrategyUs
 		return ScrubStrategyUserID
 	}
 
-	if e.GDPRID && !ampGDPRException {
+	if e.GDPRID {
 		return ScrubStrategyUserID
 	}
 
diff --git a/static/bidder-info/adot.yaml b/static/bidder-info/adot.yaml
new file mode 100644
index 00000000..529ff3ae
--- /dev/null
+++ b/static/bidder-info/adot.yaml
@@ -0,0 +1,14 @@
+maintainer:
+  email: "admin@we-are-adot.com"
+modifyingVastXmlAllowed: false
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
diff --git a/static/bidder-info/adprime.yaml b/static/bidder-info/adprime.yaml
index 9759ed63..d702521e 100644
--- a/static/bidder-info/adprime.yaml
+++ b/static/bidder-info/adprime.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "rafal@adprime.com"
+  email: "prebid@adprime.com"
 capabilities:
   app:
     mediaTypes:
@@ -8,4 +8,4 @@ capabilities:
   site:
     mediaTypes:
       - banner
-      - video 
\ No newline at end of file
+      - video 
diff --git a/static/bidder-info/ix.yaml b/static/bidder-info/ix.yaml
index 326989ae..2f00ceb9 100644
--- a/static/bidder-info/ix.yaml
+++ b/static/bidder-info/ix.yaml
@@ -1,6 +1,15 @@
 maintainer:
   email: "pdu-supply-prebid@indexexchange.com"
 capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+      - audio
   site:
     mediaTypes:
       - banner
+      - video
+      - native
+      - audio
diff --git a/static/bidder-info/mediafuse.yaml b/static/bidder-info/mediafuse.yaml
new file mode 100644
index 00000000..112f67fe
--- /dev/null
+++ b/static/bidder-info/mediafuse.yaml
@@ -0,0 +1,11 @@
+maintainer:
+  email: "support@mediafuse.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video
diff --git a/static/bidder-info/mobfoxpb.yaml b/static/bidder-info/mobfoxpb.yaml
new file mode 100644
index 00000000..ba3bb60d
--- /dev/null
+++ b/static/bidder-info/mobfoxpb.yaml
@@ -0,0 +1,11 @@
+maintainer:
+  email: "platform@mobfox.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video
diff --git a/static/bidder-params/adot.json b/static/bidder-params/adot.json
new file mode 100644
index 00000000..fa2b8533
--- /dev/null
+++ b/static/bidder-params/adot.json
@@ -0,0 +1,17 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "The Adot Adapter Params",
+    "description": "A schema which validates params accepted by Adot adapter",
+    "type": "object",
+    "properties": {
+        "placementId": {
+            "type": "string",
+            "description": "An ID which identifies this placement of the impression"
+        },
+        "parallax": {
+            "type": "boolean",
+            "description": "It determines if the wanted advertising format is a parallax."
+        }
+    },
+    "required": []
+}
\ No newline at end of file
diff --git a/static/bidder-params/mediafuse.json b/static/bidder-params/mediafuse.json
new file mode 100644
index 00000000..4f38f89d
--- /dev/null
+++ b/static/bidder-params/mediafuse.json
@@ -0,0 +1,26 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Mediafuse Adapter Params",
+  "description": "A schema which validates params accepted by the Mediafuse adapter",
+
+  "type": "object",
+  "properties": {
+    "placementId": {
+      "type": "integer",
+      "description": "An ID which identifies this placement of the impression"
+    },
+    "siteId": {
+      "type": "integer",
+      "description": "An ID which identifies the site selling the impression"
+    },
+    "aid": {
+      "type": "integer",
+      "description": "An ID which identifies the channel"
+    },
+    "bidFloor": {
+      "type": "number",
+      "description": "BidFloor, US Dollars"
+    }
+  },
+  "required": ["aid"]
+}
diff --git a/static/bidder-params/mobfoxpb.json b/static/bidder-params/mobfoxpb.json
new file mode 100644
index 00000000..0cc7a16c
--- /dev/null
+++ b/static/bidder-params/mobfoxpb.json
@@ -0,0 +1,14 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Mobfox Adapter Params",
+  "description": "A schema which validates params accepted by the Mobfox adapter",
+  "type": "object",
+  "properties": {
+    "TagID": {
+      "type": "string",
+      "minLength": 1,
+      "description": "An ID which identifies the mobfox ad tag"
+    }
+  },
+  "required" : [ "TagID" ]
+}
diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go
index 84044e85..c41f7c6c 100755
--- a/usersync/usersyncers/syncer.go
+++ b/usersync/usersyncers/syncer.go
@@ -50,6 +50,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/logicad"
 	"github.com/prebid/prebid-server/adapters/lunamedia"
 	"github.com/prebid/prebid-server/adapters/marsmedia"
+	"github.com/prebid/prebid-server/adapters/mediafuse"
 	"github.com/prebid/prebid-server/adapters/mgid"
 	"github.com/prebid/prebid-server/adapters/nanointeractive"
 	"github.com/prebid/prebid-server/adapters/ninthdecimal"
@@ -136,6 +137,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderLogicad, logicad.NewLogicadSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderLunaMedia, lunamedia.NewLunaMediaSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderMarsmedia, marsmedia.NewMarsmediaSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderMediafuse, mediafuse.NewMediafuseSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderMgid, mgid.NewMgidSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderNanoInteractive, nanointeractive.NewNanoInteractiveSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderNinthDecimal, ninthdecimal.NewNinthDecimalSyncer)


Test patch:
diff --git a/adapters/adot/adot_test.go b/adapters/adot/adot_test.go
new file mode 100644
index 00000000..fca6b303
--- /dev/null
+++ b/adapters/adot/adot_test.go
@@ -0,0 +1,76 @@
+package adot
+
+import (
+	"encoding/json"
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/adapters"
+	"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"
+	"testing"
+)
+
+const testsBidderEndpoint = "https://dsp.adotmob.com/headerbidding/bidrequest"
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderAdot, config.Adapter{
+		Endpoint: testsBidderEndpoint})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "adottest", bidder)
+}
+
+//Test the media type error
+func TestMediaTypeError(t *testing.T) {
+	_, err := getMediaTypeForBid(nil)
+
+	assert.Error(t, err)
+
+	byteInvalid, _ := json.Marshal(&adotBidExt{Adot: bidExt{"invalid"}})
+	_, err = getMediaTypeForBid(&openrtb.Bid{Ext: json.RawMessage(byteInvalid)})
+
+	assert.Error(t, err)
+}
+
+//Test the bid response when the bidder return a status code 204
+func TestBidResponseNoContent(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderAdot, config.Adapter{
+		Endpoint: "https://dsp.adotmob.com/headerbidding/bidrequest"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	bidResponse, err := bidder.MakeBids(nil, nil, &adapters.ResponseData{StatusCode: 204})
+	if bidResponse != nil {
+		t.Fatalf("the bid response should be nil since the bidder status is No Content")
+	} else if err != nil {
+		t.Fatalf("the error should be nil since the bidder status is 204 : No Content")
+	}
+}
+
+//Test the media type for a bid response
+func TestMediaTypeForBid(t *testing.T) {
+	byteBanner, _ := json.Marshal(&adotBidExt{Adot: bidExt{"banner"}})
+	byteVideo, _ := json.Marshal(&adotBidExt{Adot: bidExt{"video"}})
+	byteNative, _ := json.Marshal(&adotBidExt{Adot: bidExt{"native"}})
+
+	bidTypeBanner, _ := getMediaTypeForBid(&openrtb.Bid{Ext: json.RawMessage(byteBanner)})
+	if bidTypeBanner != openrtb_ext.BidTypeBanner {
+		t.Errorf("the type is not the valid one. actual: %v, expected: %v", bidTypeBanner, openrtb_ext.BidTypeBanner)
+	}
+
+	bidTypeVideo, _ := getMediaTypeForBid(&openrtb.Bid{Ext: json.RawMessage(byteVideo)})
+	if bidTypeVideo != openrtb_ext.BidTypeVideo {
+		t.Errorf("the type is not the valid one. actual: %v, expected: %v", bidTypeVideo, openrtb_ext.BidTypeVideo)
+	}
+
+	bidTypeNative, _ := getMediaTypeForBid(&openrtb.Bid{Ext: json.RawMessage(byteNative)})
+	if bidTypeNative != openrtb_ext.BidTypeNative {
+		t.Errorf("the type is not the valid one. actual: %v, expected: %v", bidTypeNative, openrtb_ext.BidTypeVideo)
+	}
+}
diff --git a/adapters/adot/adottest/exemplary/simple-banner.json b/adapters/adot/adottest/exemplary/simple-banner.json
new file mode 100644
index 00000000..1b8cb986
--- /dev/null
+++ b/adapters/adot/adottest/exemplary/simple-banner.json
@@ -0,0 +1,94 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-banner-id",
+    "imp": [
+      {
+        "id": "test-imp-banner-id",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 250
+            }
+          ],
+          "w": 320,
+          "h": 250
+        },
+        "ext": {
+          "adot": {}
+        }
+      }
+    ]
+  },
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+      "body": {
+        "id": "test-request-banner-id",
+        "imp": [
+          {
+            "id": "test-imp-banner-id",
+            "banner": {
+              "format": [
+                {
+                  "w": 320,
+                  "h": 250
+                }
+              ],
+              "w": 320,
+              "h": 250
+            },
+            "ext": {
+              "adot": {}
+            }
+          }
+        ]
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": {
+        "id": "test-request-banner-id",
+        "seatbid": [{
+          "seat": "adot",
+          "bid": [{
+            "id": "test-request-banner-id",
+            "impid": "test-imp-banner-id",
+            "price": 1.16346,
+            "adm": "some-test-ad",
+            "w": 320,
+            "h": 50,
+            "ext": {
+              "adot": {
+                "media_type": "banner"
+              }
+            }
+          }]
+        }
+        ],
+        "cur": "USD"
+      }
+    }
+  }],
+
+  "expectedBidResponses": [{
+      "currency": "USD",
+      "bids": [{
+          "bid": {
+            "id": "test-request-banner-id",
+            "impid": "test-imp-banner-id",
+            "price": 1.16346,
+            "adm": "some-test-ad",
+            "w": 320,
+            "h": 50,
+            "ext": {
+              "adot": {
+                "media_type": "banner"
+              }
+            }
+          },
+        "type": "banner"
+        }]
+    }]
+}
+
diff --git a/adapters/adot/adottest/exemplary/simple-interstitial.json b/adapters/adot/adottest/exemplary/simple-interstitial.json
new file mode 100644
index 00000000..0e9b573a
--- /dev/null
+++ b/adapters/adot/adottest/exemplary/simple-interstitial.json
@@ -0,0 +1,101 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-inter-id",
+    "imp": [
+      {
+        "id": "test-imp-inter-id",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 480
+            }
+          ],
+          "w": 320,
+          "h": 480
+        },
+        "instl":1,
+        "ext": {
+          "adot": {}
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+        "body": {
+          "id": "test-request-inter-id",
+          "imp": [
+            {
+              "id": "test-imp-inter-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 320,
+                    "h": 480
+                  }
+                ],
+                "w": 320,
+                "h": 480
+              },
+              "instl":1,
+              "ext": {
+                "adot": {}
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "adot",
+              "bid": [{
+                "id": "test-request-inter-id",
+                "impid": "test-imp-inter-id",
+                "adm": "some-test-ad",
+                "price": 1.16346,
+                "w": 320,
+                "h": 480,
+                "ext": {
+                  "adot": {
+                    "media_type": "banner"
+                  }
+                }
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+        "bids": [{
+            "bid": {
+                "id": "test-request-inter-id",
+                "impid": "test-imp-inter-id",
+                "price":  1.16346,
+                "adm": "some-test-ad",
+                "w": 320,
+                "h": 480,
+                "ext": {
+                    "adot": {
+                        "media_type": "banner"
+                    }
+                }
+            },
+            "type": "banner"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/adapters/adot/adottest/exemplary/simple-native.json b/adapters/adot/adottest/exemplary/simple-native.json
new file mode 100644
index 00000000..5fa3c70f
--- /dev/null
+++ b/adapters/adot/adottest/exemplary/simple-native.json
@@ -0,0 +1,88 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-native-id",
+    "imp": [
+      {
+        "id": "test-imp-native-id",
+        "native": {
+          "request": "test-native",
+          "ver": "1.1"
+        },
+        "ext": {
+          "adot": {}
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+        "body": {
+          "id": "test-request-native-id",
+          "imp": [
+            {
+              "id": "test-imp-native-id",
+              "native": {
+                "request": "test-native",
+                "ver": "1.1"
+              },
+              "ext": {
+                "adot": {}
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "adot",
+              "bid": [{
+                "id": "test-request-native-id",
+                "impid": "test-imp-native-id",
+                "price": 1.16346,
+                "adm" : "native-ad",
+                "w": 300,
+                "h": 250,
+                "ext": {
+                  "adot": {
+                    "media_type": "native"
+                  }
+                }
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "test-request-native-id",
+            "impid": "test-imp-native-id",
+            "price": 1.16346,
+            "adm" : "native-ad",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "adot": {
+                "media_type": "native"
+              }
+            }
+          },
+          "type": "native"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/adapters/adot/adottest/exemplary/simple-video.json b/adapters/adot/adottest/exemplary/simple-video.json
new file mode 100644
index 00000000..a453c4b9
--- /dev/null
+++ b/adapters/adot/adottest/exemplary/simple-video.json
@@ -0,0 +1,120 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-video-id",
+    "imp": [
+      {
+        "id": "test-imp-video-id",
+        "video": {
+          "w": 300,
+          "h": 250,
+          "maxduration": 60,
+          "minduration": 1,
+          "api": [
+            1,
+            2,
+            5,
+            6,
+            7
+          ],
+          "mimes": [
+            "video\/mp4"
+          ],
+          "placement": 4,
+          "protocols": [
+            2
+          ]
+        },
+        "ext": {
+          "adot": {}
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+        "body": {
+          "id": "test-request-video-id",
+          "imp": [
+            {
+              "id": "test-imp-video-id",
+              "video": {
+                "w": 300,
+                "h": 250,
+                "maxduration": 60,
+                "minduration": 1,
+                "api": [
+                  1,
+                  2,
+                  5,
+                  6,
+                  7
+                ],
+                "mimes": [
+                  "video\/mp4"
+                ],
+                "placement": 4,
+                "protocols": [
+                  2
+                ]
+              },
+              "ext": {
+                "adot": {}
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "adot",
+              "bid": [{
+                "id": "test-request-video-id",
+                "impid": "test-imp-video-id",
+                "price": 1.16346,
+                "adm": "some-test-ad",
+                "w": 300,
+                "h": 250,
+                "ext": {
+                  "adot": {
+                    "media_type": "video"
+                  }
+                }
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "test-request-video-id",
+            "impid": "test-imp-video-id",
+            "price": 1.16346,
+            "adm": "some-test-ad",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "adot": {
+                "media_type": "video"
+              }
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/adapters/adot/adottest/params/race/banner.json b/adapters/adot/adottest/params/race/banner.json
new file mode 100644
index 00000000..ada77aa4
--- /dev/null
+++ b/adapters/adot/adottest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+  "placementId": "ee234aac-113"
+}
\ No newline at end of file
diff --git a/adapters/adot/adottest/params/race/video.json b/adapters/adot/adottest/params/race/video.json
new file mode 100644
index 00000000..37808cd2
--- /dev/null
+++ b/adapters/adot/adottest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+  "placementId": "ee234aac-112"
+}
\ No newline at end of file
diff --git a/adapters/adot/adottest/supplemental/simple-audio.json b/adapters/adot/adottest/supplemental/simple-audio.json
new file mode 100644
index 00000000..9be53c4c
--- /dev/null
+++ b/adapters/adot/adottest/supplemental/simple-audio.json
@@ -0,0 +1,66 @@
+{
+  "mockBidRequest": {
+    "id": "unsupported-audio-request",
+    "imp": [
+      {
+        "id": "unsupported-audio-imp",
+        "audio": {
+          "mimes": ["video/mp4"]
+        },
+        "ext": {
+          "bidder": {
+            "placementId": 1
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+        "body": {
+          "id": "unsupported-audio-request",
+          "imp": [
+            {
+              "id": "unsupported-audio-imp",
+              "audio": {
+                "mimes": ["video/mp4"]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": 1
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "adot",
+              "bid": [{
+                "id": "test-request-audio-id",
+                "impid": "test-imp-audio-id",
+                "price": 1.16346,
+                "adm": "some-audio-ad",
+                "ext": {
+                  "adot": {
+                    "media_type": "audio"
+                  }
+                }
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": []
+}
diff --git a/adapters/adot/adottest/supplemental/simple-parallax.json b/adapters/adot/adottest/supplemental/simple-parallax.json
new file mode 100644
index 00000000..4ee2ebc2
--- /dev/null
+++ b/adapters/adot/adottest/supplemental/simple-parallax.json
@@ -0,0 +1,103 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-parallax-id",
+    "imp": [
+      {
+        "id": "test-imp-parallax-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 600
+            }
+          ],
+          "w": 300,
+          "h": 600
+        },
+        "ext": {
+          "adot": {
+            "parallax": true
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+        "body": {
+          "id": "test-request-parallax-id",
+          "imp": [
+            {
+              "id": "test-imp-parallax-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ],
+                "w": 300,
+                "h": 600
+              },
+              "ext": {
+                "adot": {
+                  "parallax": true
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "adot",
+              "bid": [{
+                "id": "test-request-parallax-id",
+                "impid": "test-imp-parallax-id",
+                "price": 0.5,
+                "adm": "some-test-ad",
+                "w": 300,
+                "h": 600,
+                "ext": {
+                  "adot": {
+                    "media_type": "banner"
+                  }
+                }
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "test-request-parallax-id",
+            "impid": "test-imp-parallax-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "w": 300,
+            "h": 600,
+            "ext": {
+              "adot": {
+                "media_type": "banner"
+              }
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adot/adottest/supplemental/status_204.json b/adapters/adot/adottest/supplemental/status_204.json
new file mode 100644
index 00000000..44a895b5
--- /dev/null
+++ b/adapters/adot/adottest/supplemental/status_204.json
@@ -0,0 +1,39 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-banner-id",
+    "imp": [
+      {
+        "id": "test-imp-banner-id",
+        "banner": {},
+        "ext": {
+          "adot": {}
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+        "body": {
+          "id": "test-request-banner-id",
+          "imp": [
+            {
+              "id": "test-imp-banner-id",
+              "banner": {},
+              "ext": {
+                "adot": {}
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ],
+  "expectedBidResponses": []
+}
+
diff --git a/adapters/adot/adottest/supplemental/status_400.json b/adapters/adot/adottest/supplemental/status_400.json
new file mode 100644
index 00000000..22328fd9
--- /dev/null
+++ b/adapters/adot/adottest/supplemental/status_400.json
@@ -0,0 +1,62 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-banner-id",
+    "imp": [
+      {
+        "id": "test-imp-banner-id",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 250
+            }
+          ],
+          "w": 320,
+          "h": 250
+        },
+        "ext": {
+          "adot": {}
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+        "body": {
+          "id": "test-request-banner-id",
+          "imp": [
+            {
+              "id": "test-imp-banner-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 320,
+                    "h": 250
+                  }
+                ],
+                "w": 320,
+                "h": 250
+              },
+              "ext": {
+                "adot": {}
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
+
diff --git a/adapters/adot/adottest/supplemental/status_500.json b/adapters/adot/adottest/supplemental/status_500.json
new file mode 100644
index 00000000..879bb8c5
--- /dev/null
+++ b/adapters/adot/adottest/supplemental/status_500.json
@@ -0,0 +1,62 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-banner-id",
+    "imp": [
+      {
+        "id": "test-imp-banner-id",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 250
+            }
+          ],
+          "w": 320,
+          "h": 250
+        },
+        "ext": {
+          "adot": {}
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+        "body": {
+          "id": "test-request-banner-id",
+          "imp": [
+            {
+              "id": "test-imp-banner-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 320,
+                    "h": 250
+                  }
+                ],
+                "w": 320,
+                "h": 250
+              },
+              "ext": {
+                "adot": {}
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 500,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 500. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
+
diff --git a/adapters/adot/adottest/supplemental/unmarshal_error.json b/adapters/adot/adottest/supplemental/unmarshal_error.json
new file mode 100644
index 00000000..a87e1189
--- /dev/null
+++ b/adapters/adot/adottest/supplemental/unmarshal_error.json
@@ -0,0 +1,62 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-banner-id",
+    "imp": [
+      {
+        "id": "test-imp-banner-id",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 250
+            }
+          ],
+          "w": 320,
+          "h": 250
+        },
+        "ext": {
+          "adot": {}
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://dsp.adotmob.com/headerbidding/bidrequest",
+        "body": {
+          "id": "test-request-banner-id",
+          "imp": [
+            {
+              "id": "test-imp-banner-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 320,
+                    "h": 250
+                  }
+                ],
+                "w": 320,
+                "h": 250
+              },
+              "ext": {
+                "adot": {}
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": "fail for unmarshal"
+        }
+    }],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "json: cannot unmarshal string into Go value of type openrtb.BidResponse",
+      "comparison": "literal"
+    }
+  ]
+}
+
diff --git a/adapters/adot/params_test.go b/adapters/adot/params_test.go
new file mode 100644
index 00000000..2f7b4b9a
--- /dev/null
+++ b/adapters/adot/params_test.go
@@ -0,0 +1,53 @@
+package adot
+
+import (
+	"encoding/json"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"testing"
+)
+
+// This file actually intends to test static/bidder-params/adot.json
+//
+// These also validate the format of the external API: request.imp[i].ext.adot
+
+// TestValidParams makes sure that the adot 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.BidderAdot, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected adot 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.BidderAdot, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{}`,
+	`{"placementId": "test-114"}`,
+	`{"placementId": "test-113", "parallax": true}`,
+	`{"placementId": "test-113", "parallax": false}`,
+}
+
+var invalidParams = []string{
+	`{"parallax": 1}`,
+	`{"placementId": 135123}`,
+	`{"placementId": 113, "parallax": 1}`,
+	`{"placementId": 142, "parallax": true}`,
+	`{"placementId": "test-114", "parallax": 1}`,
+}
diff --git a/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json b/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json
new file mode 100644
index 00000000..b46c6f5f
--- /dev/null
+++ b/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json
@@ -0,0 +1,141 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "placement_id": 1
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://ib.adnxs.com/openrtb2",
+        "body": {
+          "id": "test-request-id",
+          "ext": {
+            "appnexus": {
+              "hb_source": 5
+            },
+            "prebid": {}
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ],
+                "w": 300,
+                "h": 250
+              },
+              "ext": {
+                "appnexus": {
+                  "placement_id": 1
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "958",
+              "bid": [{
+                "id": "7706636740145184841",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adid": "29681110",
+                "adm": "some-test-ad",
+                "adomain": ["appnexus.com"],
+                "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+                "cid": "958",
+                "crid": "29681110",
+                "h": 250,
+                "w": 300,
+                "ext": {
+                  "appnexus": {
+                    "brand_id": 1,
+                    "brand_category_id": 1,
+                    "auction_id": 8189378542222915032,
+                    "bid_ad_type": 0,
+                    "bidder_id": 2,
+                    "ranking_price": 0.000000,
+                    "deal_priority": 5
+                  }
+                }
+              }]
+            }
+          ],
+          "bidid": "5778926625248726496",
+          "cur": "MXN"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "MXN",
+      "bids": [
+        {
+          "bid": {
+            "id": "7706636740145184841",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "adid": "29681110",
+            "adomain": ["appnexus.com"],
+            "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110",
+            "cid": "958",
+            "crid": "29681110",
+            "w": 300,
+            "h": 250,
+            "cat": ["IAB20-3"],
+            "ext": {
+              "appnexus": {
+                "brand_id": 1,
+                "brand_category_id": 1,
+                "auction_id": 8189378542222915032,
+                "bid_ad_type": 0,
+                "bidder_id": 2,
+                "ranking_price": 0.000000,
+                "deal_priority": 5
+              }
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/ix/ix_test.go b/adapters/ix/ix_test.go
index 1a9abd24..8a75e685 100644
--- a/adapters/ix/ix_test.go
+++ b/adapters/ix/ix_test.go
@@ -13,10 +13,26 @@ import (
 
 	"github.com/mxmCherry/openrtb"
 	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/prebid/prebid-server/pbs"
 )
 
-const url string = "http://appnexus-us-east.lb.indexww.com/bidder?p=184932"
+const endpoint string = "http://host/endpoint"
+
+func TestJsonSamples(t *testing.T) {
+	if bidder, err := Builder(openrtb_ext.BidderIx, config.Adapter{Endpoint: endpoint}); err == nil {
+		ixBidder := bidder.(*IxAdapter)
+		ixBidder.maxRequests = 2
+		adapterstest.RunJSONBidderTest(t, "ixtest", bidder)
+	} else {
+		t.Fatalf("Builder returned unexpected error %v", err)
+	}
+}
+
+// Tests for the legacy, non-openrtb code.
+// They can be removed after the legacy interface is deprecated.
 
 func getAdUnit() pbs.PBSAdUnit {
 	return pbs.PBSAdUnit{
@@ -33,22 +49,50 @@ func getAdUnit() pbs.PBSAdUnit {
 	}
 }
 
+func getVideoAdUnit() pbs.PBSAdUnit {
+	return pbs.PBSAdUnit{
+		Code:       "unitCodeVideo",
+		MediaTypes: []pbs.MediaType{pbs.MEDIA_TYPE_VIDEO},
+		BidID:      "bididvideo",
+		Sizes: []openrtb.Format{
+			{
+				W: 100,
+				H: 75,
+			},
+		},
+		Video: pbs.PBSVideo{
+			Mimes:          []string{"video/mp4"},
+			Minduration:    15,
+			Maxduration:    30,
+			Startdelay:     5,
+			Skippable:      0,
+			PlaybackMethod: 1,
+			Protocols:      []int8{2, 3},
+		},
+		Params: json.RawMessage("{\"siteId\":\"12\"}"),
+	}
+}
+
 func getOpenRTBBid(i openrtb.Imp) openrtb.Bid {
 	return openrtb.Bid{
-		ID:     fmt.Sprintf("%d", rand.Intn(1000)),
-		ImpID:  i.ID,
-		Price:  1.0,
-		AdM:    "Content",
-		CrID:   fmt.Sprintf("%d", rand.Intn(1000)),
-		W:      *i.Banner.W,
-		H:      *i.Banner.H,
-		DealID: "5",
+		ID:    fmt.Sprintf("%d", rand.Intn(1000)),
+		ImpID: i.ID,
+		Price: 1.0,
+		AdM:   "Content",
 	}
 }
 
+func newAdapter(endpoint string) *IxAdapter {
+	return NewIxLegacyAdapter(adapters.DefaultHTTPAdapterConfig, endpoint)
+}
+
 func dummyIXServer(w http.ResponseWriter, r *http.Request) {
 	defer r.Body.Close()
 	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
 
 	var breq openrtb.BidRequest
 	err = json.Unmarshal(body, &breq)
@@ -78,43 +122,36 @@ func dummyIXServer(w http.ResponseWriter, r *http.Request) {
 	w.Write(js)
 }
 
-func TestIxInvalidCall(t *testing.T) {
-
-	an := NewIxLegacyAdapter(adapters.DefaultHTTPAdapterConfig, url)
-	an.URI = "blah"
+func TestIxSkipNoCookies(t *testing.T) {
+	if newAdapter(endpoint).SkipNoCookies() {
+		t.Fatalf("SkipNoCookies must return false")
+	}
+}
 
+func TestIxInvalidCall(t *testing.T) {
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	pbBidder := pbs.PBSBidder{}
-	_, err := an.Call(ctx, &pbReq, &pbBidder)
+	_, err := newAdapter(endpoint).Call(ctx, &pbReq, &pbBidder)
 	if err == nil {
 		t.Fatalf("No error received for invalid request")
 	}
 }
 
 func TestIxInvalidCallReqAppNil(t *testing.T) {
-
-	an := NewIxLegacyAdapter(adapters.DefaultHTTPAdapterConfig, url)
-	an.URI = "blah"
-
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{
 		App: &openrtb.App{},
 	}
-
 	pbBidder := pbs.PBSBidder{}
-	_, err := an.Call(ctx, &pbReq, &pbBidder)
 
+	_, err := newAdapter(endpoint).Call(ctx, &pbReq, &pbBidder)
 	if err == nil {
 		t.Fatalf("No error received for invalid request")
 	}
 }
 
 func TestIxInvalidCallMissingSiteID(t *testing.T) {
-
-	an := NewIxLegacyAdapter(adapters.DefaultHTTPAdapterConfig, url)
-	an.URI = "blah"
-
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	adUnit := getAdUnit()
@@ -126,7 +163,7 @@ func TestIxInvalidCallMissingSiteID(t *testing.T) {
 			adUnit,
 		},
 	}
-	_, err := an.Call(ctx, &pbReq, &pbBidder)
+	_, err := newAdapter(endpoint).Call(ctx, &pbReq, &pbBidder)
 	if err == nil {
 		t.Fatalf("No error received for request with missing siteId")
 	}
@@ -141,8 +178,6 @@ func TestIxTimeout(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx, cancel := context.WithTimeout(context.Background(), 0)
 	defer cancel()
 
@@ -153,7 +188,7 @@ func TestIxTimeout(t *testing.T) {
 			getAdUnit(),
 		},
 	}
-	_, err := an.Call(ctx, &pbReq, &pbBidder)
+	_, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder)
 	if err == nil || err != context.DeadlineExceeded {
 		t.Fatalf("Invalid timeout error received")
 	}
@@ -207,8 +242,6 @@ func TestIxTimeoutMultipleSlots(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	pbReq := pbs.PBSRequest{}
 
 	adUnit1 := getAdUnit()
@@ -227,7 +260,7 @@ func TestIxTimeoutMultipleSlots(t *testing.T) {
 			adUnit2,
 		},
 	}
-	bids, err := an.Call(ctx, &pbReq, &pbBidder)
+	bids, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder)
 
 	if err != nil {
 		t.Fatalf("Should not have gotten an error: %v", err)
@@ -252,8 +285,6 @@ func TestIxInvalidJsonResponse(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	pbBidder := pbs.PBSBidder{
@@ -262,7 +293,7 @@ func TestIxInvalidJsonResponse(t *testing.T) {
 			getAdUnit(),
 		},
 	}
-	_, err := an.Call(ctx, &pbReq, &pbBidder)
+	_, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder)
 	if err == nil {
 		t.Fatalf("No error received for invalid request")
 	}
@@ -278,17 +309,15 @@ func TestIxInvalidStatusCode(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
-	pbReq := pbs.PBSRequest{}
+	pbReq := pbs.PBSRequest{IsDebug: true}
 	pbBidder := pbs.PBSBidder{
 		BidderCode: "bannerCode",
 		AdUnits: []pbs.PBSAdUnit{
 			getAdUnit(),
 		},
 	}
-	_, err := an.Call(ctx, &pbReq, &pbBidder)
+	_, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder)
 	if err == nil {
 		t.Fatalf("No error received for invalid request")
 	}
@@ -304,8 +333,6 @@ func TestIxBadRequest(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	pbBidder := pbs.PBSBidder{
@@ -314,7 +341,7 @@ func TestIxBadRequest(t *testing.T) {
 			getAdUnit(),
 		},
 	}
-	_, err := an.Call(ctx, &pbReq, &pbBidder)
+	_, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder)
 	if err == nil {
 		t.Fatalf("No error received for bad request")
 	}
@@ -330,8 +357,6 @@ func TestIxNoContent(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	pbBidder := pbs.PBSBidder{
@@ -341,7 +366,7 @@ func TestIxNoContent(t *testing.T) {
 		},
 	}
 
-	bids, err := an.Call(ctx, &pbReq, &pbBidder)
+	bids, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder)
 	if err != nil || bids != nil {
 		t.Fatalf("Must return nil for no content")
 	}
@@ -354,8 +379,6 @@ func TestIxInvalidCallMissingSize(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	adUnit := getAdUnit()
@@ -366,7 +389,7 @@ func TestIxInvalidCallMissingSize(t *testing.T) {
 			adUnit,
 		},
 	}
-	if _, err := an.Call(ctx, &pbReq, &pbBidder); err == nil {
+	if _, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder); err == nil {
 		t.Fatalf("Should not have gotten an error for missing/invalid size: %v", err)
 	}
 }
@@ -378,8 +401,6 @@ func TestIxInvalidCallEmptyBidIDResponse(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	adUnit := getAdUnit()
@@ -390,7 +411,7 @@ func TestIxInvalidCallEmptyBidIDResponse(t *testing.T) {
 			adUnit,
 		},
 	}
-	if _, err := an.Call(ctx, &pbReq, &pbBidder); err == nil {
+	if _, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder); err == nil {
 		t.Fatalf("Should have gotten an error for unknown adunit code")
 	}
 }
@@ -414,14 +435,12 @@ func TestIxMismatchUnitCode(t *testing.T) {
 					{
 						Bid: []openrtb.Bid{
 							{
-								ID:     fmt.Sprintf("%d", rand.Intn(1000)),
-								ImpID:  "unitCode_bogus",
-								Price:  1.0,
-								AdM:    "Content",
-								CrID:   "567",
-								W:      10,
-								H:      12,
-								DealID: "5",
+								ID:    fmt.Sprintf("%d", rand.Intn(1000)),
+								ImpID: "unitCode_bogus",
+								Price: 1.0,
+								AdM:   "Content",
+								W:     10,
+								H:     12,
 							},
 						},
 					},
@@ -439,8 +458,6 @@ func TestIxMismatchUnitCode(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	pbBidder := pbs.PBSBidder{
@@ -449,11 +466,93 @@ func TestIxMismatchUnitCode(t *testing.T) {
 			getAdUnit(),
 		},
 	}
-	if _, err := an.Call(ctx, &pbReq, &pbBidder); err == nil {
+	if _, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder); err == nil {
 		t.Fatalf("Should have gotten an error for unknown adunit code")
 	}
 }
 
+func TestNoSeatBid(t *testing.T) {
+	server := httptest.NewServer(
+		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+			defer r.Body.Close()
+			body, err := ioutil.ReadAll(r.Body)
+
+			var breq openrtb.BidRequest
+			err = json.Unmarshal(body, &breq)
+			if err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+				return
+			}
+
+			resp := openrtb.BidResponse{}
+
+			js, err := json.Marshal(resp)
+			if err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+				return
+			}
+			w.Header().Set("Content-Type", "application/json")
+			w.Write(js)
+		}),
+	)
+	defer server.Close()
+
+	ctx := context.TODO()
+	pbReq := pbs.PBSRequest{}
+	pbBidder := pbs.PBSBidder{
+		BidderCode: "bannerCode",
+		AdUnits: []pbs.PBSAdUnit{
+			getAdUnit(),
+		},
+	}
+	if _, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder); err != nil {
+		t.Fatalf("Should not have gotten an error: %v", err)
+	}
+}
+
+func TestNoSeatBidBid(t *testing.T) {
+	server := httptest.NewServer(
+		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+			defer r.Body.Close()
+			body, err := ioutil.ReadAll(r.Body)
+
+			var breq openrtb.BidRequest
+			err = json.Unmarshal(body, &breq)
+			if err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+				return
+			}
+
+			resp := openrtb.BidResponse{
+				SeatBid: []openrtb.SeatBid{
+					{},
+				},
+			}
+
+			js, err := json.Marshal(resp)
+			if err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+				return
+			}
+			w.Header().Set("Content-Type", "application/json")
+			w.Write(js)
+		}),
+	)
+	defer server.Close()
+
+	ctx := context.TODO()
+	pbReq := pbs.PBSRequest{}
+	pbBidder := pbs.PBSBidder{
+		BidderCode: "bannerCode",
+		AdUnits: []pbs.PBSAdUnit{
+			getAdUnit(),
+		},
+	}
+	if _, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder); err != nil {
+		t.Fatalf("Should not have gotten an error: %v", err)
+	}
+}
+
 func TestIxInvalidParam(t *testing.T) {
 
 	server := httptest.NewServer(
@@ -461,8 +560,6 @@ func TestIxInvalidParam(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	adUnit := getAdUnit()
@@ -473,7 +570,7 @@ func TestIxInvalidParam(t *testing.T) {
 			adUnit,
 		},
 	}
-	if _, err := an.Call(ctx, &pbReq, &pbBidder); err == nil {
+	if _, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder); err == nil {
 		t.Fatalf("Should have gotten an error for unrecognized params")
 	}
 }
@@ -485,8 +582,6 @@ func TestIxSingleSlotSingleValidSize(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	pbBidder := pbs.PBSBidder{
@@ -495,7 +590,7 @@ func TestIxSingleSlotSingleValidSize(t *testing.T) {
 			getAdUnit(),
 		},
 	}
-	bids, err := an.Call(ctx, &pbReq, &pbBidder)
+	bids, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder)
 	if err != nil {
 		t.Fatalf("Should not have gotten an error: %v", err)
 	}
@@ -512,19 +607,10 @@ func TestIxTwoSlotValidSize(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	adUnit1 := getAdUnit()
-	adUnit2 := getAdUnit()
-	adUnit2.Code = "unitCode2"
-	adUnit2.Sizes = []openrtb.Format{
-		{
-			W: 8,
-			H: 10,
-		},
-	}
+	adUnit2 := getVideoAdUnit()
 	adUnit2.Params = json.RawMessage("{\"siteId\":\"1111\"}")
 
 	pbBidder := pbs.PBSBidder{
@@ -534,7 +620,7 @@ func TestIxTwoSlotValidSize(t *testing.T) {
 			adUnit2,
 		},
 	}
-	bids, err := an.Call(ctx, &pbReq, &pbBidder)
+	bids, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder)
 	if err != nil {
 		t.Fatalf("Should not have gotten an error: %v", err)
 	}
@@ -561,8 +647,6 @@ func TestIxTwoSlotMultiSizeOnlyValidIXSizeResponse(t *testing.T) {
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	adUnit := getAdUnit()
@@ -574,8 +658,7 @@ func TestIxTwoSlotMultiSizeOnlyValidIXSizeResponse(t *testing.T) {
 			adUnit,
 		},
 	}
-	bids, err := an.Call(ctx, &pbReq, &pbBidder)
-
+	bids, err := newAdapter(server.URL).Call(ctx, &pbReq, &pbBidder)
 	if err != nil {
 		t.Fatalf("Should not have gotten an error: %v", err)
 	}
@@ -609,20 +692,19 @@ func findBidByAdUnitCode(bids pbs.PBSBidSlice, c string) *pbs.PBSBid {
 	return &pbs.PBSBid{}
 }
 
-func TestIxRequestLimit(t *testing.T) {
+func TestIxMaxRequests(t *testing.T) {
 
 	server := httptest.NewServer(
 		http.HandlerFunc(dummyIXServer),
 	)
 	defer server.Close()
 
-	conf := *adapters.DefaultHTTPAdapterConfig
-	an := NewIxLegacyAdapter(&conf, server.URL)
+	adapter := newAdapter(server.URL)
 	ctx := context.TODO()
 	pbReq := pbs.PBSRequest{}
 	adUnits := []pbs.PBSAdUnit{}
 
-	for i := 0; i < requestLimit+1; i++ {
+	for i := 0; i < adapter.maxRequests+1; i++ {
 		adUnits = append(adUnits, getAdUnit())
 	}
 
@@ -631,13 +713,12 @@ func TestIxRequestLimit(t *testing.T) {
 		AdUnits:    adUnits,
 	}
 
-	bids, err := an.Call(ctx, &pbReq, &pbBidder)
-
+	bids, err := adapter.Call(ctx, &pbReq, &pbBidder)
 	if err != nil {
 		t.Fatalf("Should not have gotten an error: %v", err)
 	}
 
-	if len(bids) != requestLimit {
-		t.Fatalf("Should have received %d bid", requestLimit)
+	if len(bids) != adapter.maxRequests {
+		t.Fatalf("Should have received %d bid", adapter.maxRequests)
 	}
 }
diff --git a/adapters/ix/ixtest/exemplary/additional-consent.json b/adapters/ix/ixtest/exemplary/additional-consent.json
new file mode 100644
index 00000000..697c8697
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/additional-consent.json
@@ -0,0 +1,124 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "w": 300,
+                    "h": 250
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ],
+        "user": {
+            "ext": {
+                "consent": "COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw",
+                "consented_providers_settings": {
+                    "consented_providers": [1]
+                }
+            }
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ],
+                    "user": {
+                        "ext": {
+                            "consent": "COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw",
+                            "consented_providers_settings": {
+                                "consented_providers": [1]
+                            }
+                        }
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/exemplary/banner-no-format.json b/adapters/ix/ixtest/exemplary/banner-no-format.json
new file mode 100644
index 00000000..84f8499f
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/banner-no-format.json
@@ -0,0 +1,108 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "w": 300,
+                    "h": 250
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/exemplary/max-requests.json b/adapters/ix/ixtest/exemplary/max-requests.json
new file mode 100644
index 00000000..46d9ec5d
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/max-requests.json
@@ -0,0 +1,255 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id-1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            },
+            {
+                "id": "test-imp-id-2",
+                "video": {
+                    "mimes": [
+                        "video/mp4"
+                    ],
+                    "minduration": 15,
+                    "maxduration": 30,
+                    "protocols": [
+                        2,
+                        3,
+                        5,
+                        6,
+                        7,
+                        8
+                    ],
+                    "w": 940,
+                    "h": 560
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            },
+            {
+                "id": "test-imp-id-3",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id-1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id-1",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        },
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id-2",
+                            "video": {
+                                "mimes": [
+                                    "video/mp4"
+                                ],
+                                "minduration": 15,
+                                "maxduration": 30,
+                                "protocols": [
+                                    2,
+                                    3,
+                                    5,
+                                    6,
+                                    7,
+                                    8
+                                ],
+                                "w": 940,
+                                "h": 560
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id-2",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "cat": [
+                                        "IAB9-1"
+                                    ],
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id-1",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        },
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id-2",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "cat": [
+                            "IAB9-1"
+                        ],
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "video"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/exemplary/no-pub-id.json b/adapters/ix/ixtest/exemplary/no-pub-id.json
new file mode 100644
index 00000000..838d3c5e
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/no-pub-id.json
@@ -0,0 +1,121 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "w": 300,
+                    "h": 250
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ],
+        "site": {
+            "page": "https://www.example.com/",
+            "publisher": {
+                "name": "publisher-name"
+            }
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ],
+                    "site": {
+                        "page": "https://www.example.com/",
+                        "publisher": {
+                            "id": "569749",
+                            "name": "publisher-name"
+                        }
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/exemplary/no-pub.json b/adapters/ix/ixtest/exemplary/no-pub.json
new file mode 100644
index 00000000..bc113468
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/no-pub.json
@@ -0,0 +1,117 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "w": 300,
+                    "h": 250
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ],
+        "site": {
+            "page": "https://www.example.com/"
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ],
+                    "site": {
+                        "page": "https://www.example.com/",
+                        "publisher": {
+                            "id": "569749"
+                        }
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/exemplary/simple-audio.json b/adapters/ix/ixtest/exemplary/simple-audio.json
new file mode 100644
index 00000000..6bfe62a4
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/simple-audio.json
@@ -0,0 +1,102 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "audio": {
+                    "mimes": [
+                        "audio/mp4"
+                    ],
+                    "protocols": [
+                        9,
+                        10
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "audio": {
+                                "mimes": [
+                                    "audio/mp4"
+                                ],
+                                "protocols": [
+                                    9,
+                                    10
+                                ]
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110"
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adid": "29681110",
+                        "adm": "some-test-ad",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110"
+                    },
+                    "type": "audio"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/exemplary/simple-banner-multi-size.json b/adapters/ix/ixtest/exemplary/simple-banner-multi-size.json
new file mode 100644
index 00000000..5e0a311a
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/simple-banner-multi-size.json
@@ -0,0 +1,201 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        },
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 600
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 600,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        },
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 600,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/exemplary/simple-native.json b/adapters/ix/ixtest/exemplary/simple-native.json
new file mode 100644
index 00000000..845ba7cd
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/simple-native.json
@@ -0,0 +1,104 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "native": {
+                    "request": "{}",
+                    "ver": "1.1"
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpcalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "native": {
+                                "request": "{}",
+                                "ver": "1.1"
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "cat": [
+                                        "IAB3-1"
+                                    ],
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adid": "29681110",
+                        "adm": "some-test-ad",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "cat": [
+                            "IAB3-1"
+                        ],
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "native"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/exemplary/simple-video.json b/adapters/ix/ixtest/exemplary/simple-video.json
new file mode 100644
index 00000000..051eaa98
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/simple-video.json
@@ -0,0 +1,134 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "video": {
+                    "mimes": [
+                        "video/mp4"
+                    ],
+                    "minduration": 15,
+                    "maxduration": 30,
+                    "protocols": [
+                        2,
+                        3,
+                        5,
+                        6,
+                        7,
+                        8
+                    ],
+                    "w": 940,
+                    "h": 560
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "video": {
+                                "mimes": [
+                                    "video/mp4"
+                                ],
+                                "minduration": 15,
+                                "maxduration": 30,
+                                "protocols": [
+                                    2,
+                                    3,
+                                    5,
+                                    6,
+                                    7,
+                                    8
+                                ],
+                                "w": 940,
+                                "h": 560
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "cat": [
+                                        "IAB9-1"
+                                    ],
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "cat": [
+                            "IAB9-1"
+                        ],
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "video"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/params/race/audio.json b/adapters/ix/ixtest/params/race/audio.json
new file mode 100644
index 00000000..703df52e
--- /dev/null
+++ b/adapters/ix/ixtest/params/race/audio.json
@@ -0,0 +1,4 @@
+{
+  "siteId": "569749",
+  "size": [300, 250]
+}
diff --git a/adapters/ix/ixtest/params/race/banner.json b/adapters/ix/ixtest/params/race/banner.json
index e90050ef..703df52e 100644
--- a/adapters/ix/ixtest/params/race/banner.json
+++ b/adapters/ix/ixtest/params/race/banner.json
@@ -1,3 +1,4 @@
 {
-  "siteId": 500
+  "siteId": "569749",
+  "size": [300, 250]
 }
diff --git a/adapters/ix/ixtest/params/race/native.json b/adapters/ix/ixtest/params/race/native.json
new file mode 100644
index 00000000..703df52e
--- /dev/null
+++ b/adapters/ix/ixtest/params/race/native.json
@@ -0,0 +1,4 @@
+{
+  "siteId": "569749",
+  "size": [300, 250]
+}
diff --git a/adapters/ix/ixtest/params/race/video.json b/adapters/ix/ixtest/params/race/video.json
index e90050ef..993f0f6a 100644
--- a/adapters/ix/ixtest/params/race/video.json
+++ b/adapters/ix/ixtest/params/race/video.json
@@ -1,3 +1,4 @@
 {
-  "siteId": 500
+  "siteId": "569749",
+  "size": [940, 560]
 }
diff --git a/adapters/ix/ixtest/supplemental/bad-ext-bidder.json b/adapters/ix/ixtest/supplemental/bad-ext-bidder.json
new file mode 100644
index 00000000..e08da1e1
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/bad-ext-bidder.json
@@ -0,0 +1,22 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "ext": {
+                    "prebid": 1
+                }
+            }
+        ],
+        "site": {
+            "page": "https://www.example.com/"
+        }
+    },
+    "expectedMakeRequestsErrors": [
+        {
+            "value": "json: cannot unmarshal number into Go struct field ExtImpBidder.prebid of type openrtb_ext.ExtImpPrebid",
+            "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/bad-ext-ix.json b/adapters/ix/ixtest/supplemental/bad-ext-ix.json
new file mode 100644
index 00000000..a9a0383b
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/bad-ext-ix.json
@@ -0,0 +1,21 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "ext": {
+                }
+            }
+        ],
+        "site": {
+            "page": "https://www.example.com/"
+        }
+    },
+    "expectedMakeRequestsErrors": [
+        {
+            "value": "unexpected end of JSON input",
+            "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/bad-imp-id.json b/adapters/ix/ixtest/supplemental/bad-imp-id.json
new file mode 100644
index 00000000..0b852c85
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/bad-imp-id.json
@@ -0,0 +1,118 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "bad-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "bad-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "29681110",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": ""
+                }
+            ]
+        }
+    ],
+    "expectedMakeBidsErrors": [
+        {
+            "value": "Unmatched impression id: bad-imp-id.",
+            "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/bad-request.json b/adapters/ix/ixtest/supplemental/bad-request.json
new file mode 100644
index 00000000..f520d785
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/bad-request.json
@@ -0,0 +1,63 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 400,
+                "body": {}
+            }
+        }
+    ],
+    "expectedMakeBidsErrors": [
+        {
+            "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+            "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/bad-response-body.json b/adapters/ix/ixtest/supplemental/bad-response-body.json
new file mode 100644
index 00000000..80c2860e
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/bad-response-body.json
@@ -0,0 +1,65 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": 1
+                }
+            }
+        }
+    ],
+    "expectedMakeBidsErrors": [
+        {
+            "value": "JSON parsing error: json: cannot unmarshal number into Go struct field BidResponse.id of type string",
+            "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/no-content.json b/adapters/ix/ixtest/supplemental/no-content.json
new file mode 100644
index 00000000..fcdf02cb
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/no-content.json
@@ -0,0 +1,57 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 204,
+                "body": {}
+            }
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/no-imp.json b/adapters/ix/ixtest/supplemental/no-imp.json
new file mode 100644
index 00000000..308decd2
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/no-imp.json
@@ -0,0 +1,6 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": []
+    }
+}
diff --git a/adapters/ix/ixtest/supplemental/not-found.json b/adapters/ix/ixtest/supplemental/not-found.json
new file mode 100644
index 00000000..980bd942
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/not-found.json
@@ -0,0 +1,63 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ],
+                                "w": 300,
+                                "h": 250
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 404,
+                "body": {}
+            }
+        }
+    ],
+    "expectedMakeBidsErrors": [
+        {
+            "value": "Unexpected status code: 404. Run with request.debug = 1 for more info",
+            "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/mediafuse/usersync_test.go b/adapters/mediafuse/usersync_test.go
new file mode 100644
index 00000000..30b5b535
--- /dev/null
+++ b/adapters/mediafuse/usersync_test.go
@@ -0,0 +1,30 @@
+package mediafuse
+
+import (
+	"testing"
+	"text/template"
+
+	"github.com/prebid/prebid-server/privacy"
+	"github.com/prebid/prebid-server/privacy/gdpr"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestMediafuseSyncer(t *testing.T) {
+	syncURL := "//sync.hbmp.mediafuse.com/csync?t=p&ep=0&redir=localhost%2Fsetuid%3Fbidder%3Dmediafuse%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7Buid%7D"
+	syncURLTemplate := template.Must(
+		template.New("sync-template").Parse(syncURL),
+	)
+
+	syncer := NewMediafuseSyncer(syncURLTemplate)
+	syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+		GDPR: gdpr.Policy{
+			Signal: "0",
+		},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, "//sync.hbmp.mediafuse.com/csync?t=p&ep=0&redir=localhost%2Fsetuid%3Fbidder%3Dmediafuse%26gdpr%3D0%26gdpr_consent%3D%26uid%3D%7Buid%7D", syncInfo.URL)
+	assert.Equal(t, "redirect", syncInfo.Type)
+	assert.EqualValues(t, 411, syncer.GDPRVendorID())
+	assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/adapters/mobfoxpb/mobfoxpb_test.go b/adapters/mobfoxpb/mobfoxpb_test.go
new file mode 100644
index 00000000..271d30a9
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpb_test.go
@@ -0,0 +1,18 @@
+package mobfoxpb
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderMobfoxpb, config.Adapter{
+		Endpoint: "http://example.com/?c=o&m=ortb"})
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+	adapterstest.RunJSONBidderTest(t, "mobfoxpbtest", bidder)
+}
diff --git a/adapters/mobfoxpb/mobfoxpbtest/exemplary/simple-banner.json b/adapters/mobfoxpb/mobfoxpbtest/exemplary/simple-banner.json
new file mode 100644
index 00000000..b1936661
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/exemplary/simple-banner.json
@@ -0,0 +1,132 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+        {
+            "id": "test-imp-id",
+            "banner": {
+                "format": [
+                    {
+                      "w": 300,
+                      "h": 250
+                    },
+                    {
+                      "w": 300,
+                      "h": 600
+                    }
+                ]
+            },
+            "tagid": "6",
+            "ext": {
+                "bidder": {
+                  "TagID": "6"
+                }
+            }
+        }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+},
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com/?c=o&m=ortb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+              {
+                "id": "test-imp-id",
+                "banner": {
+                  "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+                "tagid": "6",
+                "ext": {
+                  "bidder": {
+                  "TagID": "6"
+                }
+              }
+            }
+          ],
+          "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 id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://bes.mobfox.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                    "cid": "test_cid",
+                    "crid": "test_crid",
+                    "dealid": "test_dealid",
+                    "w": 300,
+                    "h": 250,
+                    "ext": {
+                      "prebid": {
+                        "type": "banner"
+                      }
+                    }
+                  }
+                ]
+              }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://bes.mobfox.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "prebid": {
+                "type": "banner"
+              }
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/mobfoxpb/mobfoxpbtest/exemplary/simple-video.json b/adapters/mobfoxpb/mobfoxpbtest/exemplary/simple-video.json
new file mode 100644
index 00000000..6cdcdc5a
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/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": {
+            "TagID": "7"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com/?c=o&m=ortb",
+        "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
+              },
+              "tagid": "7",
+              "ext": {
+                "bidder": {
+                  "TagID": "7"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "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\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
+                "cid": "test_cid",
+                "crid": "test_crid",
+                "dealid": "test_dealid",
+                "ext": {
+                  "prebid": {
+                    "type": "video"
+                  }
+                }
+              }
+            ],
+            "seat": "mobfoxpb"
+          }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/mobfoxpb/mobfoxpbtest/exemplary/simple-web-banner.json b/adapters/mobfoxpb/mobfoxpbtest/exemplary/simple-web-banner.json
new file mode 100644
index 00000000..bba728ac
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/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
+            }
+          ]
+        },
+        "tagid": "8",
+        "ext": {
+          "bidder": {
+            "TagID": "8"
+          }
+        }
+      }
+    ],
+    "site": {
+      "id": "1",
+      "domain": "test.com"
+    },
+    "device": {
+      "ip": "123.123.123.123"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com/?c=o&m=ortb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "tagid": "8",
+              "ext": {
+                "bidder": {
+                  "TagID": "8"
+                }
+              }
+            }
+          ],
+          "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 id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://bes.mobfox.com/?c=o&m=adm&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "w": 468,
+                  "h": 60,
+                  "ext": {
+                    "prebid": {
+                      "type": "banner"
+                    }
+                  }
+                }
+              ],
+              "seat": "mobfoxpb"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://bes.mobfox.com/?c=o&m=adm&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "w": 468,
+            "h": 60,
+            "ext": {
+              "prebid": {
+                "type": "banner"
+              }
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/mobfoxpbtest/params/race/banner.json b/adapters/mobfoxpb/mobfoxpbtest/params/race/banner.json
new file mode 100644
index 00000000..dbdac1ad
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+  "TagID": "6"
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/mobfoxpbtest/params/race/video.json b/adapters/mobfoxpb/mobfoxpbtest/params/race/video.json
new file mode 100644
index 00000000..6e2e0b38
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+  "TagID": "7"
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/mobfoxpbtest/supplemental/bad-imp-ext.json b/adapters/mobfoxpb/mobfoxpbtest/supplemental/bad-imp-ext.json
new file mode 100644
index 00000000..ac3dce59
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/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
+            }
+          ]
+        },
+        "tagid": "6",
+        "ext": {
+          "mobfoxpb": {
+            "TagID": "6"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Key path not found",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/mobfoxpbtest/supplemental/bad_response.json b/adapters/mobfoxpb/mobfoxpbtest/supplemental/bad_response.json
new file mode 100644
index 00000000..2f834c92
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/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
+            }
+          ]
+        },
+        "tagid": "17",
+        "ext": {
+          "bidder": {
+            "TagID": "17"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com/?c=o&m=ortb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "tagid": "17",
+              "ext": {
+                "bidder": {
+                  "TagID": "17"
+                }
+              }
+            }
+          ],
+          "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 openrtb.BidResponse",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/mobfoxpbtest/supplemental/bad_status_code.json b/adapters/mobfoxpb/mobfoxpbtest/supplemental/bad_status_code.json
new file mode 100644
index 00000000..96d3a649
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/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
+            }
+          ]
+        },
+        "tagid": "100000000",
+        "ext": {
+          "bidder": {
+            "TagID": "100000000"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {}
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com/?c=o&m=ortb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "tagid": "100000000",
+              "ext": {
+                "bidder": {
+                  "TagID": "100000000"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {}
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/mobfoxpbtest/supplemental/imp_ext_empty_object.json b/adapters/mobfoxpb/mobfoxpbtest/supplemental/imp_ext_empty_object.json
new file mode 100644
index 00000000..cc56fa25
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/supplemental/imp_ext_empty_object.json
@@ -0,0 +1,38 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "tagid": "6",
+        "ext": {}
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Key path not found",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/mobfoxpbtest/supplemental/imp_ext_string.json b/adapters/mobfoxpb/mobfoxpbtest/supplemental/imp_ext_string.json
new file mode 100644
index 00000000..464c9e31
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/supplemental/imp_ext_string.json
@@ -0,0 +1,38 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "tagid": "6",
+        "ext": ""
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Key path not found",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/mobfoxpbtest/supplemental/status-204.json b/adapters/mobfoxpb/mobfoxpbtest/supplemental/status-204.json
new file mode 100644
index 00000000..c1091969
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/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
+            }
+          ]
+        },
+        "tagid": "17",
+        "ext": {
+          "bidder": {
+            "TagID": "17"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com/?c=o&m=ortb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "tagid": "17",
+              "ext": {
+                "bidder": {
+                  "TagID": "17"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+          }
+        }
+      },
+      "expectedBidResponses": [],
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/mobfoxpbtest/supplemental/status-404.json b/adapters/mobfoxpb/mobfoxpbtest/supplemental/status-404.json
new file mode 100644
index 00000000..d9ef7108
--- /dev/null
+++ b/adapters/mobfoxpb/mobfoxpbtest/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
+            }
+          ]
+        },
+        "tagid": "100000000",
+        "ext": {
+          "bidder": {
+            "TagID": "100000000"
+          }
+        }
+      }
+    ],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com/?c=o&m=ortb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "tagid": "100000000",
+              "ext": {
+                "bidder": {
+                  "TagID": "100000000"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 404,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 404. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/mobfoxpb/params_test.go b/adapters/mobfoxpb/params_test.go
new file mode 100644
index 00000000..59b9ec38
--- /dev/null
+++ b/adapters/mobfoxpb/params_test.go
@@ -0,0 +1,47 @@
+package mobfoxpb
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// TestValidParams makes sure that the mobfoxpb 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.BidderMobfoxpb, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected mobfoxpb params: %s", validParam)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the mobfoxpb 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.BidderMobfoxpb, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"TagID": "6"}`,
+}
+
+var invalidParams = []string{
+	`{"id": "123"}`,
+	`{"tagid": "123"}`,
+	`{"TagID": 16}`,
+	`{"TagID": ""}`,
+}
diff --git a/amp/parse_test.go b/amp/parse_test.go
new file mode 100644
index 00000000..e2c82d71
--- /dev/null
+++ b/amp/parse_test.go
@@ -0,0 +1,168 @@
+package amp
+
+import (
+	"net/http"
+	"testing"
+
+	"github.com/mxmCherry/openrtb"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestParseParams(t *testing.T) {
+	var expectedTimeout uint64 = 42
+
+	testCases := []struct {
+		description    string
+		query          string
+		expectedParams Params
+		expectedError  string
+	}{
+		{
+			description:   "Empty",
+			query:         "",
+			expectedError: "AMP requests require an AMP tag_id",
+		},
+		{
+			description: "All Fields",
+			query: "tag_id=anyTagID&account=anyAccount&curl=anyCurl&consent_string=anyConsent&debug=1&__amp_source_origin=anyOrigin" +
+				"&slot=anySlot&timeout=42&h=1&w=2&oh=3&ow=4&ms=10x11,12x13",
+			expectedParams: Params{
+				Account:         "anyAccount",
+				CanonicalURL:    "anyCurl",
+				Consent:         "anyConsent",
+				Debug:           true,
+				Origin:          "anyOrigin",
+				Slot:            "anySlot",
+				StoredRequestID: "anyTagID",
+				Timeout:         &expectedTimeout,
+				Size: Size{
+					Height:         1,
+					OverrideHeight: 3,
+					OverrideWidth:  4,
+					Width:          2,
+					Multisize: []openrtb.Format{
+						{W: 10, H: 11}, {W: 12, H: 13},
+					},
+				},
+			},
+		},
+		{
+			description:    "Integer Values Ignored If Invalid",
+			query:          "tag_id=anyTagID&h=invalid&w=invalid&oh=invalid&ow=invalid&ms=invalid",
+			expectedParams: Params{StoredRequestID: "anyTagID"},
+		},
+		{
+			description:    "consent_string Preferred Over gdpr_consent",
+			query:          "tag_id=anyTagID&consent_string=consent1&gdpr_consent=consent2",
+			expectedParams: Params{StoredRequestID: "anyTagID", Consent: "consent1"},
+		},
+		{
+			description:    "consent_string Preferred Over gdpr_consent - Order Doesn't Matter",
+			query:          "tag_id=anyTagID&gdpr_consent=consent2&consent_string=consent1",
+			expectedParams: Params{StoredRequestID: "anyTagID", Consent: "consent1"},
+		},
+		{
+			description:    "Just gdpr_consent",
+			query:          "tag_id=anyTagID&gdpr_consent=consent2",
+			expectedParams: Params{StoredRequestID: "anyTagID", Consent: "consent2"},
+		},
+		{
+			description:    "Debug 0",
+			query:          "tag_id=anyTagID&debug=0",
+			expectedParams: Params{StoredRequestID: "anyTagID", Debug: false},
+		},
+		{
+			description:    "Debug Ignored If Invalid",
+			query:          "tag_id=anyTagID&debug=invalid",
+			expectedParams: Params{StoredRequestID: "anyTagID", Debug: false},
+		},
+	}
+
+	for _, test := range testCases {
+		httpRequest, err := http.NewRequest("GET", "http://any.url/anypage?"+test.query, nil)
+		assert.NoError(t, err, test.description+":request")
+
+		params, err := ParseParams(httpRequest)
+		assert.Equal(t, test.expectedParams, params, test.description+":params")
+		if test.expectedError == "" {
+			assert.NoError(t, err, test.description+":err")
+		} else {
+			assert.EqualError(t, err, test.expectedError)
+		}
+	}
+}
+
+func TestParseMultisize(t *testing.T) {
+	testCases := []struct {
+		description     string
+		multisize       string
+		expectedFormats []openrtb.Format
+	}{
+		{
+			description:     "Empty",
+			multisize:       "",
+			expectedFormats: nil,
+		},
+		{
+			description:     "One",
+			multisize:       "1x2",
+			expectedFormats: []openrtb.Format{{W: 1, H: 2}},
+		},
+		{
+			description:     "Many",
+			multisize:       "1x2,3x4",
+			expectedFormats: []openrtb.Format{{W: 1, H: 2}, {W: 3, H: 4}},
+		},
+		{
+			// Existing Behavior: The " 3" token in the second size is parsed as 0.
+			description:     "Many With Space - Quirky Result",
+			multisize:       "1x2, 3x4",
+			expectedFormats: []openrtb.Format{{W: 1, H: 2}, {W: 0, H: 4}},
+		},
+		{
+			description:     "One - Zero Size - Ignored",
+			multisize:       "0x0",
+			expectedFormats: nil,
+		},
+		{
+			description:     "Many - Zero Size - All Ignored",
+			multisize:       "0x0,3x4",
+			expectedFormats: nil,
+		},
+		{
+			description:     "One - Extra Dimension - Ignored",
+			multisize:       "1x2x3",
+			expectedFormats: nil,
+		},
+		{
+			description:     "Many - Extra Dimension - All Ignored",
+			multisize:       "1x2x3,4x5",
+			expectedFormats: nil,
+		},
+		{
+			description:     "One - Invalid Values - Ignored",
+			multisize:       "INVALIDxINVALID",
+			expectedFormats: nil,
+		},
+		{
+			description:     "Many - Invalid Values - All Ignored",
+			multisize:       "1x2,INVALIDxINVALID",
+			expectedFormats: nil,
+		},
+		{
+			description:     "One - No Pair - Ignored",
+			multisize:       "INVALID",
+			expectedFormats: nil,
+		},
+		{
+			description:     "Many - No Pair - All Ignored",
+			multisize:       "1x2,INVALID",
+			expectedFormats: nil,
+		},
+	}
+
+	for _, test := range testCases {
+		result := parseMultisize(test.multisize)
+		assert.ElementsMatch(t, test.expectedFormats, result, test.description)
+	}
+}
diff --git a/endpoints/auction_test.go b/endpoints/auction_test.go
index f7f915cb..6a237e39 100644
--- a/endpoints/auction_test.go
+++ b/endpoints/auction_test.go
@@ -420,14 +420,10 @@ func (m *auctionMockPermissions) BidderSyncAllowed(ctx context.Context, bidder o
 	return m.allowBidderSync, nil
 }
 
-func (m *auctionMockPermissions) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, bool, bool, error) {
+func (m *auctionMockPermissions) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal gdpr.Signal, consent string) (bool, bool, bool, error) {
 	return m.allowPI, m.allowGeo, m.allowID, nil
 }
 
-func (m *auctionMockPermissions) AMPException() bool {
-	return false
-}
-
 func TestBidSizeValidate(t *testing.T) {
 	bids := make(pbs.PBSBidSlice, 0)
 	// bid1 will be rejected due to undefined size when adunit has multiple sizes
diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go
index 77be2590..c790fcd9 100644
--- a/endpoints/cookie_sync_test.go
+++ b/endpoints/cookie_sync_test.go
@@ -254,10 +254,6 @@ func (g *gdprPerms) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.Bi
 	return ok, nil
 }
 
-func (g *gdprPerms) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, bool, bool, error) {
+func (g *gdprPerms) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal gdpr.Signal, consent string) (bool, bool, bool, error) {
 	return true, true, true, nil
 }
-
-func (g *gdprPerms) AMPException() bool {
-	return false
-}
diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go
index 746d436d..97e99c6b 100644
--- a/endpoints/openrtb2/amp_auction_test.go
+++ b/endpoints/openrtb2/amp_auction_test.go
@@ -1031,14 +1031,12 @@ func getTestBidRequest(nilUser bool, userExt *openrtb_ext.ExtUser, nilRegs bool,
 
 func TestSetEffectiveAmpPubID(t *testing.T) {
 	testPubID := "test-pub"
-	testURLQueryParams := url.Values{}
-	testURLQueryParams.Add("account", testPubID)
 
 	testCases := []struct {
-		description    string
-		req            *openrtb.BidRequest
-		urlQueryParams url.Values
-		expectedPubID  string
+		description   string
+		req           *openrtb.BidRequest
+		account       string
+		expectedPubID string
 	}{
 		{
 			description: "No publisher ID provided",
@@ -1072,7 +1070,7 @@ func TestSetEffectiveAmpPubID(t *testing.T) {
 			expectedPubID: testPubID,
 		},
 		{
-			description: "Publisher ID present in account query parameter",
+			description: "Publisher ID present in account parameter",
 			req: &openrtb.BidRequest{
 				App: &openrtb.App{
 					Publisher: &openrtb.Publisher{
@@ -1080,8 +1078,8 @@ func TestSetEffectiveAmpPubID(t *testing.T) {
 					},
 				},
 			},
-			urlQueryParams: testURLQueryParams,
-			expectedPubID:  testPubID,
+			account:       testPubID,
+			expectedPubID: testPubID,
 		},
 		{
 			description: "req.Site.Publisher present but ID set to empty string",
@@ -1097,7 +1095,7 @@ func TestSetEffectiveAmpPubID(t *testing.T) {
 	}
 
 	for _, test := range testCases {
-		setEffectiveAmpPubID(test.req, test.urlQueryParams)
+		setEffectiveAmpPubID(test.req, test.account)
 		if test.req.Site != nil {
 			assert.Equal(t, test.expectedPubID, test.req.Site.Publisher.ID,
 				"should return the expected Publisher ID for test case: %s", test.description)
diff --git a/endpoints/setuid_test.go b/endpoints/setuid_test.go
index ae063677..60285958 100644
--- a/endpoints/setuid_test.go
+++ b/endpoints/setuid_test.go
@@ -11,6 +11,7 @@ import (
 	"time"
 
 	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/gdpr"
 	"github.com/prebid/prebid-server/metrics"
 	"github.com/prebid/prebid-server/privacy"
 	"github.com/prebid/prebid-server/usersync"
@@ -437,14 +438,10 @@ func (g *mockPermsSetUID) BidderSyncAllowed(ctx context.Context, bidder openrtb_
 	return false, nil
 }
 
-func (g *mockPermsSetUID) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, bool, bool, error) {
+func (g *mockPermsSetUID) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal gdpr.Signal, consent string) (bool, bool, bool, error) {
 	return g.allowPI, g.allowPI, g.allowPI, nil
 }
 
-func (g *mockPermsSetUID) AMPException() bool {
-	return false
-}
-
 func newFakeSyncer(familyName string) usersync.Usersyncer {
 	return fakeSyncer{
 		familyName: familyName,
diff --git a/exchange/adapter_util_test.go b/exchange/adapter_util_test.go
index f0010922..d7059648 100644
--- a/exchange/adapter_util_test.go
+++ b/exchange/adapter_util_test.go
@@ -9,7 +9,6 @@ import (
 	"github.com/mxmCherry/openrtb"
 	"github.com/prebid/prebid-server/adapters"
 	"github.com/prebid/prebid-server/adapters/appnexus"
-	"github.com/prebid/prebid-server/adapters/ix"
 	"github.com/prebid/prebid-server/adapters/lifestreet"
 	"github.com/prebid/prebid-server/adapters/pulsepoint"
 	"github.com/prebid/prebid-server/adapters/rubicon"
@@ -29,12 +28,12 @@ var (
 func TestBuildAdaptersSuccess(t *testing.T) {
 	client := &http.Client{}
 	cfg := &config.Configuration{Adapters: map[string]config.Adapter{
-		"appnexus": {},
-		"ix":       {Endpoint: "anyEndpoint"},
+		"appnexus":   {},
+		"lifestreet": {Endpoint: "anyEndpoint"},
 	}}
 	infos := map[string]adapters.BidderInfo{
-		"appnexus": infoActive,
-		"ix":       infoActive,
+		"appnexus":   infoActive,
+		"lifestreet": infoActive,
 	}
 	metricEngine := &metrics.DummyMetricsEngine{}
 
@@ -45,12 +44,12 @@ func TestBuildAdaptersSuccess(t *testing.T) {
 	appnexusBidderAdapted := adaptBidder(appnexusBidderWithInfo, client, &config.Configuration{}, metricEngine, openrtb_ext.BidderAppnexus)
 	appnexusBidderValidated := addValidatedBidderMiddleware(appnexusBidderAdapted)
 
-	idLegacyAdapted := &adaptedAdapter{ix.NewIxLegacyAdapter(adapters.DefaultHTTPAdapterConfig, "anyEndpoint")}
+	idLegacyAdapted := &adaptedAdapter{lifestreet.NewLifestreetLegacyAdapter(adapters.DefaultHTTPAdapterConfig, "anyEndpoint")}
 	idLegacyValidated := addValidatedBidderMiddleware(idLegacyAdapted)
 
 	expectedBidders := map[openrtb_ext.BidderName]adaptedBidder{
-		openrtb_ext.BidderAppnexus: appnexusBidderValidated,
-		openrtb_ext.BidderIx:       idLegacyValidated,
+		openrtb_ext.BidderAppnexus:   appnexusBidderValidated,
+		openrtb_ext.BidderLifestreet: idLegacyValidated,
 	}
 
 	assert.Equal(t, expectedBidders, bidders)
@@ -215,9 +214,9 @@ func TestBuildBidders(t *testing.T) {
 		},
 		{
 			description:   "Success - Ignores Legacy",
-			adapterConfig: map[string]config.Adapter{"appnexus": {}, "ix": {}, "lifestreet": {}, "pulsepoint": {}},
-			bidderInfos:   map[string]adapters.BidderInfo{"appnexus": infoActive, "ix": infoActive, "lifestreet": infoActive, "pulsepoint": infoActive},
-			builders:      map[openrtb_ext.BidderName]adapters.Builder{openrtb_ext.BidderAppnexus: appnexusBuilder, openrtb_ext.BidderIx: inconsequentialBuilder, openrtb_ext.BidderLifestreet: inconsequentialBuilder, openrtb_ext.BidderPulsepoint: inconsequentialBuilder},
+			adapterConfig: map[string]config.Adapter{"appnexus": {}, "lifestreet": {}, "pulsepoint": {}},
+			bidderInfos:   map[string]adapters.BidderInfo{"appnexus": infoActive, "lifestreet": infoActive, "pulsepoint": infoActive},
+			builders:      map[openrtb_ext.BidderName]adapters.Builder{openrtb_ext.BidderAppnexus: appnexusBuilder, openrtb_ext.BidderLifestreet: inconsequentialBuilder, openrtb_ext.BidderPulsepoint: inconsequentialBuilder},
 			expectedBidders: map[openrtb_ext.BidderName]adapters.Bidder{
 				openrtb_ext.BidderAppnexus: adapters.EnforceBidderInfo(appnexusBidder, infoActive),
 			},
@@ -267,7 +266,6 @@ func TestBuildBidders(t *testing.T) {
 func TestBuildExchangeBiddersLegacy(t *testing.T) {
 	cfg := config.Adapter{Endpoint: "anyEndpoint"}
 
-	expectedIx := &adaptedAdapter{ix.NewIxLegacyAdapter(adapters.DefaultHTTPAdapterConfig, "anyEndpoint")}
 	expectedLifestreet := &adaptedAdapter{lifestreet.NewLifestreetLegacyAdapter(adapters.DefaultHTTPAdapterConfig, "anyEndpoint")}
 	expectedPulsepoint := &adaptedAdapter{pulsepoint.NewPulsePointLegacyAdapter(adapters.DefaultHTTPAdapterConfig, "anyEndpoint")}
 
@@ -279,27 +277,27 @@ func TestBuildExchangeBiddersLegacy(t *testing.T) {
 	}{
 		{
 			description:   "All Active",
-			adapterConfig: map[string]config.Adapter{"ix": cfg, "lifestreet": cfg, "pulsepoint": cfg},
-			bidderInfos:   map[string]adapters.BidderInfo{"ix": infoActive, "lifestreet": infoActive, "pulsepoint": infoActive},
-			expected:      map[openrtb_ext.BidderName]adaptedBidder{"ix": expectedIx, "lifestreet": expectedLifestreet, "pulsepoint": expectedPulsepoint},
+			adapterConfig: map[string]config.Adapter{"lifestreet": cfg, "pulsepoint": cfg},
+			bidderInfos:   map[string]adapters.BidderInfo{"lifestreet": infoActive, "pulsepoint": infoActive},
+			expected:      map[openrtb_ext.BidderName]adaptedBidder{"lifestreet": expectedLifestreet, "pulsepoint": expectedPulsepoint},
 		},
 		{
 			description:   "All Disabled",
-			adapterConfig: map[string]config.Adapter{"ix": cfg, "lifestreet": cfg, "pulsepoint": cfg},
-			bidderInfos:   map[string]adapters.BidderInfo{"ix": infoDisabled, "lifestreet": infoDisabled, "pulsepoint": infoDisabled},
+			adapterConfig: map[string]config.Adapter{"lifestreet": cfg, "pulsepoint": cfg},
+			bidderInfos:   map[string]adapters.BidderInfo{"lifestreet": infoDisabled, "pulsepoint": infoDisabled},
 			expected:      map[openrtb_ext.BidderName]adaptedBidder{},
 		},
 		{
 			description:   "All Unknown",
-			adapterConfig: map[string]config.Adapter{"ix": cfg, "lifestreet": cfg, "pulsepoint": cfg},
-			bidderInfos:   map[string]adapters.BidderInfo{"ix": infoUnknown, "lifestreet": infoUnknown, "pulsepoint": infoUnknown},
+			adapterConfig: map[string]config.Adapter{"lifestreet": cfg, "pulsepoint": cfg},
+			bidderInfos:   map[string]adapters.BidderInfo{"lifestreet": infoUnknown, "pulsepoint": infoUnknown},
 			expected:      map[openrtb_ext.BidderName]adaptedBidder{},
 		},
 		{
 			description:   "Mixed",
-			adapterConfig: map[string]config.Adapter{"ix": cfg, "lifestreet": cfg, "pulsepoint": cfg},
-			bidderInfos:   map[string]adapters.BidderInfo{"ix": infoActive, "lifestreet": infoDisabled, "pulsepoint": infoUnknown},
-			expected:      map[openrtb_ext.BidderName]adaptedBidder{"ix": expectedIx},
+			adapterConfig: map[string]config.Adapter{"lifestreet": cfg, "pulsepoint": cfg},
+			bidderInfos:   map[string]adapters.BidderInfo{"lifestreet": infoActive, "pulsepoint": infoUnknown},
+			expected:      map[openrtb_ext.BidderName]adaptedBidder{"lifestreet": expectedLifestreet},
 		},
 	}
 
diff --git a/exchange/gdpr_test.go b/exchange/gdpr_test.go
index 2d8fff86..f7906104 100644
--- a/exchange/gdpr_test.go
+++ b/exchange/gdpr_test.go
@@ -5,40 +5,97 @@ import (
 	"testing"
 
 	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/gdpr"
 	"github.com/stretchr/testify/assert"
 )
 
-func TestExtractGDPRFound(t *testing.T) {
-	gdprTest := openrtb.BidRequest{
-		User: &openrtb.User{
-			Ext: json.RawMessage(`{"consent": "BOS2bx5OS2bx5ABABBAAABoAAAAAFA"}`),
+func TestExtractGDPR(t *testing.T) {
+	tests := []struct {
+		description string
+		giveRegs    *openrtb.Regs
+		wantGDPR    gdpr.Signal
+	}{
+		{
+			description: "Regs Ext GDPR = 0",
+			giveRegs:    &openrtb.Regs{Ext: json.RawMessage(`{"gdpr": 0}`)},
+			wantGDPR:    gdpr.SignalNo,
 		},
-		Regs: &openrtb.Regs{
-			Ext: json.RawMessage(`{"gdpr": 1}`),
+		{
+			description: "Regs Ext GDPR = 1",
+			giveRegs:    &openrtb.Regs{Ext: json.RawMessage(`{"gdpr": 1}`)},
+			wantGDPR:    gdpr.SignalYes,
+		},
+		{
+			description: "Regs Ext GDPR = null",
+			giveRegs:    &openrtb.Regs{Ext: json.RawMessage(`{"gdpr": null}`)},
+			wantGDPR:    gdpr.SignalAmbiguous,
+		},
+		{
+			description: "Regs is nil",
+			giveRegs:    nil,
+			wantGDPR:    gdpr.SignalAmbiguous,
+		},
+		{
+			description: "Regs Ext is nil",
+			giveRegs:    &openrtb.Regs{Ext: nil},
+			wantGDPR:    gdpr.SignalAmbiguous,
+		},
+		{
+			description: "JSON unmarshal error",
+			giveRegs:    &openrtb.Regs{Ext: json.RawMessage(`{"`)},
+			wantGDPR:    gdpr.SignalAmbiguous,
 		},
 	}
-	gdpr := extractGDPR(&gdprTest, false)
-	consent := extractConsent(&gdprTest)
-	assert.Equal(t, 1, gdpr)
-	assert.Equal(t, "BOS2bx5OS2bx5ABABBAAABoAAAAAFA", consent)
-
-	gdprTest.Regs.Ext = json.RawMessage(`{"gdpr": 0}`)
-	gdpr = extractGDPR(&gdprTest, true)
-	consent = extractConsent(&gdprTest)
-	assert.Equal(t, 0, gdpr)
-	assert.Equal(t, "BOS2bx5OS2bx5ABABBAAABoAAAAAFA", consent)
-}
 
-func TestGDPRUnknown(t *testing.T) {
-	gdprTest := openrtb.BidRequest{}
+	for _, tt := range tests {
+		bidReq := openrtb.BidRequest{
+			Regs: tt.giveRegs,
+		}
 
-	gdpr := extractGDPR(&gdprTest, false)
-	consent := extractConsent(&gdprTest)
-	assert.Equal(t, 1, gdpr)
-	assert.Equal(t, "", consent)
+		result := extractGDPR(&bidReq)
+		assert.Equal(t, tt.wantGDPR, result, tt.description)
+	}
+}
 
-	gdpr = extractGDPR(&gdprTest, true)
-	consent = extractConsent(&gdprTest)
-	assert.Equal(t, 0, gdpr)
+func TestExtractConsent(t *testing.T) {
+	tests := []struct {
+		description string
+		giveUser    *openrtb.User
+		wantConsent string
+	}{
+		{
+			description: "User Ext Consent is not empty",
+			giveUser:    &openrtb.User{Ext: json.RawMessage(`{"consent": "BOS2bx5OS2bx5ABABBAAABoAAAAAFA"}`)},
+			wantConsent: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA",
+		},
+		{
+			description: "User Ext Consent is empty",
+			giveUser:    &openrtb.User{Ext: json.RawMessage(`{"consent": ""}`)},
+			wantConsent: "",
+		},
+		{
+			description: "User Ext is nil",
+			giveUser:    &openrtb.User{Ext: nil},
+			wantConsent: "",
+		},
+		{
+			description: "User is nil",
+			giveUser:    nil,
+			wantConsent: "",
+		},
+		{
+			description: "JSON unmarshal error",
+			giveUser:    &openrtb.User{Ext: json.RawMessage(`{`)},
+			wantConsent: "",
+		},
+	}
+
+	for _, tt := range tests {
+		bidReq := openrtb.BidRequest{
+			User: tt.giveUser,
+		}
 
+		result := extractConsent(&bidReq)
+		assert.Equal(t, tt.wantConsent, result, tt.description)
+	}
 }
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 5fb5707c..e13f956b 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/mxmCherry/openrtb"
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/gdpr"
 	"github.com/prebid/prebid-server/metrics"
 	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/stretchr/testify/assert"
@@ -19,7 +20,8 @@ import (
 //
 // It only allows appnexus for GDPR consent
 type permissionsMock struct {
-	personalInfoAllowed bool
+	personalInfoAllowed      bool
+	personalInfoAllowedError error
 }
 
 func (p *permissionsMock) HostCookiesAllowed(ctx context.Context, consent string) (bool, error) {
@@ -30,12 +32,8 @@ func (p *permissionsMock) BidderSyncAllowed(ctx context.Context, bidder openrtb_
 	return true, nil
 }
 
-func (p *permissionsMock) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, bool, bool, error) {
-	return p.personalInfoAllowed, p.personalInfoAllowed, p.personalInfoAllowed, nil
-}
-
-func (p *permissionsMock) AMPException() bool {
-	return false
+func (p *permissionsMock) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, gdpr gdpr.Signal, consent string) (bool, bool, bool, error) {
+	return p.personalInfoAllowed, p.personalInfoAllowed, p.personalInfoAllowed, p.personalInfoAllowedError
 }
 
 func assertReq(t *testing.T, bidderRequests []BidderRequest,
@@ -1048,6 +1046,8 @@ func TestCleanOpenRTBRequestsLMT(t *testing.T) {
 }
 
 func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
+	tcf1Consent := "BONV8oqONXwgmADACHENAO7pqzAAppY"
+	tcf2Consent := "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA"
 	trueValue, falseValue := true, false
 
 	testCases := []struct {
@@ -1057,6 +1057,8 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 		gdpr                string
 		gdprConsent         string
 		gdprScrub           bool
+		permissionsError    error
+		userSyncIfAmbiguous bool
 		expectPrivacyLabels metrics.PrivacyLabels
 	}{
 		{
@@ -1076,7 +1078,7 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			gdprAccountEnabled: &trueValue,
 			gdprHostEnabled:    true,
 			gdpr:               "1",
-			gdprConsent:        "BONV8oqONXwgmADACHENAO7pqzAAppY",
+			gdprConsent:        tcf1Consent,
 			gdprScrub:          true,
 			expectPrivacyLabels: metrics.PrivacyLabels{
 				GDPREnforced:   true,
@@ -1088,7 +1090,7 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			gdprAccountEnabled: &trueValue,
 			gdprHostEnabled:    true,
 			gdpr:               "1",
-			gdprConsent:        "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
+			gdprConsent:        tcf2Consent,
 			gdprScrub:          true,
 			expectPrivacyLabels: metrics.PrivacyLabels{
 				GDPREnforced:   true,
@@ -1100,7 +1102,7 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			gdprAccountEnabled: &trueValue,
 			gdprHostEnabled:    true,
 			gdpr:               "0",
-			gdprConsent:        "BONV8oqONXwgmADACHENAO7pqzAAppY",
+			gdprConsent:        tcf1Consent,
 			gdprScrub:          false,
 			expectPrivacyLabels: metrics.PrivacyLabels{
 				GDPREnforced:   false,
@@ -1112,7 +1114,7 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			gdprAccountEnabled: &trueValue,
 			gdprHostEnabled:    false,
 			gdpr:               "1",
-			gdprConsent:        "BONV8oqONXwgmADACHENAO7pqzAAppY",
+			gdprConsent:        tcf1Consent,
 			gdprScrub:          true,
 			expectPrivacyLabels: metrics.PrivacyLabels{
 				GDPREnforced:   true,
@@ -1124,7 +1126,7 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			gdprAccountEnabled: &falseValue,
 			gdprHostEnabled:    true,
 			gdpr:               "1",
-			gdprConsent:        "BONV8oqONXwgmADACHENAO7pqzAAppY",
+			gdprConsent:        tcf1Consent,
 			gdprScrub:          false,
 			expectPrivacyLabels: metrics.PrivacyLabels{
 				GDPREnforced:   false,
@@ -1136,7 +1138,7 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			gdprAccountEnabled: nil,
 			gdprHostEnabled:    true,
 			gdpr:               "1",
-			gdprConsent:        "BONV8oqONXwgmADACHENAO7pqzAAppY",
+			gdprConsent:        tcf1Consent,
 			gdprScrub:          true,
 			expectPrivacyLabels: metrics.PrivacyLabels{
 				GDPREnforced:   true,
@@ -1148,13 +1150,52 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			gdprAccountEnabled: nil,
 			gdprHostEnabled:    false,
 			gdpr:               "1",
-			gdprConsent:        "BONV8oqONXwgmADACHENAO7pqzAAppY",
+			gdprConsent:        tcf1Consent,
 			gdprScrub:          false,
 			expectPrivacyLabels: metrics.PrivacyLabels{
 				GDPREnforced:   false,
 				GDPRTCFVersion: "",
 			},
 		},
+		{
+			description:         "Enforce - Ambiguous signal, don't sync user if ambiguous",
+			gdprAccountEnabled:  nil,
+			gdprHostEnabled:     true,
+			gdpr:                "null",
+			gdprConsent:         tcf1Consent,
+			gdprScrub:           true,
+			userSyncIfAmbiguous: false,
+			expectPrivacyLabels: metrics.PrivacyLabels{
+				GDPREnforced:   true,
+				GDPRTCFVersion: metrics.TCFVersionV1,
+			},
+		},
+		{
+			description:         "Not Enforce - Ambiguous signal, sync user if ambiguous",
+			gdprAccountEnabled:  nil,
+			gdprHostEnabled:     true,
+			gdpr:                "null",
+			gdprConsent:         tcf1Consent,
+			gdprScrub:           false,
+			userSyncIfAmbiguous: true,
+			expectPrivacyLabels: metrics.PrivacyLabels{
+				GDPREnforced:   false,
+				GDPRTCFVersion: "",
+			},
+		},
+		{
+			description:        "Enforce - error while checking if personal info is allowed",
+			gdprAccountEnabled: nil,
+			gdprHostEnabled:    true,
+			gdpr:               "1",
+			gdprConsent:        tcf1Consent,
+			gdprScrub:          true,
+			permissionsError:   errors.New("Some error"),
+			expectPrivacyLabels: metrics.PrivacyLabels{
+				GDPREnforced:   true,
+				GDPRTCFVersion: metrics.TCFVersionV1,
+			},
+		},
 	}
 
 	for _, test := range testCases {
@@ -1166,7 +1207,8 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 
 		privacyConfig := config.Privacy{
 			GDPR: config.GDPR{
-				Enabled: test.gdprHostEnabled,
+				Enabled:             test.gdprHostEnabled,
+				UsersyncIfAmbiguous: test.userSyncIfAmbiguous,
 				TCF2: config.TCF2{
 					Enabled: true,
 				},
@@ -1189,8 +1231,8 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			context.Background(),
 			auctionReq,
 			nil,
-			&permissionsMock{personalInfoAllowed: !test.gdprScrub},
-			true,
+			&permissionsMock{personalInfoAllowed: !test.gdprScrub, personalInfoAllowedError: test.permissionsError},
+			test.userSyncIfAmbiguous,
 			privacyConfig)
 		result := results[0]
 
diff --git a/gdpr/impl_test.go b/gdpr/impl_test.go
index 793eb967..a7d4b26a 100644
--- a/gdpr/impl_test.go
+++ b/gdpr/impl_test.go
@@ -177,20 +177,107 @@ func TestMalformedConsent(t *testing.T) {
 }
 
 func TestAllowPersonalInfo(t *testing.T) {
+	bidderAllowedByConsent := openrtb_ext.BidderAppnexus
+	bidderBlockedByConsent := openrtb_ext.BidderRubicon
+	consent := "BOS2bx5OS2bx5ABABBAAABoAAAABBwAA"
+
+	tests := []struct {
+		description         string
+		bidderName          openrtb_ext.BidderName
+		publisherID         string
+		userSyncIfAmbiguous bool
+		gdpr                Signal
+		consent             string
+		allowPI             bool
+	}{
+		{
+			description:         "Allow PI - Non standard publisher",
+			bidderName:          bidderBlockedByConsent,
+			publisherID:         "appNexusAppID",
+			userSyncIfAmbiguous: false,
+			gdpr:                SignalYes,
+			consent:             consent,
+			allowPI:             true,
+		},
+		{
+			description:         "Allow PI - known vendor with No GDPR",
+			bidderName:          bidderBlockedByConsent,
+			userSyncIfAmbiguous: false,
+			gdpr:                SignalNo,
+			consent:             consent,
+			allowPI:             true,
+		},
+		{
+			description:         "Allow PI - known vendor with Yes GDPR",
+			bidderName:          bidderAllowedByConsent,
+			userSyncIfAmbiguous: false,
+			gdpr:                SignalYes,
+			consent:             consent,
+			allowPI:             true,
+		},
+		{
+			description:         "PI allowed according to host setting UserSyncIfAmbiguous true - known vendor with ambiguous GDPR and empty consent",
+			bidderName:          bidderAllowedByConsent,
+			userSyncIfAmbiguous: true,
+			gdpr:                SignalAmbiguous,
+			consent:             "",
+			allowPI:             true,
+		},
+		{
+			description:         "PI allowed according to host setting UserSyncIfAmbiguous true - known vendor with ambiguous GDPR and non-empty consent",
+			bidderName:          bidderAllowedByConsent,
+			userSyncIfAmbiguous: true,
+			gdpr:                SignalAmbiguous,
+			consent:             consent,
+			allowPI:             true,
+		},
+		{
+			description:         "PI allowed according to host setting UserSyncIfAmbiguous false - known vendor with ambiguous GDPR and empty consent",
+			bidderName:          bidderAllowedByConsent,
+			userSyncIfAmbiguous: false,
+			gdpr:                SignalAmbiguous,
+			consent:             "",
+			allowPI:             false,
+		},
+		{
+			description:         "PI allowed according to host setting UserSyncIfAmbiguous false - known vendor with ambiguous GDPR and non-empty consent",
+			bidderName:          bidderAllowedByConsent,
+			userSyncIfAmbiguous: false,
+			gdpr:                SignalAmbiguous,
+			consent:             consent,
+			allowPI:             true,
+		},
+		{
+			description:         "Don't allow PI - known vendor with Yes GDPR and empty consent",
+			bidderName:          bidderAllowedByConsent,
+			userSyncIfAmbiguous: false,
+			gdpr:                SignalYes,
+			consent:             "",
+			allowPI:             false,
+		},
+		{
+			description:         "Don't allow PI - default vendor with Yes GDPR and non-empty consent",
+			bidderName:          bidderBlockedByConsent,
+			userSyncIfAmbiguous: false,
+			gdpr:                SignalYes,
+			consent:             consent,
+			allowPI:             false,
+		},
+	}
+
 	vendorListData := tcf1MarshalVendorList(tcf1VendorList{
 		VendorListVersion: 1,
 		Vendors: []tcf1Vendor{
-			{ID: 2, Purposes: []int{1}},    // cookie reads/writes
-			{ID: 3, Purposes: []int{1, 3}}, // ad personalization
+			{ID: 2, Purposes: []int{1, 3}},
 		},
 	})
 	perms := permissionsImpl{
 		cfg: config.GDPR{
-			HostVendorID: 2,
+			HostVendorID:            2,
+			NonStandardPublisherMap: map[string]struct{}{"appNexusAppID": {}},
 		},
 		vendorIDs: map[openrtb_ext.BidderName]uint16{
 			openrtb_ext.BidderAppnexus: 2,
-			openrtb_ext.BidderPubmatic: 3,
 		},
 		fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){
 			tcf1SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{
@@ -202,20 +289,14 @@ func TestAllowPersonalInfo(t *testing.T) {
 		},
 	}
 
-	// PI needs both purposes to succeed
-	allowPI, _, _, err := perms.PersonalInfoAllowed(context.Background(), openrtb_ext.BidderAppnexus, "", "BOS2bx5OS2bx5ABABBAAABoAAAABBwAA")
-	assertNilErr(t, err)
-	assertBoolsEqual(t, false, allowPI)
+	for _, tt := range tests {
+		perms.cfg.UsersyncIfAmbiguous = tt.userSyncIfAmbiguous
 
-	allowPI, _, _, err = perms.PersonalInfoAllowed(context.Background(), openrtb_ext.BidderPubmatic, "", "BOS2bx5OS2bx5ABABBAAABoAAAABBwAA")
-	assertNilErr(t, err)
-	assertBoolsEqual(t, true, allowPI)
+		allowPI, _, _, err := perms.PersonalInfoAllowed(context.Background(), tt.bidderName, tt.publisherID, tt.gdpr, tt.consent)
 
-	// Assert that an item that otherwise would not be allowed PI access, gets approved because it is found in the GDPR.NonStandardPublishers array
-	perms.cfg.NonStandardPublisherMap = map[string]struct{}{"appNexusAppID": {}}
-	allowPI, _, _, err = perms.PersonalInfoAllowed(context.Background(), openrtb_ext.BidderAppnexus, "appNexusAppID", "BOS2bx5OS2bx5ABABBAAABoAAAABBwAA")
-	assertNilErr(t, err)
-	assertBoolsEqual(t, true, allowPI)
+		assert.Nil(t, err, tt.description)
+		assert.Equal(t, tt.allowPI, allowPI, tt.description)
+	}
 }
 
 func buildTCF2VendorList34() tcf2VendorList {
@@ -318,7 +399,7 @@ func TestAllowPersonalInfoTCF2(t *testing.T) {
 	}
 
 	for _, td := range testDefs {
-		allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), td.bidder, "", td.consent)
+		allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), td.bidder, "", SignalYes, td.consent)
 		assert.NoErrorf(t, err, "Error processing PersonalInfoAllowed for %s", td.description)
 		assert.EqualValuesf(t, td.allowPI, allowPI, "AllowPI failure on %s", td.description)
 		assert.EqualValuesf(t, td.allowGeo, allowGeo, "AllowGeo failure on %s", td.description)
@@ -344,7 +425,7 @@ func TestAllowPersonalInfoWhitelistTCF2(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
 	perms.cfg.NonStandardPublisherMap = map[string]struct{}{"appNexusAppID": {}}
-	allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), openrtb_ext.BidderAppnexus, "appNexusAppID", "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA")
+	allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), openrtb_ext.BidderAppnexus, "appNexusAppID", SignalYes, "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA")
 	assert.NoErrorf(t, err, "Error processing PersonalInfoAllowed")
 	assert.EqualValuesf(t, true, allowPI, "AllowPI failure")
 	assert.EqualValuesf(t, true, allowGeo, "AllowGeo failure")
@@ -398,7 +479,7 @@ func TestAllowPersonalInfoTCF2PubRestrict(t *testing.T) {
 	}
 
 	for _, td := range testDefs {
-		allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), td.bidder, "", td.consent)
+		allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), td.bidder, "", SignalYes, td.consent)
 		assert.NoErrorf(t, err, "Error processing PersonalInfoAllowed for %s", td.description)
 		assert.EqualValuesf(t, td.allowPI, allowPI, "AllowPI failure on %s", td.description)
 		assert.EqualValuesf(t, td.allowGeo, allowGeo, "AllowGeo failure on %s", td.description)
@@ -454,7 +535,7 @@ func TestAllowPersonalInfoTCF2PurposeOneTrue(t *testing.T) {
 	}
 
 	for _, td := range testDefs {
-		allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), td.bidder, "", td.consent)
+		allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), td.bidder, "", SignalYes, td.consent)
 		assert.NoErrorf(t, err, "Error processing PersonalInfoAllowed for %s", td.description)
 		assert.EqualValuesf(t, td.allowPI, allowPI, "AllowPI failure on %s", td.description)
 		assert.EqualValuesf(t, td.allowGeo, allowGeo, "AllowGeo failure on %s", td.description)
@@ -511,7 +592,7 @@ func TestAllowPersonalInfoTCF2PurposeOneFalse(t *testing.T) {
 	}
 
 	for _, td := range testDefs {
-		allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), td.bidder, "", td.consent)
+		allowPI, allowGeo, allowID, err := perms.PersonalInfoAllowed(context.Background(), td.bidder, "", SignalYes, td.consent)
 		assert.NoErrorf(t, err, "Error processing PersonalInfoAllowed for %s", td.description)
 		assert.EqualValuesf(t, td.allowPI, allowPI, "AllowPI failure on %s", td.description)
 		assert.EqualValuesf(t, td.allowGeo, allowGeo, "AllowGeo failure on %s", td.description)
diff --git a/privacy/enforcement_test.go b/privacy/enforcement_test.go
index 0cf36a61..9240aafc 100644
--- a/privacy/enforcement_test.go
+++ b/privacy/enforcement_test.go
@@ -59,7 +59,6 @@ func TestApply(t *testing.T) {
 	testCases := []struct {
 		description        string
 		enforcement        Enforcement
-		ampGDPRException   bool
 		expectedDeviceID   ScrubStrategyDeviceID
 		expectedDeviceIPv4 ScrubStrategyIPV4
 		expectedDeviceIPv6 ScrubStrategyIPV6
@@ -124,7 +123,6 @@ func TestApply(t *testing.T) {
 				GDPRID:  true,
 				LMT:     false,
 			},
-			ampGDPRException:   false,
 			expectedDeviceID:   ScrubStrategyDeviceIDAll,
 			expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
@@ -132,23 +130,6 @@ func TestApply(t *testing.T) {
 			expectedUser:       ScrubStrategyUserID,
 			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
 		},
-		{
-			description: "GDPR Only - Full - AMP Exception",
-			enforcement: Enforcement{
-				CCPA:    false,
-				COPPA:   false,
-				GDPRGeo: true,
-				GDPRID:  true,
-				LMT:     false,
-			},
-			ampGDPRException:   true,
-			expectedDeviceID:   ScrubStrategyDeviceIDAll,
-			expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
-			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
-			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
-			expectedUser:       ScrubStrategyUserNone,
-			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
-		},
 		{
 			description: "GDPR Only - ID Only",
 			enforcement: Enforcement{
@@ -158,7 +139,6 @@ func TestApply(t *testing.T) {
 				GDPRID:  true,
 				LMT:     false,
 			},
-			ampGDPRException:   false,
 			expectedDeviceID:   ScrubStrategyDeviceIDAll,
 			expectedDeviceIPv4: ScrubStrategyIPV4None,
 			expectedDeviceIPv6: ScrubStrategyIPV6None,
@@ -166,23 +146,6 @@ func TestApply(t *testing.T) {
 			expectedUser:       ScrubStrategyUserID,
 			expectedUserGeo:    ScrubStrategyGeoNone,
 		},
-		{
-			description: "GDPR Only - ID Only - AMP Exception",
-			enforcement: Enforcement{
-				CCPA:    false,
-				COPPA:   false,
-				GDPRGeo: false,
-				GDPRID:  true,
-				LMT:     false,
-			},
-			ampGDPRException:   true,
-			expectedDeviceID:   ScrubStrategyDeviceIDAll,
-			expectedDeviceIPv4: ScrubStrategyIPV4None,
-			expectedDeviceIPv6: ScrubStrategyIPV6None,
-			expectedDeviceGeo:  ScrubStrategyGeoNone,
-			expectedUser:       ScrubStrategyUserNone,
-			expectedUserGeo:    ScrubStrategyGeoNone,
-		},
 		{
 			description: "GDPR Only - Geo Only",
 			enforcement: Enforcement{
@@ -192,7 +155,6 @@ func TestApply(t *testing.T) {
 				GDPRID:  false,
 				LMT:     false,
 			},
-			ampGDPRException:   false,
 			expectedDeviceID:   ScrubStrategyDeviceIDNone,
 			expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
@@ -217,24 +179,7 @@ func TestApply(t *testing.T) {
 			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
 		},
 		{
-			description: "Interactions: COPPA Only + AMP Exception",
-			enforcement: Enforcement{
-				CCPA:    false,
-				COPPA:   true,
-				GDPRGeo: false,
-				GDPRID:  false,
-				LMT:     false,
-			},
-			ampGDPRException:   true,
-			expectedDeviceID:   ScrubStrategyDeviceIDAll,
-			expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
-			expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
-			expectedDeviceGeo:  ScrubStrategyGeoFull,
-			expectedUser:       ScrubStrategyUserIDAndDemographic,
-			expectedUserGeo:    ScrubStrategyGeoFull,
-		},
-		{
-			description: "Interactions: COPPA + GDPR Full + AMP Exception",
+			description: "Interactions: COPPA + GDPR Full",
 			enforcement: Enforcement{
 				CCPA:    false,
 				COPPA:   true,
@@ -242,7 +187,6 @@ func TestApply(t *testing.T) {
 				GDPRID:  true,
 				LMT:     false,
 			},
-			ampGDPRException:   true,
 			expectedDeviceID:   ScrubStrategyDeviceIDAll,
 			expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
@@ -264,7 +208,7 @@ func TestApply(t *testing.T) {
 		m.On("ScrubDevice", req.Device, test.expectedDeviceID, test.expectedDeviceIPv4, test.expectedDeviceIPv6, test.expectedDeviceGeo).Return(replacedDevice).Once()
 		m.On("ScrubUser", req.User, test.expectedUser, test.expectedUserGeo).Return(replacedUser).Once()
 
-		test.enforcement.apply(req, test.ampGDPRException, m)
+		test.enforcement.apply(req, m)
 
 		m.AssertExpectations(t)
 		assert.Same(t, replacedDevice, req.Device, "Device")
@@ -284,7 +228,7 @@ func TestApplyNoneApplicable(t *testing.T) {
 		GDPRID:  false,
 		LMT:     false,
 	}
-	enforcement.apply(req, false, m)
+	enforcement.apply(req, m)
 
 	m.AssertNotCalled(t, "ScrubDevice")
 	m.AssertNotCalled(t, "ScrubUser")
@@ -294,7 +238,7 @@ func TestApplyNil(t *testing.T) {
 	m := &mockScrubber{}
 
 	enforcement := Enforcement{}
-	enforcement.apply(nil, false, m)
+	enforcement.apply(nil, m)
 
 	m.AssertNotCalled(t, "ScrubDevice")
 	m.AssertNotCalled(t, "ScrubUser")
diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go
index dc4ca0a6..b6acbb4d 100755
--- a/usersync/usersyncers/syncer_test.go
+++ b/usersync/usersyncers/syncer_test.go
@@ -59,6 +59,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderLogicad):          syncConfig,
 			string(openrtb_ext.BidderLunaMedia):        syncConfig,
 			string(openrtb_ext.BidderMarsmedia):        syncConfig,
+			string(openrtb_ext.BidderMediafuse):        syncConfig,
 			string(openrtb_ext.BidderMgid):             syncConfig,
 			string(openrtb_ext.BidderNanoInteractive):  syncConfig,
 			string(openrtb_ext.BidderNinthDecimal):     syncConfig,
@@ -97,10 +98,12 @@ func TestNewSyncerMap(t *testing.T) {
 		openrtb_ext.BidderAdgeneration: true,
 		openrtb_ext.BidderAdhese:       true,
 		openrtb_ext.BidderAdoppler:     true,
+		openrtb_ext.BidderAdot:         true,
 		openrtb_ext.BidderApplogy:      true,
 		openrtb_ext.BidderInMobi:       true,
 		openrtb_ext.BidderKidoz:        true,
 		openrtb_ext.BidderKubient:      true,
+		openrtb_ext.BidderMobfoxpb:     true,
 		openrtb_ext.BidderMobileFuse:   true,
 		openrtb_ext.BidderOrbidder:     true,
 		openrtb_ext.BidderPubnative:    true,