Repository: prebid/prebid-server
Pull request #1656 (2021-01-14 21:23:53)

Always sync when GDPR globally enabled and allow host cookie sync …
…when host vendor ID is 0


Patch:
diff --git a/adapters/beachfront/beachfront.go b/adapters/beachfront/beachfront.go
index 72c0ef4b..1f81eda0 100644
--- a/adapters/beachfront/beachfront.go
+++ b/adapters/beachfront/beachfront.go
@@ -24,7 +24,7 @@ const defaultVideoEndpoint = "https://reachms.bfmio.com/bid.json?exchange_id"
 const nurlVideoEndpointSuffix = "&prebidserver"
 
 const beachfrontAdapterName = "BF_PREBID_S2S"
-const beachfrontAdapterVersion = "0.9.0"
+const beachfrontAdapterVersion = "0.9.1"
 
 const minBidFloor = 0.01
 
@@ -202,8 +202,8 @@ func preprocess(request *openrtb.BidRequest) (beachfrontReqs beachfrontRequests,
 	var bannerImps = make([]openrtb.Imp, 0)
 
 	for i := 0; i < len(request.Imp); i++ {
-		if request.Imp[i].Banner != nil && ((request.Imp[i].Banner.Format[0].H != 0 && request.Imp[i].Banner.Format[0].W != 0) ||
-			(request.Imp[i].Banner.H != nil && request.Imp[i].Banner.W != nil)) {
+		if request.Imp[i].Banner != nil && request.Imp[i].Banner.Format != nil &&
+			request.Imp[i].Banner.Format[0].H != 0 && request.Imp[i].Banner.Format[0].W != 0 {
 			bannerImps = append(bannerImps, request.Imp[i])
 		}
 
@@ -232,11 +232,11 @@ func preprocess(request *openrtb.BidRequest) (beachfrontReqs beachfrontRequests,
 		errs = append(errs, videoErrs...)
 
 		for i := 0; i < len(videoList); i++ {
-			if videoList[i].VideoResponseType == "nurl" || videoList[i].VideoResponseType == "both" {
+			if videoList[i].VideoResponseType == "nurl" {
 				beachfrontReqs.NurlVideo = append(beachfrontReqs.NurlVideo, videoList[i])
 			}
 
-			if videoList[i].VideoResponseType == "adm" || videoList[i].VideoResponseType == "both" {
+			if videoList[i].VideoResponseType == "adm" {
 				beachfrontReqs.ADMVideo = append(beachfrontReqs.ADMVideo, videoList[i])
 			}
 		}
@@ -412,7 +412,7 @@ func getVideoRequests(request *openrtb.BidRequest) ([]beachfrontVideoRequest, []
 		if beachfrontExt.VideoResponseType != "" {
 			bfReqs[i].VideoResponseType = beachfrontExt.VideoResponseType
 		} else {
-			bfReqs[i].VideoResponseType = "nurl"
+			bfReqs[i].VideoResponseType = "adm"
 		}
 
 		bfReqs[i].Request = *request
@@ -436,7 +436,7 @@ func getVideoRequests(request *openrtb.BidRequest) ([]beachfrontVideoRequest, []
 
 		}
 
-		if bfReqs[i].Request.Device.DeviceType == 0 {
+		if bfReqs[i].Request.Device != nil && bfReqs[i].Request.Device.DeviceType == 0 {
 			// More fine graned deviceType methods will be added in the future
 			bfReqs[i].Request.Device.DeviceType = fallBackDeviceType(request)
 		}
diff --git a/adapters/emx_digital/emx_digital.go b/adapters/emx_digital/emx_digital.go
index a219481c..e87f0681 100644
--- a/adapters/emx_digital/emx_digital.go
+++ b/adapters/emx_digital/emx_digital.go
@@ -152,8 +152,10 @@ func buildImpVideo(imp *openrtb.Imp) error {
 		}
 	}
 
-	if imp.Video.Protocols != nil {
-		imp.Video.Protocols = cleanProtocol(imp.Video.Protocols)
+	if len(imp.Video.Protocols) > 0 {
+		videoCopy := *imp.Video
+		videoCopy.Protocols = cleanProtocol(imp.Video.Protocols)
+		imp.Video = &videoCopy
 	}
 
 	return nil
diff --git a/config/config.go b/config/config.go
index d1186688..6577c1fb 100755
--- a/config/config.go
+++ b/config/config.go
@@ -216,6 +216,9 @@ func (cfg *GDPR) validate(errs []error) []error {
 	if cfg.AMPException == true {
 		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)"))
 	}
+	if cfg.TCF1.FetchGVL == true {
+		glog.Warning("gdpr.tcf1.fetch_gvl is deprecated and will be removed in a future version, at which point TCF1 will always use the fallback GVL")
+	}
 	return errs
 }
 
@@ -234,7 +237,7 @@ func (t *GDPRTimeouts) ActiveTimeout() time.Duration {
 
 // TCF1 defines the TCF1 specific configurations for GDPR
 type TCF1 struct {
-	FetchGVL        bool   `mapstructure:"fetch_gvl"`
+	FetchGVL        bool   `mapstructure:"fetch_gvl"` // Deprecated: In a future version TCF1 will always use the fallback GVL
 	FallbackGVLPath string `mapstructure:"fallback_gvl_path"`
 }
 
diff --git a/endpoints/events/vtrack.go b/endpoints/events/vtrack.go
index c4051554..9a4d9c08 100644
--- a/endpoints/events/vtrack.go
+++ b/endpoints/events/vtrack.go
@@ -4,6 +4,12 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"strings"
+	"time"
+
 	"github.com/golang/glog"
 	"github.com/julienschmidt/httprouter"
 	accountService "github.com/prebid/prebid-server/account"
@@ -13,12 +19,6 @@ import (
 	"github.com/prebid/prebid-server/errortypes"
 	"github.com/prebid/prebid-server/prebid_cache_client"
 	"github.com/prebid/prebid-server/stored_requests"
-	"io"
-	"io/ioutil"
-	"net/http"
-	"sort"
-	"strings"
-	"time"
 )
 
 const (
@@ -230,7 +230,7 @@ func (v *vtrackEndpoint) cachePutObjects(ctx context.Context, req *BidCacheReque
 		}
 
 		if _, ok := biddersAllowingVastUpdate[c.Bidder]; ok && nc.Data != nil {
-			nc.Data = modifyVastXml(v.Cfg.ExternalURL, nc.Data, c.BidID, c.Bidder, accountId, c.Timestamp)
+			nc.Data = ModifyVastXmlJSON(v.Cfg.ExternalURL, nc.Data, c.BidID, c.Bidder, accountId, c.Timestamp)
 		}
 
 		cacheables = append(cacheables, *nc)
@@ -269,32 +269,36 @@ func getAccountId(httpRequest *http.Request) string {
 	return httpRequest.URL.Query().Get(AccountParameter)
 }
 
-// modifyVastXml modifies BidCacheRequest element Vast XML data
-func modifyVastXml(externalUrl string, data json.RawMessage, bidid string, bidder string, accountId string, timestamp int64) json.RawMessage {
-	c := string(data)
-	ci := strings.Index(c, ImpressionCloseTag)
+// ModifyVastXmlString rewrites and returns the string vastXML and a flag indicating if it was modified
+func ModifyVastXmlString(externalUrl, vast, bidid, bidder, accountID string, timestamp int64) (string, bool) {
+	ci := strings.Index(vast, ImpressionCloseTag)
 
 	// no impression tag - pass it as it is
 	if ci == -1 {
-		return data
+		return vast, false
 	}
 
-	vastUrlTracking := GetVastUrlTracking(externalUrl, bidid, bidder, accountId, timestamp)
+	vastUrlTracking := GetVastUrlTracking(externalUrl, bidid, bidder, accountID, timestamp)
 	impressionUrl := "<![CDATA[" + vastUrlTracking + "]]>"
-	oi := strings.Index(c, ImpressionOpenTag)
+	oi := strings.Index(vast, ImpressionOpenTag)
 
 	if ci-oi == len(ImpressionOpenTag) {
-		return json.RawMessage(strings.Replace(c, ImpressionOpenTag, ImpressionOpenTag+impressionUrl, 1))
+		return strings.Replace(vast, ImpressionOpenTag, ImpressionOpenTag+impressionUrl, 1), true
 	}
 
-	return json.RawMessage(strings.Replace(c, ImpressionCloseTag, ImpressionCloseTag+ImpressionOpenTag+impressionUrl+ImpressionCloseTag, 1))
+	return strings.Replace(vast, ImpressionCloseTag, ImpressionCloseTag+ImpressionOpenTag+impressionUrl+ImpressionCloseTag, 1), true
 }
 
-func contains(s []string, e string) bool {
-	if len(s) == 0 {
-		return false
+// ModifyVastXmlJSON modifies BidCacheRequest element Vast XML data
+func ModifyVastXmlJSON(externalUrl string, data json.RawMessage, bidid, bidder, accountId string, timestamp int64) json.RawMessage {
+	var vast string
+	if err := json.Unmarshal(data, &vast); err != nil {
+		// failed to decode json, fall back to string
+		vast = string(data)
 	}
-
-	i := sort.SearchStrings(s, e)
-	return i < len(s) && s[i] == e
+	vast, ok := ModifyVastXmlString(externalUrl, vast, bidid, bidder, accountId, timestamp)
+	if !ok {
+		return data
+	}
+	return json.RawMessage(vast)
 }
diff --git a/exchange/auction.go b/exchange/auction.go
index aa36feb2..97f82d3c 100644
--- a/exchange/auction.go
+++ b/exchange/auction.go
@@ -147,7 +147,7 @@ func (a *auction) setRoundedPrices(priceGranularity openrtb_ext.PriceGranularity
 	a.roundedPrices = roundedPrices
 }
 
-func (a *auction) doCache(ctx context.Context, cache prebid_cache_client.Client, targData *targetData, bidRequest *openrtb.BidRequest, ttlBuffer int64, defaultTTLs *config.DefaultTTLs, bidCategory map[string]string, debugLog *DebugLog) []error {
+func (a *auction) doCache(ctx context.Context, cache prebid_cache_client.Client, targData *targetData, evTracking *eventTracking, bidRequest *openrtb.BidRequest, ttlBuffer int64, defaultTTLs *config.DefaultTTLs, bidCategory map[string]string, debugLog *DebugLog) []error {
 	var bids, vast, includeBidderKeys, includeWinners bool = targData.includeCacheBids, targData.includeCacheVast, targData.includeBidderKeys, targData.includeWinners
 	if !((bids || vast) && (includeBidderKeys || includeWinners)) {
 		return nil
@@ -176,7 +176,7 @@ func (a *auction) doCache(ctx context.Context, cache prebid_cache_client.Client,
 		expByImp[imp.ID] = imp.Exp
 	}
 	for _, topBidsPerImp := range a.winningBidsByBidder {
-		for _, topBidPerBidder := range topBidsPerImp {
+		for bidderName, topBidPerBidder := range topBidsPerImp {
 			impID := topBidPerBidder.bid.ImpID
 			isOverallWinner := a.winningBids[impID] == topBidPerBidder
 			if !includeBidderKeys && !isOverallWinner {
@@ -195,6 +195,10 @@ func (a *auction) doCache(ctx context.Context, cache prebid_cache_client.Client,
 			}
 			if bids {
 				if jsonBytes, err := json.Marshal(topBidPerBidder.bid); err == nil {
+					jsonBytes, err = evTracking.modifyBidJSON(topBidPerBidder, bidderName, jsonBytes)
+					if err != nil {
+						errs = append(errs, err)
+					}
 					if useCustomCacheKey {
 						// not allowed if bids is true; log error and cache normally
 						errs = append(errs, errors.New("cannot use custom cache key for non-vast bids"))
@@ -210,8 +214,8 @@ func (a *auction) doCache(ctx context.Context, cache prebid_cache_client.Client,
 				}
 			}
 			if vast && topBidPerBidder.bidType == openrtb_ext.BidTypeVideo {
-				vast := makeVAST(topBidPerBidder.bid)
-				if jsonBytes, err := json.Marshal(vast); err == nil {
+				vastXML := makeVAST(topBidPerBidder.bid)
+				if jsonBytes, err := json.Marshal(vastXML); err == nil {
 					if useCustomCacheKey {
 						toCache = append(toCache, prebid_cache_client.Cacheable{
 							Type:       prebid_cache_client.TypeXML,
diff --git a/exchange/bidder.go b/exchange/bidder.go
index c59d2b4f..e4867b0e 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -58,6 +58,7 @@ type adaptedBidder interface {
 // pbsOrtbBid.bidType will become "response.seatbid[i].bid.ext.prebid.type" in the final OpenRTB response.
 // pbsOrtbBid.bidTargets does not need to be filled out by the Bidder. It will be set later by the exchange.
 // pbsOrtbBid.bidVideo is optional but should be filled out by the Bidder if bidType is video.
+// pbsOrtbBid.bidEvents is set by exchange when event tracking is enabled
 // pbsOrtbBid.dealPriority is optionally provided by adapters and used internally by the exchange to support deal targeted campaigns.
 // pbsOrtbBid.dealTierSatisfied is set to true by exchange.updateHbPbCatDur if deal tier satisfied otherwise it will be set to false
 type pbsOrtbBid struct {
@@ -65,6 +66,7 @@ type pbsOrtbBid struct {
 	bidType           openrtb_ext.BidType
 	bidTargets        map[string]string
 	bidVideo          *openrtb_ext.ExtBidPrebidVideo
+	bidEvents         *openrtb_ext.ExtBidPrebidEvents
 	dealPriority      int
 	dealTierSatisfied bool
 }
diff --git a/exchange/events.go b/exchange/events.go
new file mode 100644
index 00000000..3a05e098
--- /dev/null
+++ b/exchange/events.go
@@ -0,0 +1,115 @@
+package exchange
+
+import (
+	"encoding/json"
+	"time"
+
+	jsonpatch "github.com/evanphx/json-patch"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/analytics"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/endpoints/events"
+	"github.com/prebid/prebid-server/metrics"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// eventTracking has configuration fields needed for adding event tracking to an auction response
+type eventTracking struct {
+	accountID          string
+	enabledForAccount  bool
+	enabledForRequest  bool
+	auctionTimestampMs int64
+	integration        metrics.DemandSource // web app amp
+	bidderInfos        adapters.BidderInfos
+	externalURL        string
+}
+
+// getEventTracking creates an eventTracking object from the different configuration sources
+func getEventTracking(requestExtPrebid *openrtb_ext.ExtRequestPrebid, ts time.Time, account *config.Account, bidderInfos adapters.BidderInfos, externalURL string) *eventTracking {
+	return &eventTracking{
+		accountID:          account.ID,
+		enabledForAccount:  account.EventsEnabled,
+		enabledForRequest:  requestExtPrebid != nil && requestExtPrebid.Events != nil,
+		auctionTimestampMs: ts.UnixNano() / 1e+6,
+		integration:        "", // TODO: add integration support, see #1428
+		bidderInfos:        bidderInfos,
+		externalURL:        externalURL,
+	}
+}
+
+// modifyBidsForEvents adds bidEvents and modifies VAST AdM if necessary.
+func (ev *eventTracking) modifyBidsForEvents(seatBids map[openrtb_ext.BidderName]*pbsOrtbSeatBid) map[openrtb_ext.BidderName]*pbsOrtbSeatBid {
+	for bidderName, seatBid := range seatBids {
+		modifyingVastXMLAllowed := ev.isModifyingVASTXMLAllowed(bidderName.String())
+		for _, pbsBid := range seatBid.bids {
+			if modifyingVastXMLAllowed {
+				ev.modifyBidVAST(pbsBid, bidderName)
+			}
+			pbsBid.bidEvents = ev.makeBidExtEvents(pbsBid, bidderName)
+		}
+	}
+	return seatBids
+}
+
+// isModifyingVASTXMLAllowed returns true if this bidder config allows modifying VAST XML for event tracking
+func (ev *eventTracking) isModifyingVASTXMLAllowed(bidderName string) bool {
+	return ev.bidderInfos[bidderName].ModifyingVastXmlAllowed && (ev.enabledForAccount || ev.enabledForRequest)
+}
+
+// modifyBidVAST injects event Impression url if needed, otherwise returns original VAST string
+func (ev *eventTracking) modifyBidVAST(pbsBid *pbsOrtbBid, bidderName openrtb_ext.BidderName) {
+	bid := pbsBid.bid
+	if pbsBid.bidType != openrtb_ext.BidTypeVideo || len(bid.AdM) == 0 && len(bid.NURL) == 0 {
+		return
+	}
+	vastXML := makeVAST(bid)
+	if newVastXML, ok := events.ModifyVastXmlString(ev.externalURL, vastXML, bid.ID, bidderName.String(), ev.accountID, ev.auctionTimestampMs); ok {
+		bid.AdM = newVastXML
+	}
+}
+
+// modifyBidJSON injects "wurl" (win) event url if needed, otherwise returns original json
+func (ev *eventTracking) modifyBidJSON(pbsBid *pbsOrtbBid, bidderName openrtb_ext.BidderName, jsonBytes []byte) ([]byte, error) {
+	if !(ev.enabledForAccount || ev.enabledForRequest) || pbsBid.bidType == openrtb_ext.BidTypeVideo {
+		return jsonBytes, nil
+	}
+	var winEventURL string
+	if pbsBid.bidEvents != nil { // All bids should have already been updated with win/imp event URLs
+		winEventURL = pbsBid.bidEvents.Win
+	} else {
+		winEventURL = ev.makeEventURL(analytics.Win, pbsBid, bidderName)
+	}
+	// wurl attribute is not in the schema, so we have to patch
+	patch, err := json.Marshal(map[string]string{"wurl": winEventURL})
+	if err != nil {
+		return jsonBytes, err
+	}
+	modifiedJSON, err := jsonpatch.MergePatch(jsonBytes, patch)
+	if err != nil {
+		return jsonBytes, err
+	}
+	return modifiedJSON, nil
+}
+
+// makeBidExtEvents make the data for bid.ext.prebid.events if needed, otherwise returns nil
+func (ev *eventTracking) makeBidExtEvents(pbsBid *pbsOrtbBid, bidderName openrtb_ext.BidderName) *openrtb_ext.ExtBidPrebidEvents {
+	if !(ev.enabledForAccount || ev.enabledForRequest) || pbsBid.bidType == openrtb_ext.BidTypeVideo {
+		return nil
+	}
+	return &openrtb_ext.ExtBidPrebidEvents{
+		Win: ev.makeEventURL(analytics.Win, pbsBid, bidderName),
+		Imp: ev.makeEventURL(analytics.Imp, pbsBid, bidderName),
+	}
+}
+
+// makeEventURL returns an analytics event url for the requested type (win or imp)
+func (ev *eventTracking) makeEventURL(evType analytics.EventType, pbsBid *pbsOrtbBid, bidderName openrtb_ext.BidderName) string {
+	return events.EventRequestToUrl(ev.externalURL,
+		&analytics.EventRequest{
+			Type:      evType,
+			BidID:     pbsBid.bid.ID,
+			Bidder:    string(bidderName),
+			AccountID: ev.accountID,
+			Timestamp: ev.auctionTimestampMs,
+		})
+}
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 1bd7e61e..99ac8a88 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -52,11 +52,13 @@ type IdFetcher interface {
 
 type exchange struct {
 	adapterMap          map[openrtb_ext.BidderName]adaptedBidder
+	bidderInfo          adapters.BidderInfos
 	me                  metrics.MetricsEngine
 	cache               prebid_cache_client.Client
 	cacheTime           time.Duration
 	gDPR                gdpr.Permissions
 	currencyConverter   *currency.RateConverter
+	externalURL         string
 	UsersyncIfAmbiguous bool
 	privacyConfig       config.Privacy
 	categoriesFetcher   stored_requests.CategoryFetcher
@@ -77,13 +79,15 @@ type bidResponseWrapper struct {
 	bidder       openrtb_ext.BidderName
 }
 
-func NewExchange(adapters map[openrtb_ext.BidderName]adaptedBidder, cache prebid_cache_client.Client, cfg *config.Configuration, metricsEngine metrics.MetricsEngine, gDPR gdpr.Permissions, currencyConverter *currency.RateConverter, categoriesFetcher stored_requests.CategoryFetcher) Exchange {
+func NewExchange(adapters map[openrtb_ext.BidderName]adaptedBidder, cache prebid_cache_client.Client, cfg *config.Configuration, metricsEngine metrics.MetricsEngine, infos adapters.BidderInfos, gDPR gdpr.Permissions, currencyConverter *currency.RateConverter, categoriesFetcher stored_requests.CategoryFetcher) Exchange {
 	return &exchange{
 		adapterMap:          adapters,
+		bidderInfo:          infos,
 		cache:               cache,
 		cacheTime:           time.Duration(cfg.CacheURL.ExpectedTimeMillis) * time.Millisecond,
 		categoriesFetcher:   categoriesFetcher,
 		currencyConverter:   currencyConverter,
+		externalURL:         cfg.ExternalURL,
 		gDPR:                gDPR,
 		me:                  metricsEngine,
 		UsersyncIfAmbiguous: cfg.GDPR.UsersyncIfAmbiguous,
@@ -178,6 +182,9 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
 			}
 		}
 
+		evTracking := getEventTracking(&requestExt.Prebid, r.StartTime, &r.Account, e.bidderInfo, e.externalURL)
+		adapterBids = evTracking.modifyBidsForEvents(adapterBids)
+
 		if targData != nil {
 			// A non-nil auction is only needed if targeting is active. (It is used below this block to extract cache keys)
 			auc = newAuction(adapterBids, len(r.BidRequest.Imp), targData.preferDeals)
@@ -187,8 +194,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
 				dealErrs := applyDealSupport(r.BidRequest, auc, bidCategory)
 				errs = append(errs, dealErrs...)
 			}
-
-			cacheErrs := auc.doCache(ctx, e.cache, targData, r.BidRequest, 60, &r.Account.CacheTTL, bidCategory, debugLog)
+			cacheErrs := auc.doCache(ctx, e.cache, targData, evTracking, r.BidRequest, 60, &r.Account.CacheTTL, bidCategory, debugLog)
 			if len(cacheErrs) > 0 {
 				errs = append(errs, cacheErrs...)
 			}
@@ -813,6 +819,7 @@ func (e *exchange) makeBid(Bids []*pbsOrtbBid, auc *auction, returnCreative bool
 				Targeting:         thisBid.bidTargets,
 				Type:              thisBid.bidType,
 				Video:             thisBid.bidVideo,
+				Events:            thisBid.bidEvents,
 				DealPriority:      thisBid.dealPriority,
 				DealTierSatisfied: thisBid.dealTierSatisfied,
 			},
diff --git a/exchange/gdpr.go b/exchange/gdpr.go
index f464cac2..e861f948 100644
--- a/exchange/gdpr.go
+++ b/exchange/gdpr.go
@@ -8,24 +8,22 @@ import (
 )
 
 // ExtractGDPR will pull the gdpr flag from an openrtb request
-func extractGDPR(bidRequest *openrtb.BidRequest) gdpr.Signal {
+func extractGDPR(bidRequest *openrtb.BidRequest) (gdpr.Signal, error) {
 	var re regsExt
 	var err error
-	if bidRequest.Regs != nil {
+	if bidRequest.Regs != nil && bidRequest.Regs.Ext != nil {
 		err = json.Unmarshal(bidRequest.Regs.Ext, &re)
 	}
 	if re.GDPR == nil || err != nil {
-		return gdpr.SignalAmbiguous
-	} else {
-		return gdpr.Signal(*re.GDPR)
+		return gdpr.SignalAmbiguous, err
 	}
+	return gdpr.Signal(*re.GDPR), nil
 }
 
 // ExtractConsent will pull the consent string from an openrtb request
-func extractConsent(bidRequest *openrtb.BidRequest) (consent string) {
+func extractConsent(bidRequest *openrtb.BidRequest) (consent string, err error) {
 	var ue userExt
-	var err error
-	if bidRequest.User != nil {
+	if bidRequest.User != nil && bidRequest.User.Ext != nil {
 		err = json.Unmarshal(bidRequest.User.Ext, &ue)
 	}
 	if err != nil {
diff --git a/exchange/utils.go b/exchange/utils.go
index af4dfb05..8d4c0fac 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -75,14 +75,19 @@ func cleanOpenRTBRequests(ctx context.Context,
 		return
 	}
 
-	gdprSignal := extractGDPR(req.BidRequest)
-	consent := extractConsent(req.BidRequest)
+	gdprSignal, err := extractGDPR(req.BidRequest)
+	if err != nil {
+		errs = append(errs, err)
+	}
+	consent, err := extractConsent(req.BidRequest)
+	if err != nil {
+		errs = append(errs, err)
+	}
 	gdprEnforced := gdprSignal == gdpr.SignalYes || (gdprSignal == gdpr.SignalAmbiguous && !usersyncIfAmbiguous)
 
 	ccpaEnforcer, err := extractCCPA(req.BidRequest, privacyConfig, &req.Account, aliases, integrationTypeMap[req.LegacyLabels.RType])
 	if err != nil {
 		errs = append(errs, err)
-		return
 	}
 
 	lmtEnforcer := extractLMT(req.BidRequest, privacyConfig)
diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go
index eea7fa5a..bfc238e1 100644
--- a/gdpr/gdpr.go
+++ b/gdpr/gdpr.go
@@ -34,18 +34,25 @@ const (
 
 // NewPermissions gets an instance of the Permissions for use elsewhere in the project.
 func NewPermissions(ctx context.Context, cfg config.GDPR, vendorIDs map[openrtb_ext.BidderName]uint16, client *http.Client) Permissions {
-	// If the host doesn't buy into the IAB GDPR consent framework, then save some cycles and let all syncs happen.
-	if cfg.HostVendorID == 0 {
-		return AlwaysAllow{}
+	if !cfg.Enabled {
+		return &AlwaysAllow{}
 	}
 
-	return &permissionsImpl{
+	permissionsImpl := &permissionsImpl{
 		cfg:       cfg,
 		vendorIDs: vendorIDs,
 		fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){
 			tcf1SpecVersion: newVendorListFetcher(ctx, cfg, client, vendorListURLMaker, tcf1SpecVersion),
 			tcf2SpecVersion: newVendorListFetcher(ctx, cfg, client, vendorListURLMaker, tcf2SpecVersion)},
 	}
+
+	if cfg.HostVendorID == 0 {
+		return &AllowHostCookies{
+			permissionsImpl: permissionsImpl,
+		}
+	}
+
+	return permissionsImpl
 }
 
 // An ErrorMalformedConsent will be returned by the Permissions interface if
diff --git a/gdpr/impl.go b/gdpr/impl.go
index e1822ece..c7998251 100644
--- a/gdpr/impl.go
+++ b/gdpr/impl.go
@@ -223,6 +223,16 @@ func (p *permissionsImpl) parseVendor(ctx context.Context, vendorID uint16, cons
 	return
 }
 
+// AllowHostCookies represents a GDPR permissions policy with host cookie syncing always allowed
+type AllowHostCookies struct {
+	*permissionsImpl
+}
+
+// HostCookiesAllowed always returns true
+func (p *AllowHostCookies) HostCookiesAllowed(ctx context.Context, consent string) (bool, error) {
+	return true, nil
+}
+
 // Exporting to allow for easy test setups
 type AlwaysAllow struct{}
 
diff --git a/gdpr/vendorlist-fetching.go b/gdpr/vendorlist-fetching.go
index 66a3f4ad..de6da7b4 100644
--- a/gdpr/vendorlist-fetching.go
+++ b/gdpr/vendorlist-fetching.go
@@ -95,14 +95,14 @@ func preloadCache(ctx context.Context, client *http.Client, urlMaker func(uint16
 func vendorListURLMaker(vendorListVersion uint16, tcfSpecVersion uint8) string {
 	if tcfSpecVersion == tcf2SpecVersion {
 		if vendorListVersion == 0 {
-			return "https://vendorlist.consensu.org/v2/vendor-list.json"
+			return "https://vendor-list.consensu.org/v2/vendor-list.json"
 		}
-		return "https://vendorlist.consensu.org/v2/archives/vendor-list-v" + strconv.Itoa(int(vendorListVersion)) + ".json"
+		return "https://vendor-list.consensu.org/v2/archives/vendor-list-v" + strconv.Itoa(int(vendorListVersion)) + ".json"
 	}
 	if vendorListVersion == 0 {
-		return "https://vendorlist.consensu.org/vendorlist.json"
+		return "https://vendor-list.consensu.org/vendorlist.json"
 	}
-	return "https://vendorlist.consensu.org/v-" + strconv.Itoa(int(vendorListVersion)) + "/vendorlist.json"
+	return "https://vendor-list.consensu.org/v-" + strconv.Itoa(int(vendorListVersion)) + "/vendorlist.json"
 }
 
 // newOccasionalSaver returns a wrapped version of saveOne() which only activates every few minutes.
diff --git a/openrtb_ext/bid.go b/openrtb_ext/bid.go
index e500ab00..8f4d7a09 100644
--- a/openrtb_ext/bid.go
+++ b/openrtb_ext/bid.go
@@ -15,13 +15,14 @@ type ExtBid struct {
 // DealPriority represents priority of deal bid. If its non deal bid then value will be 0
 // DealTierSatisfied true represents corresponding bid has satisfied the deal tier
 type ExtBidPrebid struct {
-	Cache             *ExtBidPrebidCache `json:"cache,omitempty"`
-	DealPriority      int                `json:"dealpriority,omitempty"`
-	DealTierSatisfied bool               `json:"dealtiersatisfied,omitempty"`
-	Meta              *ExtBidPrebidMeta  `json:"meta,omitempty"`
-	Targeting         map[string]string  `json:"targeting,omitempty"`
-	Type              BidType            `json:"type"`
-	Video             *ExtBidPrebidVideo `json:"video,omitempty"`
+	Cache             *ExtBidPrebidCache  `json:"cache,omitempty"`
+	DealPriority      int                 `json:"dealpriority,omitempty"`
+	DealTierSatisfied bool                `json:"dealtiersatisfied,omitempty"`
+	Meta              *ExtBidPrebidMeta   `json:"meta,omitempty"`
+	Targeting         map[string]string   `json:"targeting,omitempty"`
+	Type              BidType             `json:"type"`
+	Video             *ExtBidPrebidVideo  `json:"video,omitempty"`
+	Events            *ExtBidPrebidEvents `json:"events,omitempty"`
 }
 
 // ExtBidPrebidCache defines the contract for  bidresponse.seatbid.bid[i].ext.prebid.cache
@@ -58,6 +59,12 @@ type ExtBidPrebidVideo struct {
 	PrimaryCategory string `json:"primary_category"`
 }
 
+// ExtBidPrebidEvents defines the contract for bidresponse.seatbid.bid[i].ext.prebid.events
+type ExtBidPrebidEvents struct {
+	Win string `json:"win,omitempty"`
+	Imp string `json:"imp,omitempty"`
+}
+
 // BidType describes the allowed values for bidresponse.seatbid.bid[i].ext.prebid.type
 type BidType string
 
diff --git a/openrtb_ext/request.go b/openrtb_ext/request.go
index 79dc3554..124e050a 100644
--- a/openrtb_ext/request.go
+++ b/openrtb_ext/request.go
@@ -22,6 +22,7 @@ type ExtRequestPrebid struct {
 	Cache                *ExtRequestPrebidCache    `json:"cache,omitempty"`
 	Data                 *ExtRequestPrebidData     `json:"data,omitempty"`
 	Debug                bool                      `json:"debug,omitempty"`
+	Events               json.RawMessage           `json:"events,omitempty"`
 	SChains              []*ExtRequestPrebidSChain `json:"schains,omitempty"`
 	StoredRequest        *ExtStoredRequest         `json:"storedrequest,omitempty"`
 	SupportDeals         bool                      `json:"supportdeals,omitempty"`
diff --git a/router/router.go b/router/router.go
index c398f528..48580f85 100644
--- a/router/router.go
+++ b/router/router.go
@@ -251,7 +251,7 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R
 		glog.Fatalf("%v", errs)
 	}
 
-	theExchange := exchange.NewExchange(adapters, cacheClient, cfg, r.MetricsEngine, gdprPerms, rateConvertor, categoriesFetcher)
+	theExchange := exchange.NewExchange(adapters, cacheClient, cfg, r.MetricsEngine, bidderInfos, gdprPerms, rateConvertor, categoriesFetcher)
 
 	openrtbEndpoint, err := openrtb2.NewEndpoint(theExchange, paramsValidator, fetcher, accounts, cfg, r.MetricsEngine, pbsAnalytics, disabledBidders, defReqJSON, activeBidders)
 	if err != nil {
diff --git a/static/bidder-info/openx.yaml b/static/bidder-info/openx.yaml
index d16a7d73..96ef8616 100644
--- a/static/bidder-info/openx.yaml
+++ b/static/bidder-info/openx.yaml
@@ -9,3 +9,4 @@ capabilities:
     mediaTypes:
       - banner
       - video
+modifyingVastXmlAllowed: true
diff --git a/static/bidder-params/beachfront.json b/static/bidder-params/beachfront.json
index 61490d12..a7751b27 100644
--- a/static/bidder-params/beachfront.json
+++ b/static/bidder-params/beachfront.json
@@ -28,7 +28,7 @@
     },
     "videoResponseType": {
       "type": "string",
-      "description": "By default the video response will be a nurl URL, but if you want AdM/VAST, set this to 'adm'. If you want both set it to 'both'. Setting it to any other string will have no effect and the default format will be returned."
+      "description": "By default the video response will be an AdM element containing VAST 3.0 markup including tracking, click through, and mediafile elements pointing to mp4, webm or other playable media files or Vpaid media as configured for the exchange at beachfront.io. Optionally, set this to 'nurl' to receive a URI pointing to VAST 3.0 markup which will contain a mediafile pointing to a beachfront neptune javascript video player which will load your video and take care of tracking, etc. Regardless of which format is selected, the id of the returned impression will be the provided impression id (imp[{'id'...},...] in the request) with the format appended. The impression id will be returned unchanged as 'impid'. So if you indicate 'nurl', and an impression id 'someImp', the returned impression will have an 'impid' value of 'someImp', and the 'id' value 'someImpNurlVideo'. This is to differentiate the object in the case that a request includes both video and banner elements. Setting videoResponseType to any other string will have no effect and the default format (AdM) will be returned."
     }
   },
 
diff --git a/usersync/usersync.go b/usersync/usersync.go
index 2b313a02..236acbe7 100644
--- a/usersync/usersync.go
+++ b/usersync/usersync.go
@@ -17,7 +17,7 @@ type Usersyncer interface {
 
 	// GDPRVendorID returns the ID in the IAB Global Vendor List which refers to this Bidder.
 	//
-	// The Global Vendor list can be found here: https://vendorlist.consensu.org/vendorlist.json
+	// The Global Vendor list can be found here: https://vendor-list.consensu.org/vendorlist.json
 	// Bidders can register for the list here: https://register.consensu.org/
 	//
 	// If you're not on the list, this should return 0. If cookie sync requests have GDPR consent info,


Test patch:
diff --git a/adapters/beachfront/beachfront_test.go b/adapters/beachfront/beachfront_test.go
index dc51e196..1c1c4ff4 100644
--- a/adapters/beachfront/beachfront_test.go
+++ b/adapters/beachfront/beachfront_test.go
@@ -11,8 +11,8 @@ import (
 
 func TestJsonSamples(t *testing.T) {
 	bidder, buildErr := Builder(openrtb_ext.BidderBeachfront, config.Adapter{
-		Endpoint:         `https://display.bfmio.com/prebid_display`,
-		ExtraAdapterInfo: `{"video_endpoint":"https://reachms.bfmio.com/bid.json?exchange_id"}`,
+		Endpoint:         `https://qa.beachrtb.com/prebid_display`,
+		ExtraAdapterInfo: `{"video_endpoint":"https://qa.beachrtb.com/bid.json?exchange_id"}`,
 	})
 
 	if buildErr != nil {
@@ -24,7 +24,7 @@ func TestJsonSamples(t *testing.T) {
 
 func TestExtraInfoDefaultWhenEmpty(t *testing.T) {
 	bidder, buildErr := Builder(openrtb_ext.BidderBeachfront, config.Adapter{
-		Endpoint:         `https://display.bfmio.com/prebid_display`,
+		Endpoint:         `https://qa.beachrtb.com/prebid_display`,
 		ExtraAdapterInfo: ``,
 	})
 
@@ -39,7 +39,7 @@ func TestExtraInfoDefaultWhenEmpty(t *testing.T) {
 
 func TestExtraInfoDefaultWhenNotSpecified(t *testing.T) {
 	bidder, buildErr := Builder(openrtb_ext.BidderBeachfront, config.Adapter{
-		Endpoint:         `https://display.bfmio.com/prebid_display`,
+		Endpoint:         `https://qa.beachrtb.com/prebid_display`,
 		ExtraAdapterInfo: `{"video_endpoint":""}`,
 	})
 
@@ -54,7 +54,7 @@ func TestExtraInfoDefaultWhenNotSpecified(t *testing.T) {
 
 func TestExtraInfoMalformed(t *testing.T) {
 	_, buildErr := Builder(openrtb_ext.BidderBeachfront, config.Adapter{
-		Endpoint:         `https://display.bfmio.com/prebid_display`,
+		Endpoint:         `https://qa.beachrtb.com/prebid_display`,
 		ExtraAdapterInfo: `malformed`,
 	})
 
diff --git a/adapters/beachfront/beachfronttest/exemplary/adm-video-by-default.json b/adapters/beachfront/beachfronttest/exemplary/adm-video-by-default.json
new file mode 100644
index 00000000..d3fa41a2
--- /dev/null
+++ b/adapters/beachfront/beachfronttest/exemplary/adm-video-by-default.json
@@ -0,0 +1,123 @@
+{
+  "mockBidRequest": {
+    "id": "adm-video",
+    "imp": [
+      {
+        "id": "video1",
+        "ext": {
+          "bidder": {
+            "bidfloor": 3.01,
+            "appId": "videoAppId1"
+          }
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "context": "instream",
+          "w": 300,
+          "h": 250
+        }
+      }
+    ],
+    "site": {
+      "page": "https://some.domain.us/some/page.html"
+    },
+    "device":{
+      "ip":"255.255.255.255"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1",
+        "body": {
+          "id": "adm-video",
+          "imp": [
+            {
+              "video": {
+                "w": 300,
+                "h": 250,
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "bidfloor": 3.01,
+              "id": "video1",
+              "secure": 1
+            }
+          ],
+          "site": {
+            "page": "https://some.domain.us/some/page.html",
+            "domain": "some.domain.us"
+          },
+          "cur": [
+            "USD"
+          ],
+          "device":{
+            "devicetype": 2,
+            "ip":"255.255.255.255"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "adm-video",
+          "seatBid": [
+            {
+              "bid": [
+                {
+                  "id": "5fd7c8a6ff2f1f0d42ee6427",
+                  "impid": "video1",
+                  "price": 20,
+                  "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+                  "adid": "1088",
+                  "adomain": [
+                    "beachfront.io"
+                  ],
+                  "cid": "277",
+                  "crid": "532",
+                  "w": 300,
+                  "h": 250,
+                  "ext": {
+                    "duration": 30
+                  }
+                }
+              ],
+              "seat": "bfio-s-1"
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "video1AdmVideo",
+            "impid": "video1",
+            "price": 20,
+            "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+            "adid": "1088",
+            "adomain": [
+              "beachfront.io"
+            ],
+            "cid": "277",
+            "crid": "532",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "duration": 30
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/beachfront/beachfronttest/exemplary/adm-video-by-explicit-type.json b/adapters/beachfront/beachfronttest/exemplary/adm-video-by-explicit-type.json
new file mode 100644
index 00000000..8c05d65a
--- /dev/null
+++ b/adapters/beachfront/beachfronttest/exemplary/adm-video-by-explicit-type.json
@@ -0,0 +1,124 @@
+{
+  "mockBidRequest": {
+    "id": "adm-video",
+    "imp": [
+      {
+        "id": "video1",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "adm",
+            "bidfloor": 3.01,
+            "appId": "videoAppId1"
+          }
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "context": "instream",
+          "w": 300,
+          "h": 250
+        }
+      }
+    ],
+    "site": {
+      "page": "https://some.domain.us/some/page.html"
+    },
+    "device":{
+      "ip":"255.255.255.255"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1",
+        "body": {
+          "id": "adm-video",
+          "imp": [
+            {
+              "video": {
+                "w": 300,
+                "h": 250,
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "bidfloor": 3.01,
+              "id": "video1",
+              "secure": 1
+            }
+          ],
+          "site": {
+            "page": "https://some.domain.us/some/page.html",
+            "domain": "some.domain.us"
+          },
+          "cur": [
+            "USD"
+          ],
+          "device":{
+            "devicetype": 2,
+            "ip":"255.255.255.255"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "adm-video",
+          "seatBid": [
+            {
+              "bid": [
+                {
+                  "id": "5fd7c8a6ff2f1f0d42ee6427",
+                  "impid": "video1",
+                  "price": 20,
+                  "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+                  "adid": "1088",
+                  "adomain": [
+                    "beachfront.io"
+                  ],
+                  "cid": "277",
+                  "crid": "532",
+                  "w": 300,
+                  "h": 250,
+                  "ext": {
+                    "duration": 30
+                  }
+                }
+              ],
+              "seat": "bfio-s-1"
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "video1AdmVideo",
+            "impid": "video1",
+            "price": 20,
+            "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+            "adid": "1088",
+            "adomain": [
+              "beachfront.io"
+            ],
+            "cid": "277",
+            "crid": "532",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "duration": 30
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/beachfront/beachfronttest/exemplary/banner-and-adm-video-by-default.json b/adapters/beachfront/beachfronttest/exemplary/banner-and-adm-video-by-default.json
new file mode 100644
index 00000000..bff1b76a
--- /dev/null
+++ b/adapters/beachfront/beachfronttest/exemplary/banner-and-adm-video-by-default.json
@@ -0,0 +1,187 @@
+{
+  "mockBidRequest": {
+    "id": "banner-and-video",
+    "imp": [
+      {
+        "id": "mix1",
+        "ext": {
+          "bidder": {
+            "bidfloor": 0.41,
+            "appIds": {
+              "banner": "bannerAppId1",
+              "video": "videoAppId1"
+            }
+          }
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "context": "instream",
+          "w": 300,
+          "h": 250
+        }
+      }
+    ],
+    "site": {
+      "page": "https://some.domain.us/some/page.html"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/prebid_display",
+        "body": {
+          "slots": [
+            {
+              "slot": "mix1",
+              "id": "bannerAppId1",
+              "bidfloor": 0.41,
+              "sizes": [
+                {
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "domain": "some.domain.us",
+          "page": "https://some.domain.us/some/page.html",
+          "referrer": "",
+          "search": "",
+          "secure": 1,
+          "deviceOs": "",
+          "deviceModel": "",
+          "isMobile": 0,
+          "ua": "",
+          "ip": "",
+          "dnt": 0,
+          "user": {},
+          "adapterName": "BF_PREBID_S2S",
+          "adapterVersion": "0.9.1",
+          "requestId": "banner-and-video"
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": [
+          {
+            "crid": "crid_1",
+            "price": 9.5019655,
+            "w": 300,
+            "h": 250,
+            "slot": "mix1",
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
+          }
+        ]
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1",
+        "body": {
+          "id": "banner-and-video",
+          "imp": [
+            {
+              "video": {
+                "w": 300,
+                "h": 250,
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "bidfloor": 0.41,
+              "secure": 1,
+              "id": "mix1"
+            }
+          ],
+          "site": {
+            "domain": "some.domain.us",
+            "page": "https://some.domain.us/some/page.html"
+          },
+          "cur": [
+            "USD"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "5d839458f73decdc1572b7f6",
+                  "impid": "mix1",
+                  "price": 20,
+                  "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+                  "adid": "1088",
+                  "adomain": [
+                    "beachfront.io"
+                  ],
+                  "cid": "277",
+                  "crid": "532",
+                  "w": 300,
+                  "h": 250
+                }
+              ],
+              "seat": "bfb-io-s1"
+            }
+          ],
+          "bidid": "5d839458f73decdc1572b7f6",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "mix1Banner",
+            "impid": "mix1",
+            "price": 9.5019655,
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
+            "crid": "crid_1",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    },
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "mix1AdmVideo",
+            "impid": "mix1",
+            "price": 20,
+            "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+            "adid": "1088",
+            "adomain": [
+              "beachfront.io"
+            ],
+            "cid": "277",
+            "crid": "532",
+            "w": 300,
+            "h": 250
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/beachfront/beachfronttest/exemplary/banner-and-adm-video-by-explicit-type.json b/adapters/beachfront/beachfronttest/exemplary/banner-and-adm-video-by-explicit-type.json
new file mode 100644
index 00000000..3482f4ef
--- /dev/null
+++ b/adapters/beachfront/beachfronttest/exemplary/banner-and-adm-video-by-explicit-type.json
@@ -0,0 +1,188 @@
+{
+  "mockBidRequest": {
+    "id": "banner-and-video",
+    "imp": [
+      {
+        "id": "mix1",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "adm",
+            "bidfloor": 0.41,
+            "appIds": {
+              "banner": "bannerAppId1",
+              "video": "videoAppId1"
+            }
+          }
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "context": "instream",
+          "w": 300,
+          "h": 250
+        }
+      }
+    ],
+    "site": {
+      "page": "https://some.domain.us/some/page.html"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/prebid_display",
+        "body": {
+          "slots": [
+            {
+              "slot": "mix1",
+              "id": "bannerAppId1",
+              "bidfloor": 0.41,
+              "sizes": [
+                {
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "domain": "some.domain.us",
+          "page": "https://some.domain.us/some/page.html",
+          "referrer": "",
+          "search": "",
+          "secure": 1,
+          "deviceOs": "",
+          "deviceModel": "",
+          "isMobile": 0,
+          "ua": "",
+          "ip": "",
+          "dnt": 0,
+          "user": {},
+          "adapterName": "BF_PREBID_S2S",
+          "adapterVersion": "0.9.1",
+          "requestId": "banner-and-video"
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": [
+          {
+            "crid": "crid_1",
+            "price": 9.5019655,
+            "w": 300,
+            "h": 250,
+            "slot": "mix1",
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
+          }
+        ]
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1",
+        "body": {
+          "id": "banner-and-video",
+          "imp": [
+            {
+              "video": {
+                "w": 300,
+                "h": 250,
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "bidfloor": 0.41,
+              "secure": 1,
+              "id": "mix1"
+            }
+          ],
+          "site": {
+            "domain": "some.domain.us",
+            "page": "https://some.domain.us/some/page.html"
+          },
+          "cur": [
+            "USD"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "5d839458f73decdc1572b7f6",
+                  "impid": "mix1",
+                  "price": 20,
+                  "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+                  "adid": "1088",
+                  "adomain": [
+                    "beachfront.io"
+                  ],
+                  "cid": "277",
+                  "crid": "532",
+                  "w": 300,
+                  "h": 250
+                }
+              ],
+              "seat": "bfb-io-s1"
+            }
+          ],
+          "bidid": "5d839458f73decdc1572b7f6",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "mix1Banner",
+            "impid": "mix1",
+            "price": 9.5019655,
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
+            "crid": "crid_1",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    },
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "mix1AdmVideo",
+            "impid": "mix1",
+            "price": 20,
+            "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+            "adid": "1088",
+            "adomain": [
+              "beachfront.io"
+            ],
+            "cid": "277",
+            "crid": "532",
+            "w": 300,
+            "h": 250
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/beachfront/beachfronttest/exemplary/banner-and-nurl-video.json b/adapters/beachfront/beachfronttest/exemplary/banner-and-nurl-video.json
new file mode 100644
index 00000000..9db714f4
--- /dev/null
+++ b/adapters/beachfront/beachfronttest/exemplary/banner-and-nurl-video.json
@@ -0,0 +1,189 @@
+{
+  "mockBidRequest": {
+    "id": "banner-and-video",
+    "imp": [
+      {
+        "id": "mix1",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "nurl",
+            "bidfloor": 0.41,
+            "appIds": {
+              "banner": "bannerAppId1",
+              "video": "videoAppId1"
+            }
+          }
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "context": "instream",
+          "w": 300,
+          "h": 250
+        }
+      }
+    ],
+    "site": {
+      "page": "https://some.domain.us/some/page.html"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/prebid_display",
+        "body": {
+          "slots": [
+            {
+              "slot": "mix1",
+              "id": "bannerAppId1",
+              "bidfloor": 0.41,
+              "sizes": [
+                {
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "domain": "some.domain.us",
+          "page": "https://some.domain.us/some/page.html",
+          "referrer": "",
+          "search": "",
+          "secure": 1,
+          "deviceOs": "",
+          "deviceModel": "",
+          "isMobile": 0,
+          "ua": "",
+          "ip": "",
+          "dnt": 0,
+          "user": {},
+          "adapterName": "BF_PREBID_S2S",
+          "adapterVersion": "0.9.1",
+          "requestId": "banner-and-video"
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": [
+          {
+            "crid": "crid_1",
+            "price": 9.5019655,
+            "w": 300,
+            "h": 250,
+            "slot": "mix1",
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
+          }
+        ]
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1&prebidserver",
+        "body": {
+          "id": "banner-and-video",
+          "imp": [
+            {
+              "video": {
+                "w": 300,
+                "h": 250,
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "bidfloor": 0.41,
+              "secure": 1,
+              "id": "mix1"
+            }
+          ],
+          "site": {
+            "domain": "some.domain.us",
+            "page": "https://some.domain.us/some/page.html"
+          },
+          "isPrebid": true,
+          "cur": [
+            "USD"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "5d839458f73decdc1572b7f6",
+                  "impid": "mix1",
+                  "price": 20,
+                  "nurl": "https://useast.bfmio.com/getBids?aid=bid:70b99087-1b92-4e81-bc42-05c940fd6014:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8391a85f35945a70c9ddf0,0.01&i_type=pre",
+                  "crid": "70b99087-1b92-4e81-bc42-05c940fd6014",
+                  "adid": "1088",
+                  "adomain": [
+                    "beachfront.io"
+                  ],
+                  "cid": "277",
+                  "w": 300,
+                  "h": 250
+                }
+              ],
+              "seat": "bfb-io-s1"
+            }
+          ],
+          "bidid": "5d839458f73decdc1572b7f6",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "mix1Banner",
+            "impid": "mix1",
+            "price": 9.5019655,
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
+            "crid": "crid_1",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    },
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "mix1NurlVideo",
+            "impid": "mix1",
+            "price": 20,
+            "nurl": "https://useast.bfmio.com/getBids?aid=bid:70b99087-1b92-4e81-bc42-05c940fd6014:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8391a85f35945a70c9ddf0,0.01&i_type=pre",
+            "adid": "1088",
+            "adomain": [
+              "beachfront.io"
+            ],
+            "cid": "277",
+            "crid": "70b99087-1b92-4e81-bc42-05c940fd6014",
+            "w": 300,
+            "h": 250
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json b/adapters/beachfront/beachfronttest/exemplary/banner.json
similarity index 83%
rename from adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json
rename to adapters/beachfront/beachfronttest/exemplary/banner.json
index a12f7fd9..1eb17286 100644
--- a/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json
+++ b/adapters/beachfront/beachfronttest/exemplary/banner.json
@@ -2,7 +2,7 @@
   "mockBidRequest": {
     "id": "some_test_ad",
     "site": {
-      "page": "test.opposingviews.com"
+      "page": "https://some.domain.us/some/page.html"
     },
     "imp": [
       {
@@ -18,21 +18,22 @@
         "ext": {
           "bidder": {
             "bidfloor": 0.02,
-            "appId": "3b16770b-17af-4d22-daff-9606bdf2c9c3"
+            "appId": "bannerAppId1"
           }
         }
       }
     ]
   },
+
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "https://display.bfmio.com/prebid_display",
+        "uri": "https://qa.beachrtb.com/prebid_display",
         "body": {
           "slots": [
             {
               "slot": "",
-              "id": "3b16770b-17af-4d22-daff-9606bdf2c9c3",
+              "id": "bannerAppId1",
               "bidfloor": 0.02,
               "sizes": [
                 {
@@ -42,12 +43,12 @@
               ]
             }
           ],
-          "domain": "test.opposingviews.com",
-          "page": "test.opposingviews.com",
-          "requestId": "some_test_ad",
+          "domain": "some.domain.us",
+          "page": "https://some.domain.us/some/page.html",
           "referrer": "",
           "search": "",
-          "secure": 0,
+          "secure": 1,
+          "requestId": "some_test_ad",
           "isMobile": 0,
           "ip": "",
           "deviceModel": "",
@@ -55,7 +56,7 @@
           "dnt": 0,
           "ua": "",
           "adapterName": "BF_PREBID_S2S",
-          "adapterVersion": "0.9.0",
+          "adapterVersion": "0.9.1",
           "user": {}
         }
       },
diff --git a/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json b/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json
deleted file mode 100644
index 6672e2af..00000000
--- a/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json
+++ /dev/null
@@ -1,95 +0,0 @@
-{
-  "mockBidRequest": {
-    "id": "some_test_ad",
-    "site": {
-      "page": "https://test.opposingviews.com/i/society/republican-sen-collins-may-change-vote-tax-bill?cb=1234534"
-    },
-    "imp": [
-      {
-        "bidfloor": 0.02,
-        "banner": {
-          "format": [
-            {
-              "w": 300,
-              "h": 250
-            }
-          ]
-        },
-        "ext": {
-          "bidder": {
-            "bidfloor": 0.02,
-            "appId": "3b16770b-17af-4d22-daff-9606bdf2c9c3"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri": "https://display.bfmio.com/prebid_display",
-        "body": {
-          "slots": [
-            {
-              "slot": "",
-              "id": "3b16770b-17af-4d22-daff-9606bdf2c9c3",
-              "bidfloor": 0.02,
-              "sizes": [
-                {
-                  "w": 300,
-                  "h": 250
-                }
-              ]
-            }
-          ],
-          "domain": "test.opposingviews.com",
-          "page": "https://test.opposingviews.com/i/society/republican-sen-collins-may-change-vote-tax-bill?cb=1234534",
-          "referrer": "",
-          "search": "",
-          "secure": 1,
-          "requestId": "some_test_ad",
-          "isMobile": 0,
-          "ip": "",
-          "deviceModel": "",
-          "deviceOs": "",
-          "dnt": 0,
-          "ua": "",
-          "adapterName": "BF_PREBID_S2S",
-          "adapterVersion": "0.9.0",
-          "user": {}
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": [
-          {
-            "crid": "crid_1",
-            "price": 2.942808,
-            "w": 300,
-            "h": 250,
-            "slot": "div-gpt-ad-1460505748561-0",
-            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
-          }
-        ]
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids": [
-        {
-          "bid": {
-            "id": "div-gpt-ad-1460505748561-0Banner",
-            "impid": "div-gpt-ad-1460505748561-0",
-            "price": 2.942808,
-            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
-            "crid": "crid_1",
-            "w": 300,
-            "h": 250
-          },
-          "type": "banner"
-        }
-      ]
-    }
-  ]
-}
diff --git a/adapters/beachfront/beachfronttest/exemplary/simple-nurl-video.json b/adapters/beachfront/beachfronttest/exemplary/nurl-video.json
similarity index 71%
rename from adapters/beachfront/beachfronttest/exemplary/simple-nurl-video.json
rename to adapters/beachfront/beachfronttest/exemplary/nurl-video.json
index 0f96d9f2..b9b1881e 100644
--- a/adapters/beachfront/beachfronttest/exemplary/simple-nurl-video.json
+++ b/adapters/beachfront/beachfronttest/exemplary/nurl-video.json
@@ -1,17 +1,14 @@
 {
   "mockBidRequest": {
-    "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-    "tmax": 1000,
-    "source": {
-      "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-    },
+    "id": "nurl-video",
     "imp": [
       {
         "id": "video1",
         "ext": {
           "bidder": {
+            "videoResponseType": "nurl",
             "bidfloor": 0.01,
-            "appId": "11bc5dd5-7421-4dd8-c926-40fa653bec76"
+            "appId": "videoAppId1"
           }
         },
         "video": {
@@ -25,27 +22,19 @@
       }
     ],
     "site": {
-      "publisher": {
-        "id": "publisher1"
-      },
       "page": "http://example.com/whatever/something.html"
     },
-    "user": {
-      "id": "some-user",
-      "buyeruid": "some-buyer"
-    },
     "device": {
-      "devicetype": 2,
-      "ip": "127.0.0.1",
-      "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16"
+      "ip": "255.255.255.255"
     }
   },
+
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76&prebidserver",
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1&prebidserver",
         "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "id": "nurl-video",
           "isPrebid": true,
           "imp": [
             {
@@ -61,28 +50,16 @@
             }
           ],
           "site": {
-            "publisher": {
-              "id": "publisher1"
-            },
             "page": "http://example.com/whatever/something.html",
             "domain": "example.com"
           },
           "device": {
             "devicetype": 2,
-            "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-            "ip": "192.168.255.255"
+            "ip": "255.255.255.255"
           },
-          "source": {
-            "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-          },
-          "tmax": 1000,
           "cur": [
             "USD"
-          ],
-          "user": {
-            "id": "some-user",
-            "buyeruid": "some-buyer"
-          }
+          ]
         }
       },
       "mockResponse": {
@@ -115,6 +92,7 @@
       }
     }
   ],
+
   "expectedBidResponses": [
     {
       "bids": [
@@ -139,4 +117,4 @@
       ]
     }
   ]
-}
+}
\ No newline at end of file
diff --git a/adapters/beachfront/beachfronttest/exemplary/simple-adm-video.json b/adapters/beachfront/beachfronttest/exemplary/simple-adm-video.json
deleted file mode 100644
index cb1f4c20..00000000
--- a/adapters/beachfront/beachfronttest/exemplary/simple-adm-video.json
+++ /dev/null
@@ -1,150 +0,0 @@
-{
-  "mockBidRequest": {
-    "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-    "tmax": 1000,
-    "source": {
-      "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-    },
-    "imp": [
-      {
-        "id": "video1",
-        "ext": {
-          "bidder": {
-            "videoResponseType": "adm",
-            "bidfloor": 0.01,
-            "appId": "11bc5dd5-7421-4dd8-c926-40fa653bec76"
-          }
-        },
-        "video": {
-          "mimes": [
-            "video/mp4"
-          ],
-          "context": "instream",
-          "w": 300,
-          "h": 250
-        }
-      }
-    ],
-    "site": {
-      "publisher": {
-        "id": "publisher1"
-      },
-      "page": "http://example.com/whatever/something.html"
-    },
-    "user": {
-      "id": "some-user",
-      "buyeruid": "some-buyer"
-    },
-    "device": {
-      "devicetype": 2,
-      "ip": "127.0.0.1",
-      "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16"
-    }
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76",
-        "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "imp": [
-            {
-              "video": {
-                "w": 300,
-                "h": 250,
-                "mimes": [
-                  "video/mp4"
-                ]
-              },
-              "id": "video1",
-              "secure": 0
-            }
-          ],
-          "site": {
-            "publisher": {
-              "id": "publisher1"
-            },
-            "page": "http://example.com/whatever/something.html",
-            "domain": "example.com"
-          },
-          "device": {
-            "devicetype": 2,
-            "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-            "ip": "192.168.255.255"
-          },
-          "source": {
-            "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-          },
-          "tmax": 1000,
-          "cur": [
-            "USD"
-          ],
-          "user": {
-            "id": "some-user",
-            "buyeruid": "some-buyer"
-          }
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatBid": [
-            {
-              "bid": [
-                {
-                  "id": "video1AdmVideo",
-                  "impid": "video1",
-                  "price": 20,
-                  "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d8393417cbc8e5aa4fe2202,0.01\",\"inventory_id\":\"bid:95d219a2-6025-44ba-bff8-1dca987beaae:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
-                  "adid": "1088",
-                  "adomain": [
-                    "beachfront.io"
-                  ],
-                  "cid": "277",
-                  "crid": "532",
-                  "w": 300,
-                  "h": 250,
-                  "ext": {
-                    "prebid": {
-                      "type": "video"
-                    }
-                  }
-                }
-              ],
-              "seat": "beachfront"
-            }
-          ]
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids": [
-        {
-          "bid": {
-            "id": "video1AdmVideo",
-            "impid": "video1",
-            "price": 20,
-            "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d8393417cbc8e5aa4fe2202,0.01\",\"inventory_id\":\"bid:95d219a2-6025-44ba-bff8-1dca987beaae:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
-            "adid": "1088",
-            "adomain": [
-              "beachfront.io"
-            ],
-            "cid": "277",
-            "crid": "532",
-            "w": 300,
-            "h": 250,
-            "ext": {
-              "prebid": {
-                "type": "video"
-              }
-            }
-          },
-          "type": "video"
-        }
-      ]
-    }
-  ]
-}
diff --git a/adapters/beachfront/beachfronttest/exemplary/simple-mix.json b/adapters/beachfront/beachfronttest/exemplary/simple-mix.json
deleted file mode 100644
index cc2b4158..00000000
--- a/adapters/beachfront/beachfronttest/exemplary/simple-mix.json
+++ /dev/null
@@ -1,214 +0,0 @@
-{
-  "mockBidRequest": {
-    "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-    "tmax": 1000,
-    "source": {
-      "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-    },
-    "imp": [
-      {
-        "id": "mix1",
-        "ext": {
-          "bidder": {
-            "videoResponseType": "adm",
-            "bidfloor": 0.41,
-            "appIds": {
-              "banner": "487cf244-5e95-43cb-e7b9-bb540873ca7e",
-              "video": "11bc5dd5-7421-4dd8-c926-40fa653bec76"
-            }
-          }
-        },
-        "banner": {
-          "format": [
-            {
-              "w": 300,
-              "h": 250
-            }
-          ]
-        },
-        "video": {
-          "mimes": [
-            "video/mp4"
-          ],
-          "context": "instream",
-          "w": 300,
-          "h": 250
-        }
-      }
-    ],
-    "site": {
-      "page": "http://example.com/somepage.html"
-    },
-    "user": {
-      "id": "some-user",
-      "buyeruid": "some-buyer"
-    },
-    "device": {
-      "ip": "192.168.255.255",
-      "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16"
-    }
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri": "https://display.bfmio.com/prebid_display",
-        "body": {
-          "slots": [
-            {
-              "slot": "mix1",
-              "id": "487cf244-5e95-43cb-e7b9-bb540873ca7e",
-              "bidfloor": 0.41,
-              "sizes": [
-                {
-                  "w": 300,
-                  "h": 250
-                }
-              ]
-            }
-          ],
-          "domain": "example.com",
-          "page": "http://example.com/somepage.html",
-          "referrer": "",
-          "search": "",
-          "secure": 0,
-          "deviceOs": "",
-          "deviceModel": "",
-          "isMobile": 0,
-          "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-          "dnt": 0,
-          "user": {
-            "id": "some-user",
-            "buyeruid": "some-buyer"
-          },
-          "adapterName": "BF_PREBID_S2S",
-          "adapterVersion": "0.9.0",
-          "ip": "192.168.255.255",
-          "requestId": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": [
-          {
-            "crid": "crid_1",
-            "price": 9.5019655,
-            "w": 300,
-            "h": 250,
-            "slot": "mix1",
-            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
-          }
-        ]
-      }
-    },
-    {
-      "expectedRequest": {
-        "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76",
-        "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "imp": [
-            {
-              "video": {
-                "w": 300,
-                "h": 250,
-                "mimes": [
-                  "video/mp4"
-                ]
-              },
-              "bidfloor": 0.41,
-              "secure": 0,
-              "id": "mix1"
-            }
-          ],
-          "site": {
-            "page": "http://example.com/somepage.html",
-            "domain": "example.com"
-          },
-          "source": {
-            "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-          },
-          "device": {
-            "devicetype": 2,
-            "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-            "ip": "192.168.255.255"
-          },
-          "cur": [
-            "USD"
-          ],
-          "tmax": 1000,
-          "user": {
-            "id": "some-user",
-            "buyeruid": "some-buyer"
-          }
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatbid": [
-            {
-              "bid": [
-                {
-                  "id": "5d839458f73decdc1572b7f6",
-                  "impid": "mix1",
-                  "price": 20,
-                  "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d839458f73decdc1572b7f6,0.41\",\"inventory_id\":\"bid:26826cf7-f8bb-4e47-a636-769d83dd9b4f:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
-                  "adid": "1088",
-                  "adomain": [
-                    "beachfront.io"
-                  ],
-                  "cid": "277",
-                  "crid": "532",
-                  "w": 300,
-                  "h": 250
-                }
-              ],
-              "seat": "bfb-io-s1"
-            }
-          ],
-          "bidid": "5d839458f73decdc1572b7f6",
-          "cur": "USD"
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids": [
-        {
-          "bid": {
-            "id": "mix1Banner",
-            "impid": "mix1",
-            "price": 9.5019655,
-            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
-            "crid": "crid_1",
-            "w": 300,
-            "h": 250
-          },
-          "type": "banner"
-        }
-      ]
-    },
-    {
-      "bids": [
-        {
-          "bid": {
-            "id": "mix1AdmVideo",
-            "impid": "mix1",
-            "price": 20,
-            "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d839458f73decdc1572b7f6,0.41\",\"inventory_id\":\"bid:26826cf7-f8bb-4e47-a636-769d83dd9b4f:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
-            "adid": "1088",
-            "adomain": [
-              "beachfront.io"
-            ],
-            "cid": "277",
-            "crid": "532",
-            "w": 300,
-            "h": 250
-          },
-          "type": "video"
-        }
-      ]
-    }
-  ]
-}
diff --git a/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json b/adapters/beachfront/beachfronttest/supplemental/banner-empty_array-200.json
similarity index 75%
rename from adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json
rename to adapters/beachfront/beachfronttest/supplemental/banner-empty_array-200.json
index 01207f22..c90c1215 100644
--- a/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json
+++ b/adapters/beachfront/beachfronttest/supplemental/banner-empty_array-200.json
@@ -2,10 +2,11 @@
   "mockBidRequest": {
     "id": "some_test_ad",
     "site": {
-      "page": "https://yourmomshouse.com"
+      "page": "https://some.domain.us/some/page.html"
     },
     "imp": [
       {
+        "id": "dudImp",
         "bidfloor": 0.02,
         "banner": {
           "format": [
@@ -18,7 +19,7 @@
         "ext": {
           "bidder": {
             "bidfloor": 0.02,
-            "appId": "00000000-1111-2222-3333-11111111111"
+            "appId": "dudAppId1"
           }
         }
       }
@@ -28,12 +29,12 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "https://display.bfmio.com/prebid_display",
+        "uri": "https://qa.beachrtb.com/prebid_display",
         "body": {
           "slots": [
             {
-              "slot": "",
-              "id": "00000000-1111-2222-3333-11111111111",
+              "slot": "dudImp",
+              "id": "dudAppId1",
               "bidfloor": 0.02,
               "sizes": [
                 {
@@ -43,8 +44,8 @@
               ]
             }
           ],
-          "domain": "yourmomshouse.com",
-          "page": "https://yourmomshouse.com",
+          "domain": "some.domain.us",
+          "page": "https://some.domain.us/some/page.html",
           "referrer": "",
           "search": "",
           "secure": 1,
@@ -56,7 +57,7 @@
           "dnt": 0,
           "ua": "",
           "adapterName": "BF_PREBID_S2S",
-          "adapterVersion": "0.9.0",
+          "adapterVersion": "0.9.1",
           "user": {
           }
         }
diff --git a/adapters/beachfront/beachfronttest/supplemental/minimal-mobile-video.json b/adapters/beachfront/beachfronttest/supplemental/minimal-mobile-video.json
deleted file mode 100644
index 5556f6e7..00000000
--- a/adapters/beachfront/beachfronttest/supplemental/minimal-mobile-video.json
+++ /dev/null
@@ -1,119 +0,0 @@
-{
-  "mockBidRequest": {
-    "id": "some_test_ad",
-    "app": {
-      "bundle": "_org.prebid.mobile.demoapp",
-      "id": "some-mobile-app"
-    },
-    "imp": [
-      {
-        "id": "video1",
-        "ext": {
-          "bidder": {
-            "bidfloor": 0.01,
-            "appId": "11bc5dd5-7421-4dd8-c926-40fa653bec76",
-            "videoResponseType": "nurl"
-          }
-        },
-        "video": {
-          "mimes": [
-            "video/mp4"
-          ],
-          "w": 300,
-          "h": 250
-        }
-      }
-    ],
-    "device": {
-      "devicetype": 1,
-      "ifa": "bb956625-df13-4568-b60b-eb5cbf76e986"
-    }
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76&prebidserver",
-        "body": {
-          "cur": [
-            "USD"
-          ],
-          "device": {
-            "devicetype": 1,
-            "ifa": "bb956625-df13-4568-b60b-eb5cbf76e986"
-          },
-          "id": "some_test_ad",
-          "imp": [
-            {
-              "id": "video1",
-              "secure": 0,
-              "video": {
-                "mimes": [
-                  "video/mp4"
-                ],
-                "h": 250,
-                "w": 300
-              }
-            }
-          ],
-          "isPrebid": true,
-          "app": {
-            "bundle": "_org.prebid.mobile.demoapp",
-            "domain": "prebid.org",
-            "id": "some-mobile-app"
-          }
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatBid": [
-            {
-              "bid": [
-                {
-                  "w": 0,
-                  "h": 0,
-                  "id": "0",
-                  "impid": "",
-                  "price": 0.01,
-                  "adid": "",
-                  "nurl": "https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
-                  "adm": "",
-                  "adomain": [],
-                  "iurl": "",
-                  "cid": "",
-                  "crid": "",
-                  "attr": [],
-                  "ext": {},
-                  "cat": []
-                }
-              ],
-              "seat": "",
-              "group": 0,
-              "ext": {}
-            }
-          ]
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids": [
-        {
-          "bid": {
-            "id": "video1NurlVideo",
-            "impid": "video1",
-            "price": 0.01,
-            "nurl": "https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
-            "crid": "0d32aea6-d199-4803-a188-bd7cf7be1e12",
-            "w": 300,
-            "h": 250,
-            "ext":{}
-          },
-          "type": "video"
-        }
-      ]
-    }
-  ]
-}
diff --git a/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json b/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json
deleted file mode 100644
index 17cc7d32..00000000
--- a/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json
+++ /dev/null
@@ -1,128 +0,0 @@
-{
-  "mockBidRequest": {
-    "id":"763e3312-19d5-4b07-a61d-890147e863a1",
-    "source":{
-      "tid":"763e3312-19d5-4b07-a61d-890147e863a1"
-    },
-    "tmax":1000,
-    "imp":[
-      {
-        "id":"div-gpt-ad-1460505748561-0",
-        "ext":{
-          "bidder":{
-            "appId":"3b16770b-17af-4d22-daff-9606bdf2c9c3",
-            "bidfloor":0.01
-          }
-        },
-        "banner":{
-          "format":[
-            {
-              "w":300,
-              "h":250
-            },
-            {
-              "w":300,
-              "h":600
-            }
-          ]
-        }
-      }
-    ],
-    "device":{
-      "make":"Huawei",
-      "model":"Android SDK built for x86",
-      "ua":"Mozilla\/5.0 (Linux; Android 5.1.1; Android SDK built for x86 Build\/LMY48X) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/39.0.0.0 Mobile Safari\/537.36",
-      "w":360,
-      "h":567,
-      "pxratio":2,
-      "mccmnc":"310-260",
-      "carrier":"Android",
-      "connectiontype":2,
-      "lmt":0,
-      "ifa":"bb956625-df13-4568-b60b-eb5cbf76e986",
-      "os":"android",
-      "osv":"22",
-      "language":"en"
-    },
-    "app":{
-      "id":"bfa84af2-bd16-4d35-96ad-31c6bb888df0",
-      "name":"Demo app",
-      "bundle":"_org.prebid.mobile.demoapp",
-      "domain":"beachfront.com"
-    }
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri" : "https://display.bfmio.com/prebid_display",
-        "body" : {
-          "slots":[
-            {
-              "slot":"div-gpt-ad-1460505748561-0",
-              "id":"3b16770b-17af-4d22-daff-9606bdf2c9c3",
-              "bidfloor":0,
-              "sizes":[
-                {
-                  "w":300,
-                  "h":250
-                },
-                {
-                  "w":300,
-                  "h":600
-                }
-              ]
-            }
-          ],
-          "domain":"beachfront.com",
-          "page":"_org.prebid.mobile.demoapp",
-          "referrer":"",
-          "search":"",
-          "secure":0,
-          "deviceOs":"android",
-          "deviceModel":"Android SDK built for x86",
-          "isMobile":1,
-          "ua":"Mozilla/5.0 (Linux; Android 5.1.1; Android SDK built for x86 Build/LMY48X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36",
-          "dnt":0,
-          "user":{
-
-          },
-          "adapterName":"BF_PREBID_S2S",
-          "adapterVersion":"0.9.0",
-          "ip":"192.168.255.255",
-          "requestId":"763e3312-19d5-4b07-a61d-890147e863a1"
-        }
-      }
-    ,
-      "mockResponse": {
-        "status": 200,
-        "body": [
-          {
-            "crid":"crid_1",
-            "price":2.942808,
-            "w":300,
-            "h":250,
-            "slot":"div-gpt-ad-1460505748561-0",
-            "adm":"<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
-          }
-        ]
-      }
-    }
-  ],
-
-  "expectedBidResponses": [
-    {
-      "bids": [{
-        "bid": {
-          "id": "div-gpt-ad-1460505748561-0Banner",
-          "impid": "div-gpt-ad-1460505748561-0",
-          "price": 2.942808,
-          "adm":"<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
-          "crid": "crid_1",
-          "w": 300,
-          "h": 250
-        },
-        "type": "banner"
-      }]
-    }
-  ]
-}
diff --git a/adapters/beachfront/beachfronttest/supplemental/multi-banner.json b/adapters/beachfront/beachfronttest/supplemental/multi-banner.json
deleted file mode 100644
index 1d355dba..00000000
--- a/adapters/beachfront/beachfronttest/supplemental/multi-banner.json
+++ /dev/null
@@ -1,138 +0,0 @@
-{
-  "mockBidRequest": {
-    "id": "fail_id",
-    "tmax": 800,
-    "site": {
-      "page": "https://test.opposingviews.com/i/society/republican-sen-collins-may-change-vote-tax-bill?cb=1234534"
-    },
-    "user": {
-      "id": "some-user",
-      "buyeruid": "some-buyer"
-    },
-    "device": {
-      "ip": "127.0.0.1",
-      "model": "MacBookPro",
-      "OS": "macOS Sierra 10.12.6",
-      "dnt": 1,
-      "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16"
-    },
-    "imp": [
-      {
-        "id": "test_slot",
-        "bidfloor": 0.02,
-        "banner": {
-          "format": [
-            {
-              "w": 300,
-              "h": 250
-            }
-          ]
-        },
-        "ext": {
-          "bidder": {
-            "bidfloor": 0.02,
-            "appId": "3b16770b-17af-4d22-daff-9606bdf2c9c3"
-          }
-        }
-      },{
-        "id": "test_slot2",
-        "bidfloor": 0.03,
-        "banner": {
-          "format": [
-            {
-              "w": 600,
-              "h": 450
-            }
-          ]
-        },
-        "ext": {
-          "bidder": {
-            "bidfloor": 0.03,
-            "appId": "3b16770b-17af-4d22-daff-9606bdf2c9c3"
-          }
-        }
-      }
-    ]
-  },
-
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri": "https://display.bfmio.com/prebid_display",
-        "body": {
-          "slots": [
-            {
-              "slot": "test_slot",
-              "id": "3b16770b-17af-4d22-daff-9606bdf2c9c3",
-              "bidfloor": 0.02,
-              "sizes": [
-                {
-                  "w": 300,
-                  "h": 250
-                }
-              ]
-            }, {
-              "slot": "test_slot2",
-              "bidfloor": 0.03,
-              "id": "3b16770b-17af-4d22-daff-9606bdf2c9c3",
-              "sizes": [
-                {
-                  "h": 450,
-                  "w": 600
-                }
-              ]
-            }
-          ],
-          "domain": "test.opposingviews.com",
-          "page": "https://test.opposingviews.com/i/society/republican-sen-collins-may-change-vote-tax-bill?cb=1234534",
-          "referrer": "",
-          "requestId": "fail_id",
-          "search": "",
-          "secure": 1,
-          "isMobile": 0,
-          "ip": "192.168.255.255",
-          "deviceModel": "MacBookPro",
-          "deviceOs": "macOS Sierra 10.12.6",
-          "dnt": 1,
-          "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-          "adapterName": "BF_PREBID_S2S",
-          "adapterVersion": "0.9.0",
-          "user": {
-            "buyeruid": "some-buyer",
-            "id": "some-user"
-          }
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": [
-          {
-            "crid":"crid_1",
-            "price":2.942808,
-            "w":300,
-            "h":250,
-            "slot":"div-gpt-ad-1460505748561-0",
-            "adm":"<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
-          }
-        ]
-      }
-    }
-  ],
-
-  "expectedBidResponses": [
-    {
-      "bids": [{
-        "bid": {
-          "id": "div-gpt-ad-1460505748561-0Banner",
-          "impid": "div-gpt-ad-1460505748561-0",
-          "price": 2.942808,
-          "adm":"<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>",
-          "crid": "crid_1",
-          "w": 300,
-          "h": 250
-        },
-        "type": "banner"
-      }]
-    }
-  ]
-}
diff --git a/adapters/beachfront/beachfronttest/supplemental/multi-video.json b/adapters/beachfront/beachfronttest/supplemental/multi-video.json
deleted file mode 100644
index 8ccd0a8d..00000000
--- a/adapters/beachfront/beachfronttest/supplemental/multi-video.json
+++ /dev/null
@@ -1,235 +0,0 @@
-{
-  "mockBidRequest": {
-    "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-    "tmax": 1000,
-    "source": {
-      "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-    },
-    "imp": [
-      {
-        "id": "multivideo",
-        "ext": {
-          "bidder": {
-            "bidfloor": 3.01,
-            "videoResponseType": "both",
-            "appId": "11bc5dd5-7421-4dd8-c926-40fa653bec76"
-          }
-        },
-        "video": {
-          "mimes": [
-            "video/mp4",
-            "video/webm"
-          ],
-          "context": "instream",
-          "w": 600,
-          "h": 450
-        }
-      }
-    ],
-    "site": {
-      "publisher": {
-        "id": "publisher1"
-      },
-      "page": "http://example.com/whatever"
-    },
-    "user": {
-      "id": "some-user",
-      "buyeruid": "some-buyer"
-    },
-    "device": {
-      "ip": "127.0.0.1",
-      "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16"
-    }
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76",
-        "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "imp": [
-            {
-              "id": "multivideo",
-              "secure": 0,
-              "video": {
-                "mimes": [
-                  "video/mp4",
-                  "video/webm"
-                ],
-                "w": 600,
-                "h": 450
-              },
-              "bidfloor": 3.01
-            }
-          ],
-          "site": {
-            "domain": "example.com",
-            "page": "http://example.com/whatever",
-            "publisher": {
-              "id": "publisher1"
-            }
-          },
-          "device": {
-            "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-            "ip": "192.168.255.255",
-            "devicetype": 2
-          },
-          "user": {
-            "id": "some-user",
-            "buyeruid": "some-buyer"
-          },
-          "tmax": 1000,
-          "cur": [
-            "USD"
-          ],
-          "source": {
-            "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-          }
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatbid": [
-            {
-              "bid": [
-                {
-                  "id": "5d8231a4254b2eca804965a3",
-                  "impid": "multivideo",
-                  "price": 20.0,
-                  "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d8231a4254b2eca804965a3,3.01\",\"inventory_id\":\"bid:1680831c-83a2-42a3-a790-a683d780749a:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
-                  "adid": "1088",
-                  "adomain": [
-                    "beachfront.io"
-                  ],
-                  "cid": "277",
-                  "crid": "532",
-                  "w": 600,
-                  "h": 450
-                }
-              ],
-              "seat": "bfb-io-s1"
-            }
-          ],
-          "bidid": "5d8231a4254b2eca804965a3",
-          "cur": "USD"
-        }
-      }
-    },
-    {
-      "expectedRequest": {
-        "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76&prebidserver",
-        "body": {
-          "isPrebid": true,
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "imp": [
-            {
-              "id": "multivideo",
-              "secure": 0,
-              "video": {
-                "mimes": [
-                  "video/mp4",
-                  "video/webm"
-                ],
-                "w": 600,
-                "h": 450
-              },
-              "bidfloor": 3.01
-            }
-          ],
-          "site": {
-            "domain": "example.com",
-            "page": "http://example.com/whatever",
-            "publisher": {
-              "id": "publisher1"
-            }
-          },
-          "device": {
-            "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-            "ip": "192.168.255.255",
-            "devicetype": 2
-          },
-          "user": {
-            "id": "some-user",
-            "buyeruid": "some-buyer"
-          },
-          "tmax": 1000,
-          "cur": [
-            "USD"
-          ],
-          "source": {
-            "tid": "61b87329-8790-47b7-90dd-c53ae7ce1723"
-          }
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatBid": [
-            {
-              "bid": [
-                {
-                  "id": "multivideo",
-                  "price": 20.0,
-                  "nurl": "https://useast.bfmio.com/getBids?aid=bid:b489a745-e577-4fcb-815d-0b6a1e052ec7:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8231a48d308d0a1f9b4526,0.61&i_type=pre",
-                  "adomain": [],
-                  "cat": [],
-                  "attr": [],
-                  "w": 0,
-                  "h": 0,
-                  "ext": {}
-                }
-              ],
-              "group": 0,
-              "ext": {}
-            }
-          ]
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids": [
-        {
-          "bid": {
-            "id": "multivideoAdmVideo",
-            "impid": "multivideo",
-            "price": 20,
-            "adm": "<?xml version=\"1.0\" encoding=\"utf-8\"?><VAST version=\"2.0\"><Ad id=\"VPAID\"><InLine><AdSystem version=\"2.0\">IO</AdSystem><AdTitle>Neptune</AdTitle><Impression></Impression><Creatives><Creative sequence=\"1\"><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" width=\"640\" height=\"480\" scalable=\"1\" type=\"application/javascript\" apiFramework=\"VPAID\"><![CDATA[http://player-cdn.beachfrontmedia.com/players/neptune/3/17/5/neptune-player.js]]></MediaFile></MediaFiles><AdParameters><![CDATA[{\"dsp\":\"5d8231a4254b2eca804965a3,3.01\",\"inventory_id\":\"bid:1680831c-83a2-42a3-a790-a683d780749a:11bc5dd5-7421-4dd8-c926-40fa653bec76:${AUCTION_PRICE}:20.0\",\"request_endpoint\":\"//useast.bfmio.com/getmu\",\"inventory_type\":\"pre\"}]]></AdParameters></Linear></Creative></Creatives></InLine></Ad></VAST>",
-            "adid": "1088",
-            "adomain": [
-              "beachfront.io"
-            ],
-            "cid": "277",
-            "crid": "532",
-            "w": 600,
-            "h": 450
-          },
-          "type": "video"
-        }
-      ],
-      "seat": "beachfront"
-    },
-    {
-      "bids": [
-        {
-          "bid": {
-            "id": "multivideoNurlVideo",
-            "impid": "multivideo",
-            "price": 20,
-            "nurl": "https://useast.bfmio.com/getBids?aid=bid:b489a745-e577-4fcb-815d-0b6a1e052ec7:11bc5dd5-7421-4dd8-c926-40fa653bec76:20.0:20.0&v=1&dsp=5d8231a48d308d0a1f9b4526,0.61&i_type=pre",
-            "crid": "b489a745-e577-4fcb-815d-0b6a1e052ec7",
-            "w": 600,
-            "h": 450,
-            "ext": {}
-          },
-          "type": "video"
-        }
-      ],
-      "seat": "beachfront"
-    }
-  ]
-}
diff --git a/adapters/beachfront/beachfronttest/supplemental/six-nine-combo--response-order--banner-adm-nurl--PASS.json b/adapters/beachfront/beachfronttest/supplemental/six-nine-combo--response-order--banner-adm-nurl--PASS.json
new file mode 100644
index 00000000..56af3df3
--- /dev/null
+++ b/adapters/beachfront/beachfronttest/supplemental/six-nine-combo--response-order--banner-adm-nurl--PASS.json
@@ -0,0 +1,465 @@
+{
+  "mockBidRequest":
+  {
+    "id": "six-nine-combo",
+    "imp": [
+      {
+        "id": "ADMVideoWithBannerImp1",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "adm",
+            "bidfloor": 1.01,
+            "appIds": {
+              "banner" : "bannerAppId1",
+              "video" :  "videoAppId1"
+            }
+          }
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 300,
+          "h": 400
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 400
+            }
+          ]
+        }
+      },
+      {
+        "id": "ADMVideoWithBannerImp2",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "adm",
+            "bidfloor": 1.01,
+            "appIds": {
+              "banner" : "bannerAppId2",
+              "video" :  "videoAppId1"
+            }
+          }
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 100,
+          "h": 150
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 100,
+              "h": 150
+            }
+          ]
+        }
+      },
+      {
+        "id": "NURLVideoImp3",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "nurl",
+            "bidfloor": 1.01,
+            "appId": "videoAppId1"
+          }
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 150,
+          "h": 300
+        }
+      },
+      {
+        "id": "RegularBannerImp4",
+        "ext": {
+          "bidder": {
+            "bidfloor": 1.05,
+            "appId" : "bannerAppId3"
+          }
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 1280,
+              "h": 1024
+            }
+          ]
+        }
+      },
+      {
+        "id": "RegularBannerImp5",
+        "ext": {
+          "bidder": {
+            "bidfloor": 1.05,
+            "appId" : "bannerAppId4"
+          }
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 1280,
+              "h": 1024
+            }
+          ]
+        }
+      },
+      {
+        "id": "ADMVideoImp6",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "adm",
+            "bidfloor": 1.01,
+            "appId": "videoAppId1"
+          }
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 100,
+          "h": 150
+        }
+      }
+    ],
+    "site": {
+      "page": "http://example.com/whatever/something.html"
+    }
+  } ,
+  "httpCalls": [
+
+    {
+      "expectedRequest":  {
+        "uri": "https://qa.beachrtb.com/prebid_display",
+        "body": {
+          "slots": [
+            {
+              "slot": "ADMVideoWithBannerImp1",
+              "id": "bannerAppId1",
+              "bidfloor": 1.01,
+              "sizes": [
+                {
+                  "w": 300,
+                  "h": 400
+                }
+              ]
+            },
+            {
+              "slot": "ADMVideoWithBannerImp2",
+              "id": "bannerAppId2",
+              "bidfloor": 1.01,
+              "sizes": [
+                {
+                  "w": 100,
+                  "h": 150
+                }
+              ]
+            },
+            {
+              "slot": "RegularBannerImp4",
+              "id": "bannerAppId3",
+              "bidfloor": 1.05,
+              "sizes": [
+                {
+                  "w": 1280,
+                  "h": 1024
+                }
+              ]
+            },
+            {
+              "slot": "RegularBannerImp5",
+              "id": "bannerAppId4",
+              "bidfloor": 1.05,
+              "sizes": [
+                {
+                  "w": 1280,
+                  "h": 1024
+                }
+              ]
+            }
+          ],
+          "domain": "example.com",
+          "page": "http://example.com/whatever/something.html",
+          "referrer": "",
+          "search": "",
+          "secure": 0,
+          "deviceOs": "",
+          "deviceModel": "",
+          "isMobile": 0,
+          "ua": "",
+          "dnt": 0,
+          "user": {},
+          "adapterName": "BF_PREBID_S2S",
+          "adapterVersion": "0.9.1",
+          "ip": "",
+          "requestId": "six-nine-combo"
+        }
+      },
+      "mockResponse": {
+        "status" : 200,
+        "body": [
+          {
+            "crid": "crid_1",
+            "price": 1.594764,
+            "w": 100,
+            "h": 150,
+            "slot": "ADMVideoWithBannerImp1",
+            "adm": "<div id=\"crid_1\">Buy now!</div>"
+          },
+          {
+            "crid": "crid_2",
+            "price": 1.594764,
+            "w": 100,
+            "h": 150,
+            "slot": "ADMVideoWithBannerImp2",
+            "adm": "<div id=\"crid_2\">Buy now!</div>"
+          },
+          {
+            "crid": "crid_3",
+            "price": 1.501188,
+            "w": 1280,
+            "h": 1024,
+            "slot": "RegularBannerImp4",
+            "adm": "<div id=\"crid_3\">Buy now!</div>"
+          },
+          {
+            "crid": "crid_4",
+            "price": 1.501188,
+            "w": 1280,
+            "h": 1024,
+            "slot": "RegularBannerImp5",
+            "adm": "<div id=\"crid_4\">Buy now!</div>"
+          }
+        ]
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1",
+        "body": {
+          "id": "six-nine-combo",
+          "imp": [
+            {
+              "id": "ADMVideoWithBannerImp1",
+              "secure": 0,
+              "bidfloor": 1.01,
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "w": 300,
+                "h": 400
+              }
+            }
+          ],
+          "site": {
+            "domain": "example.com",
+            "page": "http://example.com/whatever/something.html"
+          },
+          "cur": [
+            "USD"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status" : 200,
+        "body": {
+          "id": "six-nine-combo",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "crid_7",
+                  "impid": "ADMVideoWithBannerImp1",
+                  "price": 0.8,
+                  "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+                  "w": 300,
+                  "h": 400,
+                  "ext": {
+                    "duration": 30
+                  }
+                }
+              ],
+              "seat": "bfb-io-s1"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1",
+        "body": {
+          "id": "six-nine-combo",
+          "imp": [
+            {
+              "id": "ADMVideoWithBannerImp2",
+              "secure": 0,
+              "bidfloor": 1.01,
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "w": 100,
+                "h": 150
+              }
+            }
+          ],
+          "site": {
+            "domain": "example.com",
+            "page": "http://example.com/whatever/something.html"
+          },
+          "cur": [
+            "USD"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status" : 200,
+        "body": {
+          "id": "six-nine-combo",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "crid_7",
+                  "impid": "ADMVideoWithBannerImp2",
+                  "price": 0.8,
+                  "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+                  "w": 300,
+                  "h": 400,
+                  "ext": {
+                    "duration": 30
+                  }
+                }
+              ],
+              "seat": "bfb-io-s1"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1",
+        "body": {
+          "id": "six-nine-combo",
+          "imp": [
+            {
+              "id": "ADMVideoImp6",
+              "bidfloor": 1.01,
+              "secure": 0,
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "w": 100,
+                "h": 150
+              }
+            }
+          ],
+          "site": {
+            "domain": "example.com",
+            "page": "http://example.com/whatever/something.html"
+          },
+          "cur": [
+            "USD"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status" : 200,
+        "body": {
+          "id": "5f4f8790dca51d29347f4dd8",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "crid_8",
+                  "impid": "ADMVideoImp6",
+                  "price": 0.8,
+                  "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+                  "w": 100,
+                  "h": 150,
+                  "ext": {
+                    "duration": 30
+                  }
+                }
+              ],
+              "seat": "bfb-io-s1"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1&prebidserver",
+        "body": {
+          "isPrebid": true,
+          "id": "six-nine-combo",
+          "imp": [
+            {
+              "id": "NURLVideoImp3",
+              "bidfloor": 1.01,
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "w": 150,
+                "h": 300
+              },
+              "secure": 0
+            }
+          ],
+          "site": {
+            "domain": "example.com",
+            "page": "http://example.com/whatever/something.html"
+          },
+          "cur": [
+            "USD"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
+          "seatBid": [
+            {
+              "bid": [
+                {
+                  "id": "NURLVideoImp3",
+                  "price": 20.0,
+                  "nurl": "https://useast.bfmio.com/getBids?aid=bid:de5b4976-0d2a-4032-874c-35e2b3e3ab95: videoAppId1: 10.0: 10.0&v=1&dsp=5f7da002b6b0ca361fc692b0,0.01&i_type=pre",
+                  "adomain": [
+                  ],
+                  "cat": [
+                  ],
+                  "attr": [
+                  ],
+                  "w": 0,
+                  "h": 0,
+                  "ext": {
+                  }
+                }
+              ],
+              "group": 0,
+              "ext": {
+              }
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/adapters/beachfront/beachfronttest/supplemental/two-four-combo.json b/adapters/beachfront/beachfronttest/supplemental/two-four-combo.json
new file mode 100644
index 00000000..bff475ff
--- /dev/null
+++ b/adapters/beachfront/beachfronttest/supplemental/two-four-combo.json
@@ -0,0 +1,263 @@
+{
+  "mockBidRequest": {
+    "id": "two-four-combo",
+    "imp": [
+      {
+        "id": "ComboADMVideoWithBannerImp1",
+        "ext": {
+          "bidder": {
+            "videoResponseType": "adm",
+            "bidfloor": 1.01,
+            "appIds": {
+              "banner": "bannerAppId1",
+              "video": "videoAppId1"
+            }
+          }
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 300,
+          "h": 400
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 400
+            }
+          ]
+        }
+      },
+      {
+        "id": "ComboNurlVideoWithBannerImp2",
+        "ext": {
+          "bidder": {
+            "videoResponsetype": "nurl",
+            "bidfloor": 1.01,
+            "appIds": {
+              "banner": "bannerAppId2",
+              "video": "videoAppId1"
+            }
+          }
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 100,
+          "h": 150
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 100,
+              "h": 150
+            }
+          ]
+        }
+      }
+    ],
+    "site": {
+      "page": "http://example.com/whatever/something.html"
+    },
+    "device": {
+      "ip": "255.255.255.255"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/prebid_display",
+        "body": {
+          "slots":[
+            {
+              "slot":"ComboADMVideoWithBannerImp1",
+              "id":"bannerAppId1",
+              "bidfloor":1.01,
+              "sizes":[
+                {
+                  "w":300,
+                  "h":400
+                }
+              ]
+            },
+            {
+              "slot":"ComboNurlVideoWithBannerImp2",
+              "id":"bannerAppId2",
+              "bidfloor":1.01,
+              "sizes":[
+                {
+                  "w":100,
+                  "h":150
+                }
+              ]
+            }
+          ],
+          "domain":"example.com",
+          "page":"http://example.com/whatever/something.html",
+          "referrer":"",
+          "search":"",
+          "secure":0,
+          "deviceOs":"",
+          "deviceModel":"",
+          "isMobile":0,
+          "ua":"",
+          "dnt":0,
+          "user":{
+
+          },
+          "adapterName":"BF_PREBID_S2S",
+          "adapterVersion":"0.9.1",
+          "ip":"255.255.255.255",
+          "requestId":"two-four-combo"
+
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+
+        "body": [
+          {
+            "crid": "crid_1",
+            "price": 2.942808,
+            "w": 300,
+            "h": 250,
+            "slot": "div-gpt-ad-1460505748561-0",
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
+          },
+          {
+            "crid": "crid_1",
+            "price": 2.942808,
+            "w": 300,
+            "h": 250,
+            "slot": "div-gpt-ad-1460505748561-0",
+            "adm": "<div id=\"44861168\"><script>!function(){console.log\"Hello, ad.\";}();<\/script><\/div>"
+          }
+        ]
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1",
+        "body": {
+          "id":"two-four-combo",
+          "imp":[
+            {
+              "id":"ComboADMVideoWithBannerImp1",
+              "video":{
+                "mimes":[
+                  "video/mp4"
+                ],
+                "w":300,
+                "h":400
+              },
+              "bidfloor":1.01,
+              "secure":0
+            }
+          ],
+          "site":{
+            "domain":"example.com",
+            "page":"http://example.com/whatever/something.html"
+          },
+          "device":{
+            "devicetype": 2,
+            "ip":"255.255.255.255"
+          },
+          "cur":[
+            "USD"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id":"two-four-combo",
+          "seatbid":[
+            {
+              "bid":[
+                {
+                  "id":"5fe7ad26d49d461ab0544836",
+                  "impid":"ComboADMVideoWithBannerImp1",
+                  "price":2.5500002,
+                  "adm": "<VAST version=\"2.0\"><Ad><Wrapper>http://example.com/vast.xml</Wrapper></Ad></VAST>",
+                  "adid":"22873",
+                  "adomain":[
+                    "nintendo.com"
+                  ],
+                  "cid":"6095",
+                  "crid":"0",
+                  "cat":[
+                    "IAB9-30"
+                  ],
+                  "w":300,
+                  "h":400,
+                  "ext":{
+                    "duration":15
+                  }
+                }
+              ],
+              "seat":"bfb-io-s1"
+            }
+          ],
+          "bidid":"5fe7ad26d49d461ab0544836",
+          "cur":"USD"
+        }
+      }
+    },
+    {
+      "expectedRequest":  {
+        "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1&prebidserver",
+        "body": {
+          "isPrebid":true,
+          "id":"two-four-combo",
+          "imp":[
+            {
+              "id":"ComboNurlVideoWithBannerImp2",
+              "video":{
+                "mimes":[
+                  "video/mp4"
+                ],
+                "w":100,
+                "h":150
+              },
+              "bidfloor":1.01,
+              "secure":0
+            }
+          ],
+          "site":{
+            "domain":"example.com",
+            "page":"http://example.com/whatever/something.html"
+          },
+          "device":{
+            "devicetype": 2,
+            "ip":"255.255.255.255"
+          },
+          "cur":[
+            "USD"
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id":"two-four-combo",
+          "seatBid":[
+            {
+              "bid":[
+                {
+                  "id":"ComboNurlVideoWithBannerImp2",
+                  "price":2.4700302,
+                  "nurl":"https://useast.bfmio.com/getmu?aid=bid:747f49a2-7a15-40bd-a43f-b8576eaa0368:2096a4df-d32c-4b7b-b46c-f4b5d717327a:2.5500002:2.5500002&v=1&dsp=5fe7a6ab3f06cc571bf5c897,1.01&i_type=pre",
+                  "w":300,
+                  "h":400
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-banner.json b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-banner.json
index fc1bb910..8d07852b 100644
--- a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-banner.json
+++ b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-banner.json
@@ -2,7 +2,7 @@
   "mockBidRequest": {
     "id": "some_test_ad",
     "site": {
-      "page": "https://test.opposingviews.com/i/society/republican-sen-collins-may-change-vote-tax-bill?cb=1234534"
+      "page": "https://some.domain.us/some/page.html"
     },
     "imp": [
       {
@@ -19,7 +19,7 @@
         "ext": {
           "bidder": {
             "bidfloor": 0.02,
-            "appId": 123456789101112
+            "appId": 123456
           }
         }
       }
diff --git a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-but-another-good-video.json b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-but-another-good-video.json
deleted file mode 100644
index 963a2adc..00000000
--- a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-but-another-good-video.json
+++ /dev/null
@@ -1,172 +0,0 @@
-{
-  "mockBidRequest": {
-    "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-    "imp": [
-      {
-        "bidfloor": 0.02,
-        "id": "looser",
-        "video":{
-          "mimes":[
-            "video/mp4"
-          ],
-          "context":"instream",
-          "w":300,
-          "h":250
-        },
-        "ext": {
-          "bidder": {
-            "some": "other thing",
-            "bidfloor": "One MILLION dollars, ha, ha ha, ha, ha ha!",
-            "appId": {
-              "not": "the object",
-              "you": "were looking for"
-            }
-          }
-        }
-      },
-     {
-        "id":"video2",
-        "ext":{
-          "bidder":{
-            "bidfloor":0.01,
-            "appId":"11bc5dd5-7421-4dd8-c926-40fa653bec76"
-          }
-        },
-        "video":{
-          "mimes":[
-            "video/mp4", "video/webm"
-          ],
-          "context":"instream",
-          "w":600,
-          "h":450
-        }
-      }
-    ],
-    "site": {
-      "domain": "example.com",
-      "page": "http://example.com/whatever"
-    },
-    "device": {
-      "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-      "ip": "127.0.0.1",
-      "js": 1
-    },
-    "cur": [
-      "USD"
-    ],
-    "user": {
-      "id": "some-user",
-      "buyeruid": "some-buyer"
-    }
-  },
-
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri": "https://reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76&prebidserver",
-        "body": {
-          "isPrebid": true,
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "imp": [
-            {
-              "video": {
-                "w": 600,
-                "h": 450,
-                "mimes": [
-                  "video/mp4",
-                  "video/webm"
-                ]
-              },
-              "id": "video2",
-              "secure": 0
-            }
-          ],
-          "site": {
-            "domain": "example.com",
-            "page": "http://example.com/whatever"
-          },
-          "device": {
-            "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
-            "ip": "192.168.255.255",
-            "devicetype": 2,
-            "js": 1
-          },
-          "cur": [
-            "USD"
-          ],
-          "user": {
-            "id": "some-user",
-            "buyeruid": "some-buyer"
-          }
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "seatBid": [
-            {
-              "bid": [
-                {
-                  "w": 0,
-                  "h": 0,
-                  "id": "0",
-                  "impid": "",
-                  "price": 0.01,
-                  "adid": "",
-                  "nurl": "https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
-                  "adm": "",
-                  "adomain": [],
-                  "iurl": "",
-                  "cid": "",
-                  "crid": "",
-                  "attr": [],
-                  "ext": {},
-                  "cat": []
-                }
-              ],
-              "seat": "",
-              "group": 0,
-              "ext": {
-              }
-            }
-          ]
-        }
-      }
-    }
-  ],
-
-
-  "expectedBids": [
-    {
-
-      "bid":[
-        {
-          "id":"61b87329-8790-47b7-90dd-c53ae7ce1723",
-          "impid":"video2",
-          "price":9.605201,
-          "nurl":"https://evt.bfmio.com/getmu?aid=bid:0d32aea6-d199-4803-a188-bd7cf7be1e12:11bc5dd5-7421-4dd8-c926-40fa653bec76:0.01:0.01&v=1&dsp=5afda03c7c2d2bfaee55a3f0,0.01&i_type=pre",
-          "crid":"video10d32aea6-d199-4803-a188-bd7cf7be1e12",
-          "w":1500,
-          "h":1280,
-          "ext":{
-            "prebid":{
-              "type":"video"
-            },
-            "bidder":{
-
-            }
-          }
-        }
-      ]
-    }
-  ],
-
-
-  "expectedMakeRequestsErrors": [
-    {
-      "value": "ignoring imp id=looser, error while decoding extImpBeachfront, err: json: cannot unmarshal string into Go struct field ExtImpBeachfront.bidfloor of type float64",
-      "comparison": "literal"
-    }
-  ]
-}
diff --git a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-video.json b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-video.json
index 3082ff20..73ac2032 100644
--- a/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-video.json
+++ b/adapters/beachfront/beachfronttest/supplemental/unmarshal-error-video.json
@@ -2,7 +2,7 @@
   "mockBidRequest": {
     "id": "some_test_ad",
     "site": {
-      "page": "https://example.com/whatever"
+      "page": "https://some.domain.us/some/page.html"
     },
     "imp": [
       {
diff --git a/endpoints/auction_test.go b/endpoints/auction_test.go
index 6a237e39..db26a84b 100644
--- a/endpoints/auction_test.go
+++ b/endpoints/auction_test.go
@@ -349,7 +349,7 @@ func TestCacheVideoOnly(t *testing.T) {
 		t.Fatal(err.Error())
 	}
 	syncers := usersyncers.NewSyncerMap(cfg)
-	gdprPerms := gdpr.NewPermissions(nil, config.GDPR{
+	gdprPerms := gdpr.NewPermissions(context.Background(), config.GDPR{
 		HostVendorID: 0,
 	}, nil, nil)
 	prebid_cache_client.InitPrebidCache(server.URL)
diff --git a/endpoints/openrtb2/auction_benchmark_test.go b/endpoints/openrtb2/auction_benchmark_test.go
index 51f35316..b42e45b6 100644
--- a/endpoints/openrtb2/auction_benchmark_test.go
+++ b/endpoints/openrtb2/auction_benchmark_test.go
@@ -77,6 +77,7 @@ func BenchmarkOpenrtbEndpoint(b *testing.B) {
 		nil,
 		&config.Configuration{},
 		newTestMetrics(),
+		infos,
 		gdpr.AlwaysAllow{},
 		currency.NewRateConverter(&http.Client{}, "", time.Duration(0)),
 		empty_fetcher.EmptyFetcher{},
diff --git a/exchange/auction_test.go b/exchange/auction_test.go
index cdd6a6ca..7e8a8a8c 100644
--- a/exchange/auction_test.go
+++ b/exchange/auction_test.go
@@ -6,9 +6,9 @@ import (
 	"encoding/xml"
 	"fmt"
 	"io/ioutil"
+	"path/filepath"
 	"regexp"
 	"strconv"
-	"strings"
 	"testing"
 
 	"github.com/prebid/prebid-server/config"
@@ -100,57 +100,21 @@ func TestBuildCacheString(t *testing.T) {
 // TestCacheJSON executes tests for all the *.json files in cachetest.
 // customcachekey.json test here verifies custom cache key not used for non-vast video
 func TestCacheJSON(t *testing.T) {
-	if specFiles, err := ioutil.ReadDir("./cachetest"); err == nil {
-		for _, specFile := range specFiles {
-			fileName := "./cachetest/" + specFile.Name()
-			fileDisplayName := "exchange/cachetest/" + specFile.Name()
-			specData, err := loadCacheSpec(fileName)
-			if err != nil {
-				t.Fatalf("Failed to load contents of file %s: %v", fileDisplayName, err)
+	for _, dir := range []string{"cachetest", "customcachekeytest", "impcustomcachekeytest", "eventscachetest"} {
+		if specFiles, err := ioutil.ReadDir(dir); err == nil {
+			for _, specFile := range specFiles {
+				fileName := filepath.Join(dir, specFile.Name())
+				fileDisplayName := "exchange/" + fileName
+				t.Run(fileDisplayName, func(t *testing.T) {
+					specData, err := loadCacheSpec(fileName)
+					if assert.NoError(t, err, "Failed to load contents of file %s: %v", fileDisplayName, err) {
+						runCacheSpec(t, fileDisplayName, specData)
+					}
+				})
 			}
-
-			runCacheSpec(t, fileDisplayName, specData)
-		}
-	} else {
-		t.Fatalf("Failed to read contents of directory exchange/cachetest/: %v", err)
-	}
-}
-
-// TestCacheJSON executes tests for all the *.json files in customcachekeytest.
-// customcachekey.json test here verifies custom cache key is used for vast video
-func TestCustomCacheKeyJSON(t *testing.T) {
-	if specFiles, err := ioutil.ReadDir("./customcachekeytest"); err == nil {
-		for _, specFile := range specFiles {
-			fileName := "./customcachekeytest/" + specFile.Name()
-			fileDisplayName := "exchange/customcachekeytest/" + specFile.Name()
-			specData, err := loadCacheSpec(fileName)
-			if err != nil {
-				t.Fatalf("Failed to load contents of file %s: %v", fileDisplayName, err)
-			}
-
-			runCacheSpec(t, fileDisplayName, specData)
-		}
-	} else {
-		t.Fatalf("Failed to read contents of directory exchange/customcachekeytest/: %v", err)
-	}
-}
-
-// TestMultiImpCache executes multi-Imp test cases found in *.json files in
-// impcustomcachekeytest.
-func TestCustomCacheKeyMultiImp(t *testing.T) {
-	if specFiles, err := ioutil.ReadDir("./impcustomcachekeytest"); err == nil {
-		for _, specFile := range specFiles {
-			fileName := "./impcustomcachekeytest/" + specFile.Name()
-			fileDisplayName := "exchange/impcustomcachekeytest/" + specFile.Name()
-			multiImpSpecData, err := loadCacheSpec(fileName)
-			if err != nil {
-				t.Fatalf("Failed to load contents of file %s: %v", fileDisplayName, err)
-			}
-
-			runCacheSpec(t, fileDisplayName, multiImpSpecData)
+		} else {
+			t.Fatalf("Failed to read contents of directory exchange/%s: %v", dir, err)
 		}
-	} else {
-		t.Fatalf("Failed to read contents of directory exchange/customcachekeytest/: %v", err)
 	}
 }
 
@@ -169,9 +133,8 @@ func loadCacheSpec(filename string) (*cacheSpec, error) {
 	return &spec, nil
 }
 
-// runCacheSpec has been modified to handle multi-Imp and multi-bid Json test files,
-// it cycles through the bids found in the test cases hardcoded in json files and
-// finds the highest bid of every Imp.
+// runCacheSpec cycles through the bids found in the json test cases and
+// finds the highest bid of every Imp, then tests doCache() with resulting auction object
 func runCacheSpec(t *testing.T, fileDisplayName string, specData *cacheSpec) {
 	var bid *pbsOrtbBid
 	winningBidsByImp := make(map[string]*pbsOrtbBid)
@@ -245,7 +208,14 @@ func runCacheSpec(t *testing.T, fileDisplayName string, specData *cacheSpec) {
 		winningBidsByBidder: winningBidsByBidder,
 		roundedPrices:       roundedPrices,
 	}
-	_ = testAuction.doCache(ctx, cache, targData, &specData.BidRequest, 60, &specData.DefaultTTLs, bidCategory, &specData.DebugLog)
+	evTracking := &eventTracking{
+		accountID:          "TEST_ACC_ID",
+		enabledForAccount:  specData.EventsDataEnabledForAccount,
+		enabledForRequest:  specData.EventsDataEnabledForRequest,
+		externalURL:        "http://localhost",
+		auctionTimestampMs: 1234567890,
+	}
+	_ = testAuction.doCache(ctx, cache, targData, evTracking, &specData.BidRequest, 60, &specData.DefaultTTLs, bidCategory, &specData.DebugLog)
 
 	if len(specData.ExpectedCacheables) > len(cache.items) {
 		t.Errorf("%s:  [CACHE_ERROR] Less elements were cached than expected \n", fileDisplayName)
@@ -254,27 +224,43 @@ func runCacheSpec(t *testing.T, fileDisplayName string, specData *cacheSpec) {
 	} else { // len(specData.ExpectedCacheables) == len(cache.items)
 		// We cached the exact number of elements we expected, now we compare them side by side in n^2
 		var matched int = 0
-		var formattedExpectedData string
-		for i := 0; i < len(specData.ExpectedCacheables); i++ {
-			if specData.ExpectedCacheables[i].Type == prebid_cache_client.TypeJSON {
-				ExpectedData := strings.Replace(string(specData.ExpectedCacheables[i].Data), "\\", "", -1)
-				ExpectedData = strings.Replace(ExpectedData, " ", "", -1)
-				formattedExpectedData = ExpectedData[1 : len(ExpectedData)-1]
-			} else {
-				formattedExpectedData = string(specData.ExpectedCacheables[i].Data)
+		for i, expectedCacheable := range specData.ExpectedCacheables {
+			found := false
+			var expectedData interface{}
+			if err := json.Unmarshal(expectedCacheable.Data, &expectedData); err != nil {
+				t.Fatalf("Failed to decode expectedCacheables[%d].value: %v", i, err)
 			}
-			for j := 0; j < len(cache.items); j++ {
-				if formattedExpectedData == string(cache.items[j].Data) &&
-					specData.ExpectedCacheables[i].TTLSeconds == cache.items[j].TTLSeconds &&
-					specData.ExpectedCacheables[i].Type == cache.items[j].Type &&
-					len(specData.ExpectedCacheables[i].Key) <= len(cache.items[j].Key) &&
-					specData.ExpectedCacheables[i].Key == cache.items[j].Key[:len(specData.ExpectedCacheables[i].Key)] {
-					matched++
+			if s, ok := expectedData.(string); ok && expectedCacheable.Type == prebid_cache_client.TypeJSON {
+				// decode again if we have pre-encoded json string values
+				if err := json.Unmarshal([]byte(s), &expectedData); err != nil {
+					t.Fatalf("Failed to re-decode expectedCacheables[%d].value :%v", i, err)
 				}
 			}
+			for j, cachedItem := range cache.items {
+				var actualData interface{}
+				if err := json.Unmarshal(cachedItem.Data, &actualData); err != nil {
+					t.Fatalf("Failed to decode actual cache[%d].value: %s", j, err)
+				}
+				if assert.ObjectsAreEqual(expectedData, actualData) &&
+					expectedCacheable.TTLSeconds == cachedItem.TTLSeconds &&
+					expectedCacheable.Type == cachedItem.Type &&
+					len(expectedCacheable.Key) <= len(cachedItem.Key) &&
+					expectedCacheable.Key == cachedItem.Key[:len(expectedCacheable.Key)] {
+					found = true
+					cache.items = append(cache.items[:j], cache.items[j+1:]...) // remove matched item
+					break
+				}
+			}
+			if found {
+				matched++
+			} else {
+				t.Errorf("%s: [CACHE_ERROR] Did not see expected cacheable #%d: type=%s, ttl=%d, value=%s", fileDisplayName, i, expectedCacheable.Type, expectedCacheable.TTLSeconds, string(expectedCacheable.Data))
+			}
 		}
 		if matched != len(specData.ExpectedCacheables) {
-			t.Errorf("%s: [CACHE_ERROR] One or more keys were not cached as we expected \n", fileDisplayName)
+			for i, item := range cache.items {
+				t.Errorf("%s: [CACHE_ERROR] Got unexpected cached item #%d: type=%s, ttl=%d, value=%s", fileDisplayName, i, item.Type, item.TTLSeconds, string(item.Data))
+			}
 			t.FailNow()
 		}
 	}
@@ -508,6 +494,8 @@ type cacheSpec struct {
 	TargetDataIncludeBidderKeys bool                            `json:"targetDataIncludeBidderKeys"`
 	TargetDataIncludeCacheBids  bool                            `json:"targetDataIncludeCacheBids"`
 	TargetDataIncludeCacheVast  bool                            `json:"targetDataIncludeCacheVast"`
+	EventsDataEnabledForAccount bool                            `json:"eventsDataEnabledForAccount"`
+	EventsDataEnabledForRequest bool                            `json:"eventsDataEnabledForRequest"`
 	DebugLog                    DebugLog                        `json:"debugLog,omitempty"`
 }
 
diff --git a/exchange/events_test.go b/exchange/events_test.go
new file mode 100644
index 00000000..1d72739d
--- /dev/null
+++ b/exchange/events_test.go
@@ -0,0 +1,138 @@
+package exchange
+
+import (
+	"testing"
+
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_eventsData_makeBidExtEvents(t *testing.T) {
+	type args struct {
+		enabledForAccount bool
+		enabledForRequest bool
+		bidType           openrtb_ext.BidType
+	}
+	tests := []struct {
+		name string
+		args args
+		want *openrtb_ext.ExtBidPrebidEvents
+	}{
+		{
+			name: "banner: events enabled for request, disabled for account",
+			args: args{enabledForAccount: false, enabledForRequest: true, bidType: openrtb_ext.BidTypeBanner},
+			want: &openrtb_ext.ExtBidPrebidEvents{
+				Win: "http://localhost/event?t=win&b=BID-1&a=123456&bidder=openx&ts=1234567890",
+				Imp: "http://localhost/event?t=imp&b=BID-1&a=123456&bidder=openx&ts=1234567890",
+			},
+		},
+		{
+			name: "banner: events enabled for account, disabled for request",
+			args: args{enabledForAccount: true, enabledForRequest: false, bidType: openrtb_ext.BidTypeBanner},
+			want: &openrtb_ext.ExtBidPrebidEvents{
+				Win: "http://localhost/event?t=win&b=BID-1&a=123456&bidder=openx&ts=1234567890",
+				Imp: "http://localhost/event?t=imp&b=BID-1&a=123456&bidder=openx&ts=1234567890",
+			},
+		},
+		{
+			name: "banner: events disabled for account and request",
+			args: args{enabledForAccount: false, enabledForRequest: false, bidType: openrtb_ext.BidTypeBanner},
+			want: nil,
+		},
+		{
+			name: "video: events enabled for account and request",
+			args: args{enabledForAccount: true, enabledForRequest: true, bidType: openrtb_ext.BidTypeVideo},
+			want: nil,
+		},
+		{
+			name: "video: events disabled for account and request",
+			args: args{enabledForAccount: false, enabledForRequest: false, bidType: openrtb_ext.BidTypeVideo},
+			want: nil,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			evData := &eventTracking{
+				enabledForAccount:  tt.args.enabledForAccount,
+				enabledForRequest:  tt.args.enabledForRequest,
+				accountID:          "123456",
+				auctionTimestampMs: 1234567890,
+				externalURL:        "http://localhost",
+			}
+			bid := &pbsOrtbBid{bid: &openrtb.Bid{ID: "BID-1"}, bidType: tt.args.bidType}
+			assert.Equal(t, tt.want, evData.makeBidExtEvents(bid, openrtb_ext.BidderOpenx))
+		})
+	}
+}
+
+func Test_eventsData_modifyBidJSON(t *testing.T) {
+	type args struct {
+		enabledForAccount bool
+		enabledForRequest bool
+		bidType           openrtb_ext.BidType
+	}
+	tests := []struct {
+		name      string
+		args      args
+		jsonBytes []byte
+		want      []byte
+	}{
+		{
+			name:      "banner: events enabled for request, disabled for account",
+			args:      args{enabledForAccount: false, enabledForRequest: true, bidType: openrtb_ext.BidTypeBanner},
+			jsonBytes: []byte(`{"ID": "something"}`),
+			want:      []byte(`{"ID": "something", "wurl": "http://localhost/event?t=win&b=BID-1&a=123456&bidder=openx&ts=1234567890"}`),
+		},
+		{
+			name:      "banner: events enabled for account, disabled for request",
+			args:      args{enabledForAccount: true, enabledForRequest: false, bidType: openrtb_ext.BidTypeBanner},
+			jsonBytes: []byte(`{"ID": "something"}`),
+			want:      []byte(`{"ID": "something", "wurl": "http://localhost/event?t=win&b=BID-1&a=123456&bidder=openx&ts=1234567890"}`),
+		},
+		{
+			name:      "banner: events disabled for account and request",
+			args:      args{enabledForAccount: false, enabledForRequest: false, bidType: openrtb_ext.BidTypeBanner},
+			jsonBytes: []byte(`{"ID": "something"}`),
+			want:      []byte(`{"ID": "something"}`),
+		},
+		{
+			name:      "video: events disabled for account and request",
+			args:      args{enabledForAccount: false, enabledForRequest: false, bidType: openrtb_ext.BidTypeVideo},
+			jsonBytes: []byte(`{"ID": "something"}`),
+			want:      []byte(`{"ID": "something"}`),
+		},
+		{
+			name:      "video: events enabled for account and request",
+			args:      args{enabledForAccount: true, enabledForRequest: true, bidType: openrtb_ext.BidTypeVideo},
+			jsonBytes: []byte(`{"ID": "something"}`),
+			want:      []byte(`{"ID": "something"}`),
+		},
+		{
+			name:      "banner: broken json expected to fail patching",
+			args:      args{enabledForAccount: true, enabledForRequest: true, bidType: openrtb_ext.BidTypeBanner},
+			jsonBytes: []byte(`broken json`),
+			want:      nil,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			evData := &eventTracking{
+				enabledForAccount:  tt.args.enabledForAccount,
+				enabledForRequest:  tt.args.enabledForRequest,
+				accountID:          "123456",
+				auctionTimestampMs: 1234567890,
+				externalURL:        "http://localhost",
+			}
+			bid := &pbsOrtbBid{bid: &openrtb.Bid{ID: "BID-1"}, bidType: tt.args.bidType}
+			modifiedJSON, err := evData.modifyBidJSON(bid, openrtb_ext.BidderOpenx, tt.jsonBytes)
+			if tt.want != nil {
+				assert.NoError(t, err, "Unexpected error")
+				assert.JSONEq(t, string(tt.want), string(modifiedJSON))
+			} else {
+				assert.Error(t, err)
+				assert.Equal(t, string(tt.jsonBytes), string(modifiedJSON), "Expected original json on failure to modify")
+			}
+		})
+	}
+}
diff --git a/exchange/eventscachetest/json-account-off-request-off.json b/exchange/eventscachetest/json-account-off-request-off.json
new file mode 100644
index 00000000..9d7af624
--- /dev/null
+++ b/exchange/eventscachetest/json-account-off-request-off.json
@@ -0,0 +1,49 @@
+{
+    "bidRequest": {
+        "imp": [{
+            "id":  "oneImp"
+        }]
+    },
+    "pbsBids": [{
+        "bid":{
+            "id": "bidOne",
+            "impid": "oneImp",
+            "price": 7.64,
+            "exp":   600
+        },
+        "bidType": "banner",
+        "bidder": "appnexus"
+    }, {
+        "bid": {
+            "id": "bidTwo",
+            "impid": "oneImp",
+            "price": 5.64
+        },
+        "bidType": "banner",
+        "bidder": "pubmatic"
+    }],
+    "expectedCacheables": [
+        {
+            "type": "json",
+            "ttlseconds": 660,
+            "value":{ "id": "bidOne", "impid": "oneImp", "price": 7.64, "exp": 600}
+        }, {
+            "type": "json",
+            "ttlseconds": 360,
+            "value": { "id": "bidTwo", "impid": "oneImp", "price": 5.64}
+        }
+    ],
+    "defaultTTLs": {
+        "banner": 300,
+        "video": 3600,
+        "audio": 1800,
+        "native": 300
+    },
+    "targetDataIncludeWinners":true,
+    "targetDataIncludeBidderKeys":true,
+    "targetDataIncludeCacheBids":true,
+    "targetDataIncludeCacheVast":false,
+    "eventsDataEnabledForAccount": false,
+    "eventsDataEnabledForRequest": false
+}
+
diff --git a/exchange/eventscachetest/json-account-off-request-on.json b/exchange/eventscachetest/json-account-off-request-on.json
new file mode 100644
index 00000000..3c69c499
--- /dev/null
+++ b/exchange/eventscachetest/json-account-off-request-on.json
@@ -0,0 +1,49 @@
+{
+    "bidRequest": {
+        "imp": [{
+            "id":  "oneImp"
+        }]
+    },
+    "pbsBids": [{
+        "bid":{
+            "id": "bidOne",
+            "impid": "oneImp",
+            "price": 7.64,
+            "exp":   600
+        },
+        "bidType": "banner",
+        "bidder": "appnexus"
+    }, {
+        "bid": {
+            "id": "bidTwo",
+            "impid": "oneImp",
+            "price": 5.64
+        },
+        "bidType": "banner",
+        "bidder": "pubmatic"
+    }],
+    "expectedCacheables": [
+        {
+            "type": "json",
+            "ttlseconds": 660,
+            "value":{ "id": "bidOne", "impid": "oneImp", "price": 7.64, "exp": 600, "wurl": "http://localhost/event?t=win&b=bidOne&a=TEST_ACC_ID&bidder=appnexus&ts=1234567890"}
+        }, {
+            "type": "json",
+            "ttlseconds": 360,
+            "value": { "id": "bidTwo", "impid": "oneImp", "price": 5.64, "wurl": "http://localhost/event?t=win&b=bidTwo&a=TEST_ACC_ID&bidder=pubmatic&ts=1234567890"}
+        }
+    ],
+    "defaultTTLs": {
+        "banner": 300,
+        "video": 3600,
+        "audio": 1800,
+        "native": 300
+    },
+    "targetDataIncludeWinners":true,
+    "targetDataIncludeBidderKeys":true,
+    "targetDataIncludeCacheBids":true,
+    "targetDataIncludeCacheVast":false,
+    "eventsDataEnabledForAccount": false,
+    "eventsDataEnabledForRequest": true
+}
+
diff --git a/exchange/eventscachetest/json-account-on-request-off.json b/exchange/eventscachetest/json-account-on-request-off.json
new file mode 100644
index 00000000..e193c0b8
--- /dev/null
+++ b/exchange/eventscachetest/json-account-on-request-off.json
@@ -0,0 +1,49 @@
+{
+    "bidRequest": {
+        "imp": [{
+            "id":  "oneImp"
+        }]
+    },
+    "pbsBids": [{
+        "bid":{
+            "id": "bidOne",
+            "impid": "oneImp",
+            "price": 7.64,
+            "exp":   600
+        },
+        "bidType": "banner",
+        "bidder": "appnexus"
+    }, {
+        "bid": {
+            "id": "bidTwo",
+            "impid": "oneImp",
+            "price": 5.64
+        },
+        "bidType": "banner",
+        "bidder": "pubmatic"
+    }],
+    "expectedCacheables": [
+        {
+            "type": "json",
+            "ttlseconds": 660,
+            "value":{ "id": "bidOne", "impid": "oneImp", "price": 7.64, "exp": 600, "wurl": "http://localhost/event?t=win&b=bidOne&a=TEST_ACC_ID&bidder=appnexus&ts=1234567890"}
+        }, {
+            "type": "json",
+            "ttlseconds": 360,
+            "value": { "id": "bidTwo", "impid": "oneImp", "price": 5.64, "wurl": "http://localhost/event?t=win&b=bidTwo&a=TEST_ACC_ID&bidder=pubmatic&ts=1234567890"}
+        }
+    ],
+    "defaultTTLs": {
+        "banner": 300,
+        "video": 3600,
+        "audio": 1800,
+        "native": 300
+    },
+    "targetDataIncludeWinners":true,
+    "targetDataIncludeBidderKeys":true,
+    "targetDataIncludeCacheBids":true,
+    "targetDataIncludeCacheVast":false,
+    "eventsDataEnabledForAccount": true,
+    "eventsDataEnabledForRequest": false
+}
+
diff --git a/exchange/eventscachetest/json-account-on-request-on.json b/exchange/eventscachetest/json-account-on-request-on.json
new file mode 100644
index 00000000..807c517b
--- /dev/null
+++ b/exchange/eventscachetest/json-account-on-request-on.json
@@ -0,0 +1,49 @@
+{
+    "bidRequest": {
+        "imp": [{
+            "id":  "oneImp"
+        }]
+    },
+    "pbsBids": [{
+        "bid":{
+            "id": "bidOne",
+            "impid": "oneImp",
+            "price": 7.64,
+            "exp":   600
+        },
+        "bidType": "banner",
+        "bidder": "appnexus"
+    }, {
+        "bid": {
+            "id": "bidTwo",
+            "impid": "oneImp",
+            "price": 5.64
+        },
+        "bidType": "banner",
+        "bidder": "pubmatic"
+    }],
+    "expectedCacheables": [
+        {
+            "type": "json",
+            "ttlseconds": 660,
+            "value": { "id": "bidOne", "impid": "oneImp", "price": 7.64, "exp": 600, "wurl": "http://localhost/event?t=win&b=bidOne&a=TEST_ACC_ID&bidder=appnexus&ts=1234567890"}
+        }, {
+            "type": "json",
+            "ttlseconds": 360,
+            "value": { "id": "bidTwo", "impid": "oneImp", "price": 5.64, "wurl": "http://localhost/event?t=win&b=bidTwo&a=TEST_ACC_ID&bidder=pubmatic&ts=1234567890"}
+        }
+    ],
+    "defaultTTLs": {
+        "banner": 300,
+        "video": 3600,
+        "audio": 1800,
+        "native": 300
+    },
+    "targetDataIncludeWinners":true,
+    "targetDataIncludeBidderKeys":true,
+    "targetDataIncludeCacheBids":true,
+    "targetDataIncludeCacheVast":false,
+    "eventsDataEnabledForAccount": true,
+    "eventsDataEnabledForRequest": true
+}
+
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 5ebe1cc6..416875a1 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -59,7 +59,7 @@ func TestNewExchange(t *testing.T) {
 	}
 
 	currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
-	e := NewExchange(adapters, nil, cfg, &metricsConf.DummyMetricsEngine{}, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
+	e := NewExchange(adapters, nil, cfg, &metricsConf.DummyMetricsEngine{}, biddersInfo, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
 	for _, bidderName := range knownAdapters {
 		if _, ok := e.adapterMap[bidderName]; !ok {
 			t.Errorf("NewExchange produced an Exchange without bidder %s", bidderName)
@@ -103,7 +103,7 @@ func TestCharacterEscape(t *testing.T) {
 	}
 
 	currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
-	e := NewExchange(adapters, nil, cfg, &metricsConf.DummyMetricsEngine{}, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
+	e := NewExchange(adapters, nil, cfg, &metricsConf.DummyMetricsEngine{}, biddersInfo, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
 
 	/* 	3) Build all the parameters e.buildBidResponse(ctx.Background(), liveA... ) needs */
 	//liveAdapters []openrtb_ext.BidderName,
@@ -529,7 +529,7 @@ func TestGetBidCacheInfoEndToEnd(t *testing.T) {
 	}
 	currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
 	pbc := pbc.NewClient(&http.Client{}, &cfg.CacheURL, &cfg.ExtCacheURL, testEngine)
-	e := NewExchange(adapters, pbc, cfg, &metricsConf.DummyMetricsEngine{}, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
+	e := NewExchange(adapters, pbc, cfg, &metricsConf.DummyMetricsEngine{}, biddersInfo, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
 	/* 	3) Build all the parameters e.buildBidResponse(ctx.Background(), liveA... ) needs */
 	liveAdapters := []openrtb_ext.BidderName{bidderName}
 
@@ -878,7 +878,7 @@ func TestBidResponseCurrency(t *testing.T) {
 	}
 
 	currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
-	e := NewExchange(adapters, nil, cfg, &metricsConf.DummyMetricsEngine{}, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
+	e := NewExchange(adapters, nil, cfg, &metricsConf.DummyMetricsEngine{}, biddersInfo, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
 
 	liveAdapters := make([]openrtb_ext.BidderName, 1)
 	liveAdapters[0] = "appnexus"
@@ -1059,7 +1059,7 @@ func TestRaceIntegration(t *testing.T) {
 		UserSyncs:  &emptyUsersync{},
 	}
 
-	ex := NewExchange(adapters, &wellBehavedCache{}, cfg, &metricsConf.DummyMetricsEngine{}, gdpr.AlwaysAllow{}, currencyConverter, &nilCategoryFetcher{}).(*exchange)
+	ex := NewExchange(adapters, &wellBehavedCache{}, cfg, &metricsConf.DummyMetricsEngine{}, biddersInfo, gdpr.AlwaysAllow{}, currencyConverter, &nilCategoryFetcher{}).(*exchange)
 	_, err := ex.HoldAuction(context.Background(), auctionRequest, nil)
 	if err != nil {
 		t.Errorf("HoldAuction returned unexpected error: %v", err)
@@ -1149,7 +1149,7 @@ func TestPanicRecovery(t *testing.T) {
 	}
 
 	currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
-	e := NewExchange(adapters, nil, cfg, &metricsConf.DummyMetricsEngine{}, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
+	e := NewExchange(adapters, nil, cfg, &metricsConf.DummyMetricsEngine{}, biddersInfo, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange)
 
 	chBids := make(chan *bidResponseWrapper, 1)
 	panicker := func(bidderRequest BidderRequest, conversions currency.Conversions) {
@@ -1241,7 +1241,7 @@ func TestPanicRecoveryHighLevel(t *testing.T) {
 		t.Errorf("Failed to create a category Fetcher: %v", error)
 	}
 
-	e := NewExchange(adapters, &mockCache{}, cfg, &metricsConf.DummyMetricsEngine{}, gdpr.AlwaysAllow{}, currencyConverter, categoriesFetcher).(*exchange)
+	e := NewExchange(adapters, &mockCache{}, cfg, &metricsConf.DummyMetricsEngine{}, biddersInfo, gdpr.AlwaysAllow{}, currencyConverter, categoriesFetcher).(*exchange)
 
 	e.adapterMap[openrtb_ext.BidderBeachfront] = panicingAdapter{}
 	e.adapterMap[openrtb_ext.BidderAppnexus] = panicingAdapter{}
@@ -1342,12 +1342,12 @@ func TestExchangeJSON(t *testing.T) {
 		for _, specFile := range specFiles {
 			fileName := "./exchangetest/" + specFile.Name()
 			fileDisplayName := "exchange/exchangetest/" + specFile.Name()
-			specData, err := loadFile(fileName)
-			if err != nil {
-				t.Fatalf("Failed to load contents of file %s: %v", fileDisplayName, err)
-			}
-
-			runSpec(t, fileDisplayName, specData)
+			t.Run(fileDisplayName, func(t *testing.T) {
+				specData, err := loadFile(fileName)
+				if assert.NoError(t, err, "Failed to load contents of file %s: %v", fileDisplayName, err) {
+					runSpec(t, fileDisplayName, specData)
+				}
+			})
 		}
 	}
 }
@@ -1403,8 +1403,14 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) {
 
 	auctionRequest := AuctionRequest{
 		BidRequest: &spec.IncomingRequest.OrtbRequest,
-		Account:    config.Account{},
-		UserSyncs:  mockIdFetcher(spec.IncomingRequest.Usersyncs),
+		Account: config.Account{
+			ID:            "testaccount",
+			EventsEnabled: spec.EventsEnabled,
+		},
+		UserSyncs: mockIdFetcher(spec.IncomingRequest.Usersyncs),
+	}
+	if spec.StartTime > 0 {
+		auctionRequest.StartTime = time.Unix(0, spec.StartTime*1e+6)
 	}
 
 	bid, err := ex.HoldAuction(context.Background(), auctionRequest, debugLog)
@@ -1482,26 +1488,28 @@ func extractResponseTimes(t *testing.T, context string, bid *openrtb.BidResponse
 }
 
 func newExchangeForTests(t *testing.T, filename string, expectations map[string]*bidderSpec, aliases map[string]string, privacyConfig config.Privacy) Exchange {
-	adapters := make(map[openrtb_ext.BidderName]adaptedBidder)
+	bidderAdapters := make(map[openrtb_ext.BidderName]adaptedBidder, len(expectations))
+	bidderInfos := make(adapters.BidderInfos, len(expectations))
 	for _, bidderName := range openrtb_ext.CoreBidderNames() {
 		if spec, ok := expectations[string(bidderName)]; ok {
-			adapters[bidderName] = &validatingBidder{
+			bidderAdapters[bidderName] = &validatingBidder{
 				t:             t,
 				fileName:      filename,
 				bidderName:    string(bidderName),
 				expectations:  map[string]*bidderRequest{string(bidderName): spec.ExpectedRequest},
 				mockResponses: map[string]bidderResponse{string(bidderName): spec.MockResponse},
 			}
+			bidderInfos[string(bidderName)] = adapters.BidderInfo{ModifyingVastXmlAllowed: spec.ModifyingVastXmlAllowed}
 		}
 	}
 
 	for alias, coreBidder := range aliases {
 		if spec, ok := expectations[alias]; ok {
-			if bidder, ok := adapters[openrtb_ext.BidderName(coreBidder)]; ok {
+			if bidder, ok := bidderAdapters[openrtb_ext.BidderName(coreBidder)]; ok {
 				bidder.(*validatingBidder).expectations[alias] = spec.ExpectedRequest
 				bidder.(*validatingBidder).mockResponses[alias] = spec.MockResponse
 			} else {
-				adapters[openrtb_ext.BidderName(coreBidder)] = &validatingBidder{
+				bidderAdapters[openrtb_ext.BidderName(coreBidder)] = &validatingBidder{
 					t:             t,
 					fileName:      filename,
 					bidderName:    coreBidder,
@@ -1518,7 +1526,7 @@ func newExchangeForTests(t *testing.T, filename string, expectations map[string]
 	}
 
 	return &exchange{
-		adapterMap:          adapters,
+		adapterMap:          bidderAdapters,
 		me:                  metricsConf.NewMetricsEngine(&config.Configuration{}, openrtb_ext.CoreBidderNames()),
 		cache:               &wellBehavedCache{},
 		cacheTime:           0,
@@ -1527,6 +1535,8 @@ func newExchangeForTests(t *testing.T, filename string, expectations map[string]
 		UsersyncIfAmbiguous: privacyConfig.GDPR.UsersyncIfAmbiguous,
 		privacyConfig:       privacyConfig,
 		categoriesFetcher:   categoriesFetcher,
+		bidderInfo:          bidderInfos,
+		externalURL:         "http://localhost",
 	}
 }
 
@@ -1612,10 +1622,10 @@ func TestCategoryMapping(t *testing.T) {
 	bid3 := openrtb.Bid{ID: "bid_id3", ImpID: "imp_id3", Price: 30.0000, Cat: cats3, W: 1, H: 1}
 	bid4 := openrtb.Bid{ID: "bid_id4", ImpID: "imp_id4", Price: 40.0000, Cat: cats4, W: 1, H: 1}
 
-	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, 0, false}
-	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30, PrimaryCategory: "AdapterOverride"}, 0, false}
-	bid1_4 := pbsOrtbBid{&bid4, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
+	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, nil, 0, false}
+	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30, PrimaryCategory: "AdapterOverride"}, nil, 0, false}
+	bid1_4 := pbsOrtbBid{&bid4, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
 
 	innerBids := []*pbsOrtbBid{
 		&bid1_1,
@@ -1667,10 +1677,10 @@ func TestCategoryMappingNoIncludeBrandCategory(t *testing.T) {
 	bid3 := openrtb.Bid{ID: "bid_id3", ImpID: "imp_id3", Price: 30.0000, Cat: cats3, W: 1, H: 1}
 	bid4 := openrtb.Bid{ID: "bid_id4", ImpID: "imp_id4", Price: 40.0000, Cat: cats4, W: 1, H: 1}
 
-	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, 0, false}
-	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30, PrimaryCategory: "AdapterOverride"}, 0, false}
-	bid1_4 := pbsOrtbBid{&bid4, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 50}, 0, false}
+	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, nil, 0, false}
+	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30, PrimaryCategory: "AdapterOverride"}, nil, 0, false}
+	bid1_4 := pbsOrtbBid{&bid4, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 50}, nil, 0, false}
 
 	innerBids := []*pbsOrtbBid{
 		&bid1_1,
@@ -1721,9 +1731,9 @@ func TestCategoryMappingTranslateCategoriesNil(t *testing.T) {
 	bid2 := openrtb.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 20.0000, Cat: cats2, W: 1, H: 1}
 	bid3 := openrtb.Bid{ID: "bid_id3", ImpID: "imp_id3", Price: 30.0000, Cat: cats3, W: 1, H: 1}
 
-	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, 0, false}
-	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
+	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, nil, 0, false}
+	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
 
 	innerBids := []*pbsOrtbBid{
 		&bid1_1,
@@ -1803,9 +1813,9 @@ func TestCategoryMappingTranslateCategoriesFalse(t *testing.T) {
 	bid2 := openrtb.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 20.0000, Cat: cats2, W: 1, H: 1}
 	bid3 := openrtb.Bid{ID: "bid_id3", ImpID: "imp_id3", Price: 30.0000, Cat: cats3, W: 1, H: 1}
 
-	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, 0, false}
-	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
+	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, nil, 0, false}
+	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
 
 	innerBids := []*pbsOrtbBid{
 		&bid1_1,
@@ -1855,11 +1865,11 @@ func TestCategoryDedupe(t *testing.T) {
 	bid4 := openrtb.Bid{ID: "bid_id4", ImpID: "imp_id4", Price: 20.0000, Cat: cats4, W: 1, H: 1}
 	bid5 := openrtb.Bid{ID: "bid_id5", ImpID: "imp_id5", Price: 20.0000, Cat: cats1, W: 1, H: 1}
 
-	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 50}, 0, false}
-	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_4 := pbsOrtbBid{&bid4, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_5 := pbsOrtbBid{&bid5, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
+	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 50}, nil, 0, false}
+	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_4 := pbsOrtbBid{&bid4, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_5 := pbsOrtbBid{&bid5, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
 
 	selectedBids := make(map[string]int)
 	expectedCategories := map[string]string{
@@ -1934,11 +1944,11 @@ func TestNoCategoryDedupe(t *testing.T) {
 	bid4 := openrtb.Bid{ID: "bid_id4", ImpID: "imp_id4", Price: 20.0000, Cat: cats4, W: 1, H: 1}
 	bid5 := openrtb.Bid{ID: "bid_id5", ImpID: "imp_id5", Price: 10.0000, Cat: cats1, W: 1, H: 1}
 
-	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_4 := pbsOrtbBid{&bid4, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_5 := pbsOrtbBid{&bid5, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
+	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_3 := pbsOrtbBid{&bid3, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_4 := pbsOrtbBid{&bid4, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_5 := pbsOrtbBid{&bid5, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
 
 	selectedBids := make(map[string]int)
 	expectedCategories := map[string]string{
@@ -2014,8 +2024,8 @@ func TestCategoryMappingBidderName(t *testing.T) {
 	bid1 := openrtb.Bid{ID: "bid_id1", ImpID: "imp_id1", Price: 10.0000, Cat: cats1, W: 1, H: 1}
 	bid2 := openrtb.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 10.0000, Cat: cats2, W: 1, H: 1}
 
-	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
+	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
 
 	innerBids1 := []*pbsOrtbBid{
 		&bid1_1,
@@ -2068,8 +2078,8 @@ func TestCategoryMappingBidderNameNoCategories(t *testing.T) {
 	bid1 := openrtb.Bid{ID: "bid_id1", ImpID: "imp_id1", Price: 10.0000, Cat: cats1, W: 1, H: 1}
 	bid2 := openrtb.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 12.0000, Cat: cats2, W: 1, H: 1}
 
-	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
+	bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
 
 	innerBids1 := []*pbsOrtbBid{
 		&bid1_1,
@@ -2180,7 +2190,7 @@ func TestBidRejectionErrors(t *testing.T) {
 		innerBids := []*pbsOrtbBid{}
 		for _, bid := range test.bids {
 			currentBid := pbsOrtbBid{
-				bid, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: test.duration}, 0, false,
+				bid, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: test.duration}, nil, 0, false,
 			}
 			innerBids = append(innerBids, &currentBid)
 		}
@@ -2229,8 +2239,8 @@ func TestCategoryMappingTwoBiddersOneBidEachNoCategorySamePrice(t *testing.T) {
 	bidApn1 := openrtb.Bid{ID: "bid_idApn1", ImpID: "imp_idApn1", Price: 10.0000, Cat: cats1, W: 1, H: 1}
 	bidApn2 := openrtb.Bid{ID: "bid_idApn2", ImpID: "imp_idApn2", Price: 10.0000, Cat: cats2, W: 1, H: 1}
 
-	bid1_Apn1 := pbsOrtbBid{&bidApn1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
-	bid1_Apn2 := pbsOrtbBid{&bidApn2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0, false}
+	bid1_Apn1 := pbsOrtbBid{&bidApn1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
+	bid1_Apn2 := pbsOrtbBid{&bidApn2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, 0, false}
 
 	innerBidsApn1 := []*pbsOrtbBid{
 		&bid1_Apn1,
@@ -2357,7 +2367,7 @@ func TestApplyDealSupport(t *testing.T) {
 			},
 		}
 
-		bid := pbsOrtbBid{&openrtb.Bid{ID: "123456"}, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, test.dealPriority, false}
+		bid := pbsOrtbBid{&openrtb.Bid{ID: "123456"}, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, test.dealPriority, false}
 		bidCategory := map[string]string{
 			bid.bid.ID: test.targ["hb_pb_cat_dur"],
 		}
@@ -2524,7 +2534,7 @@ func TestUpdateHbPbCatDur(t *testing.T) {
 	}
 
 	for _, test := range testCases {
-		bid := pbsOrtbBid{&openrtb.Bid{ID: "123456"}, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, test.dealPriority, false}
+		bid := pbsOrtbBid{&openrtb.Bid{ID: "123456"}, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, test.dealPriority, false}
 		bidCategory := map[string]string{
 			bid.bid.ID: test.targ["hb_pb_cat_dur"],
 		}
@@ -2545,6 +2555,8 @@ type exchangeSpec struct {
 	EnforceLMT        bool                   `json:"enforceLmt"`
 	AssumeGDPRApplies bool                   `json:"assume_gdpr_applies"`
 	DebugLog          *DebugLog              `json:"debuglog,omitempty"`
+	EventsEnabled     bool                   `json:"events_enabled,omitempty"`
+	StartTime         int64                  `json:"start_time_ms,omitempty"`
 }
 
 type exchangeRequest struct {
@@ -2559,8 +2571,9 @@ type exchangeResponse struct {
 }
 
 type bidderSpec struct {
-	ExpectedRequest *bidderRequest `json:"expectRequest"`
-	MockResponse    bidderResponse `json:"mockResponse"`
+	ExpectedRequest         *bidderRequest `json:"expectRequest"`
+	MockResponse            bidderResponse `json:"mockResponse"`
+	ModifyingVastXmlAllowed bool           `json:"modifyingVastXmlAllowed,omitempty"`
 }
 
 type bidderRequest struct {
diff --git a/exchange/exchangetest/events-bid-account-off-request-off.json b/exchange/exchangetest/events-bid-account-off-request-off.json
new file mode 100644
index 00000000..9ce23f5e
--- /dev/null
+++ b/exchange/exchangetest/events-bid-account-off-request-off.json
@@ -0,0 +1,97 @@
+{
+  "events_enabled": false,
+  "start_time_ms": 1234567890,
+  "incomingRequest": {
+    "ortbRequest": {
+      "id": "some-request-id",
+      "site": {
+        "id": "some-site"
+      },
+      "imp": [
+        {
+          "id": "my-imp-id",
+          "banner": {},
+          "ext": {
+            "appnexus": {
+              "placementId": 1
+            }
+          }
+        }
+      ],
+      "ext": {
+        "prebid": {
+        }
+      }
+    }
+  },
+  "outgoingRequests": {
+    "appnexus": {
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
+                "id": "winning-bid",
+                "impid": "my-imp-id",
+                "price": 0.71,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-1"
+              },
+              "bidType": "banner"
+            },
+            {
+              "ortbBid": {
+                "id": "losing-bid",
+                "impid": "my-imp-id",
+                "price": 0.21,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-2"
+              },
+              "bidType": "banner"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "response": {
+    "bids": {
+      "id": "some-request-id",
+      "seatbid": [
+        {
+          "seat": "appnexus",
+          "bid": [
+            {
+              "id": "winning-bid",
+              "impid": "my-imp-id",
+              "price": 0.71,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-1",
+              "ext": {
+                "prebid": {
+                  "type": "banner"
+                }
+              }
+            },
+            {
+              "id": "losing-bid",
+              "impid": "my-imp-id",
+              "price": 0.21,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-2",
+              "ext": {
+                "prebid": {
+                  "type": "banner"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/exchange/exchangetest/events-bid-account-off-request-on.json b/exchange/exchangetest/events-bid-account-off-request-on.json
new file mode 100644
index 00000000..b88ec67c
--- /dev/null
+++ b/exchange/exchangetest/events-bid-account-off-request-on.json
@@ -0,0 +1,106 @@
+{
+  "events_enabled": false,
+  "start_time_ms": 1234567890,
+  "incomingRequest": {
+    "ortbRequest": {
+      "id": "some-request-id",
+      "site": {
+        "id": "some-site"
+      },
+      "imp": [
+        {
+          "id": "my-imp-id",
+          "banner": {},
+          "ext": {
+            "appnexus": {
+              "placementId": 1
+            }
+          }
+        }
+      ],
+      "ext": {
+        "prebid": {
+          "events": {}
+        }
+      }
+    }
+  },
+  "outgoingRequests": {
+    "appnexus": {
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
+                "id": "winning-bid",
+                "impid": "my-imp-id",
+                "price": 0.71,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-1"
+              },
+              "bidType": "banner"
+            },
+            {
+              "ortbBid": {
+                "id": "losing-bid",
+                "impid": "my-imp-id",
+                "price": 0.21,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-2"
+              },
+              "bidType": "banner"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "response": {
+    "bids": {
+      "id": "some-request-id",
+      "seatbid": [
+        {
+          "seat": "appnexus",
+          "bid": [
+            {
+              "id": "winning-bid",
+              "impid": "my-imp-id",
+              "price": 0.71,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-1",
+              "ext": {
+                "prebid": {
+                  "type": "banner",
+                  "events": {
+                    "imp": "http://localhost/event?t=imp&b=winning-bid&a=testaccount&bidder=appnexus&ts=1234567890",
+                    "win": "http://localhost/event?t=win&b=winning-bid&a=testaccount&bidder=appnexus&ts=1234567890"
+                  }
+                }
+              }
+            },
+            {
+              "id": "losing-bid",
+              "impid": "my-imp-id",
+              "price": 0.21,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-2",
+              "ext": {
+                "prebid": {
+                  "type": "banner",
+                  "events": {
+                    "imp": "http://localhost/event?t=imp&b=losing-bid&a=testaccount&bidder=appnexus&ts=1234567890",
+                    "win": "http://localhost/event?t=win&b=losing-bid&a=testaccount&bidder=appnexus&ts=1234567890"
+                  }
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/exchange/exchangetest/events-bid-account-on-request-off.json b/exchange/exchangetest/events-bid-account-on-request-off.json
new file mode 100644
index 00000000..e440b030
--- /dev/null
+++ b/exchange/exchangetest/events-bid-account-on-request-off.json
@@ -0,0 +1,104 @@
+{
+  "events_enabled": true,
+  "start_time_ms": 1234567890,
+  "incomingRequest": {
+    "ortbRequest": {
+      "id": "some-request-id",
+      "site": {
+        "id": "some-site"
+      },
+      "imp": [
+        {
+          "id": "my-imp-id",
+          "banner": {},
+          "ext": {
+            "appnexus": {
+              "placementId": 1
+            }
+          }
+        }
+      ],
+      "ext": {
+        "prebid": {}
+      }
+    }
+  },
+  "outgoingRequests": {
+    "appnexus": {
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
+                "id": "winning-bid",
+                "impid": "my-imp-id",
+                "price": 0.71,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-1"
+              },
+              "bidType": "banner"
+            },
+            {
+              "ortbBid": {
+                "id": "losing-bid",
+                "impid": "my-imp-id",
+                "price": 0.21,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-2"
+              },
+              "bidType": "banner"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "response": {
+    "bids": {
+      "id": "some-request-id",
+      "seatbid": [
+        {
+          "seat": "appnexus",
+          "bid": [
+            {
+              "id": "winning-bid",
+              "impid": "my-imp-id",
+              "price": 0.71,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-1",
+              "ext": {
+                "prebid": {
+                  "type": "banner",
+                  "events": {
+                    "imp": "http://localhost/event?t=imp&b=winning-bid&a=testaccount&bidder=appnexus&ts=1234567890",
+                    "win": "http://localhost/event?t=win&b=winning-bid&a=testaccount&bidder=appnexus&ts=1234567890"
+                  }
+                }
+              }
+            },
+            {
+              "id": "losing-bid",
+              "impid": "my-imp-id",
+              "price": 0.21,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-2",
+              "ext": {
+                "prebid": {
+                  "type": "banner",
+                  "events": {
+                    "imp": "http://localhost/event?t=imp&b=losing-bid&a=testaccount&bidder=appnexus&ts=1234567890",
+                    "win": "http://localhost/event?t=win&b=losing-bid&a=testaccount&bidder=appnexus&ts=1234567890"
+                  }
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/exchange/exchangetest/events-vast-account-off-request-off.json b/exchange/exchangetest/events-vast-account-off-request-off.json
new file mode 100644
index 00000000..f322e7c5
--- /dev/null
+++ b/exchange/exchangetest/events-vast-account-off-request-off.json
@@ -0,0 +1,157 @@
+{
+  "events_enabled": false,
+  "start_time_ms": 1234567890,
+  "incomingRequest": {
+    "ortbRequest": {
+      "id": "some-request-id",
+      "app": {
+        "id": "some-app"
+      },
+      "imp": [
+        {
+          "id": "my-imp-id",
+          "video": {},
+          "ext": {
+            "appnexus": {
+              "placementId": 1
+            },
+            "audienceNetwork": {
+              "placementId": 1
+            }
+          }
+        }
+      ],
+      "ext": {
+        "prebid": {
+          "targeting": {
+            "includewinners": true,
+            "includebidderkeys": false
+          }
+        }
+      }
+    }
+  },
+  "outgoingRequests": {
+    "appnexus": {
+      "modifyingVastXmlAllowed": true,
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
+                "id": "winning-bid",
+                "nurl": "http://domain.com/winning-bid",
+                "impid": "my-imp-id",
+                "price": 0.71,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-1"
+              },
+              "bidType": "video"
+            },
+            {
+              "ortbBid": {
+                "id": "losing-bid",
+                "nurl": "http://domain.com/losing-bid",
+                "impid": "my-imp-id",
+                "price": 0.21,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-2"
+              },
+              "bidType": "video"
+            }
+          ]
+        }
+      }
+    },
+    "audienceNetwork": {
+      "modifyingVastXmlAllowed": false,
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
+                "id": "contending-bid",
+                "nurl": "http://domain.com/contending-bid",
+                "impid": "my-imp-id",
+                "price": 0.51,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-4"
+              },
+              "bidType": "video"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "response": {
+    "bids": {
+      "id": "some-request-id",
+      "seatbid": [
+        {
+          "seat": "audienceNetwork",
+          "bid": [
+            {
+              "id": "contending-bid",
+              "nurl": "http://domain.com/contending-bid",
+              "impid": "my-imp-id",
+              "price": 0.51,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-4",
+              "ext": {
+                "prebid": {
+                  "type": "video"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "seat": "appnexus",
+          "bid": [
+            {
+              "id": "winning-bid",
+              "nurl": "http://domain.com/winning-bid",
+              "impid": "my-imp-id",
+              "price": 0.71,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-1",
+              "ext": {
+                "prebid": {
+                  "type": "video",
+                  "targeting": {
+                      "hb_bidder": "appnexus",
+                      "hb_cache_host": "www.pbcserver.com",
+                      "hb_cache_path": "/pbcache/endpoint",
+                      "hb_env": "mobile-app",
+                      "hb_pb": "0.70",
+                      "hb_size": "200x250"
+                  }
+                }
+              }
+            },
+            {
+              "id": "losing-bid",
+              "nurl": "http://domain.com/losing-bid",
+              "impid": "my-imp-id",
+              "price": 0.21,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-2",
+              "ext": {
+                "prebid": {
+                  "type": "video"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/exchange/exchangetest/events-vast-account-off-request-on.json b/exchange/exchangetest/events-vast-account-off-request-on.json
new file mode 100644
index 00000000..6e29ccdf
--- /dev/null
+++ b/exchange/exchangetest/events-vast-account-off-request-on.json
@@ -0,0 +1,160 @@
+{
+  "events_enabled": false,
+  "start_time_ms": 1234567890,
+  "incomingRequest": {
+    "ortbRequest": {
+      "id": "some-request-id",
+      "app": {
+        "id": "some-app"
+      },
+      "imp": [
+        {
+          "id": "my-imp-id",
+          "video": {},
+          "ext": {
+            "appnexus": {
+              "placementId": 1
+            },
+            "audienceNetwork": {
+              "placementId": 1
+            }
+          }
+        }
+      ],
+      "ext": {
+        "prebid": {
+          "targeting": {
+            "includewinners": true,
+            "includebidderkeys": false
+          },
+          "events": {}
+        }
+      }
+    }
+  },
+  "outgoingRequests": {
+    "appnexus": {
+      "modifyingVastXmlAllowed": true,
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
+                "id": "winning-bid",
+                "nurl": "http://domain.com/winning-bid",
+                "impid": "my-imp-id",
+                "price": 0.71,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-1"
+              },
+              "bidType": "video"
+            },
+            {
+              "ortbBid": {
+                "id": "losing-bid",
+                "nurl": "http://domain.com/losing-bid",
+                "impid": "my-imp-id",
+                "price": 0.21,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-2"
+              },
+              "bidType": "video"
+            }
+          ]
+        }
+      }
+    },
+    "audienceNetwork": {
+      "modifyingVastXmlAllowed": false,
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
+                "id": "contending-bid",
+                "nurl": "http://domain.com/contending-bid",
+                "impid": "my-imp-id",
+                "price": 0.51,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-4"
+              },
+              "bidType": "video"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "response": {
+    "bids": {
+      "id": "some-request-id",
+      "seatbid": [
+        {
+          "seat": "audienceNetwork",
+          "bid": [
+            {
+              "id": "contending-bid",
+              "nurl": "http://domain.com/contending-bid",
+              "impid": "my-imp-id",
+              "price": 0.51,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-4",
+              "ext": {
+                "prebid": {
+                  "type": "video"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "seat": "appnexus",
+          "bid": [
+            {
+              "id": "winning-bid",
+              "adm": "<VAST version=\"3.0\"><Ad><Wrapper><AdSystem>prebid.org wrapper</AdSystem><VASTAdTagURI><![CDATA[http://domain.com/winning-bid]]></VASTAdTagURI><Impression><![CDATA[http://localhost/event?t=imp&b=winning-bid&a=testaccount&bidder=appnexus&f=b&ts=1234567890]]></Impression><Creatives></Creatives></Wrapper></Ad></VAST>",
+              "nurl": "http://domain.com/winning-bid",
+              "impid": "my-imp-id",
+              "price": 0.71,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-1",
+              "ext": {
+                "prebid": {
+                  "type": "video",
+                  "targeting": {
+                      "hb_bidder": "appnexus",
+                      "hb_cache_host": "www.pbcserver.com",
+                      "hb_cache_path": "/pbcache/endpoint",
+                      "hb_env": "mobile-app",
+                      "hb_pb": "0.70",
+                      "hb_size": "200x250"
+                  }
+                }
+              }
+            },
+            {
+              "id": "losing-bid",
+              "adm": "<VAST version=\"3.0\"><Ad><Wrapper><AdSystem>prebid.org wrapper</AdSystem><VASTAdTagURI><![CDATA[http://domain.com/losing-bid]]></VASTAdTagURI><Impression><![CDATA[http://localhost/event?t=imp&b=losing-bid&a=testaccount&bidder=appnexus&f=b&ts=1234567890]]></Impression><Creatives></Creatives></Wrapper></Ad></VAST>",
+              "nurl": "http://domain.com/losing-bid",
+              "impid": "my-imp-id",
+              "price": 0.21,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-2",
+              "ext": {
+                "prebid": {
+                  "type": "video"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/exchange/exchangetest/events-vast-account-on-request-off.json b/exchange/exchangetest/events-vast-account-on-request-off.json
new file mode 100644
index 00000000..21f47356
--- /dev/null
+++ b/exchange/exchangetest/events-vast-account-on-request-off.json
@@ -0,0 +1,159 @@
+{
+  "events_enabled": true,
+  "start_time_ms": 1234567890,
+  "incomingRequest": {
+    "ortbRequest": {
+      "id": "some-request-id",
+      "app": {
+        "id": "some-app"
+      },
+      "imp": [
+        {
+          "id": "my-imp-id",
+          "video": {},
+          "ext": {
+            "appnexus": {
+              "placementId": 1
+            },
+            "audienceNetwork": {
+              "placementId": 1
+            }
+          }
+        }
+      ],
+      "ext": {
+        "prebid": {
+          "targeting": {
+            "includewinners": true,
+            "includebidderkeys": false
+          }
+        }
+      }
+    }
+  },
+  "outgoingRequests": {
+    "appnexus": {
+      "modifyingVastXmlAllowed": true,
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
+                "id": "winning-bid",
+                "nurl": "http://domain.com/winning-bid",
+                "impid": "my-imp-id",
+                "price": 0.71,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-1"
+              },
+              "bidType": "video"
+            },
+            {
+              "ortbBid": {
+                "id": "losing-bid",
+                "nurl": "http://domain.com/losing-bid",
+                "impid": "my-imp-id",
+                "price": 0.21,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-2"
+              },
+              "bidType": "video"
+            }
+          ]
+        }
+      }
+    },
+    "audienceNetwork": {
+      "modifyingVastXmlAllowed": false,
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
+                "id": "contending-bid",
+                "nurl": "http://domain.com/contending-bid",
+                "impid": "my-imp-id",
+                "price": 0.51,
+                "w": 200,
+                "h": 250,
+                "crid": "creative-4"
+              },
+              "bidType": "video"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "response": {
+    "bids": {
+      "id": "some-request-id",
+      "seatbid": [
+        {
+          "seat": "audienceNetwork",
+          "bid": [
+            {
+              "id": "contending-bid",
+              "nurl": "http://domain.com/contending-bid",
+              "impid": "my-imp-id",
+              "price": 0.51,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-4",
+              "ext": {
+                "prebid": {
+                  "type": "video"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "seat": "appnexus",
+          "bid": [
+            {
+              "id": "winning-bid",
+              "adm": "<VAST version=\"3.0\"><Ad><Wrapper><AdSystem>prebid.org wrapper</AdSystem><VASTAdTagURI><![CDATA[http://domain.com/winning-bid]]></VASTAdTagURI><Impression><![CDATA[http://localhost/event?t=imp&b=winning-bid&a=testaccount&bidder=appnexus&f=b&ts=1234567890]]></Impression><Creatives></Creatives></Wrapper></Ad></VAST>",
+              "nurl": "http://domain.com/winning-bid",
+              "impid": "my-imp-id",
+              "price": 0.71,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-1",
+              "ext": {
+                "prebid": {
+                  "type": "video",
+                  "targeting": {
+                      "hb_bidder": "appnexus",
+                      "hb_cache_host": "www.pbcserver.com",
+                      "hb_cache_path": "/pbcache/endpoint",
+                      "hb_env": "mobile-app",
+                      "hb_pb": "0.70",
+                      "hb_size": "200x250"
+                  }
+                }
+              }
+            },
+            {
+              "id": "losing-bid",
+              "adm": "<VAST version=\"3.0\"><Ad><Wrapper><AdSystem>prebid.org wrapper</AdSystem><VASTAdTagURI><![CDATA[http://domain.com/losing-bid]]></VASTAdTagURI><Impression><![CDATA[http://localhost/event?t=imp&b=losing-bid&a=testaccount&bidder=appnexus&f=b&ts=1234567890]]></Impression><Creatives></Creatives></Wrapper></Ad></VAST>",
+              "nurl": "http://domain.com/losing-bid",
+              "impid": "my-imp-id",
+              "price": 0.21,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-2",
+              "ext": {
+                "prebid": {
+                  "type": "video"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/exchange/gdpr_test.go b/exchange/gdpr_test.go
index f7906104..35193909 100644
--- a/exchange/gdpr_test.go
+++ b/exchange/gdpr_test.go
@@ -14,6 +14,7 @@ func TestExtractGDPR(t *testing.T) {
 		description string
 		giveRegs    *openrtb.Regs
 		wantGDPR    gdpr.Signal
+		wantError   bool
 	}{
 		{
 			description: "Regs Ext GDPR = 0",
@@ -44,6 +45,7 @@ func TestExtractGDPR(t *testing.T) {
 			description: "JSON unmarshal error",
 			giveRegs:    &openrtb.Regs{Ext: json.RawMessage(`{"`)},
 			wantGDPR:    gdpr.SignalAmbiguous,
+			wantError:   true,
 		},
 	}
 
@@ -52,8 +54,14 @@ func TestExtractGDPR(t *testing.T) {
 			Regs: tt.giveRegs,
 		}
 
-		result := extractGDPR(&bidReq)
+		result, err := extractGDPR(&bidReq)
 		assert.Equal(t, tt.wantGDPR, result, tt.description)
+
+		if tt.wantError {
+			assert.NotNil(t, err, tt.description)
+		} else {
+			assert.Nil(t, err, tt.description)
+		}
 	}
 }
 
@@ -62,6 +70,7 @@ func TestExtractConsent(t *testing.T) {
 		description string
 		giveUser    *openrtb.User
 		wantConsent string
+		wantError   bool
 	}{
 		{
 			description: "User Ext Consent is not empty",
@@ -87,6 +96,7 @@ func TestExtractConsent(t *testing.T) {
 			description: "JSON unmarshal error",
 			giveUser:    &openrtb.User{Ext: json.RawMessage(`{`)},
 			wantConsent: "",
+			wantError:   true,
 		},
 	}
 
@@ -95,7 +105,13 @@ func TestExtractConsent(t *testing.T) {
 			User: tt.giveUser,
 		}
 
-		result := extractConsent(&bidReq)
+		result, err := extractConsent(&bidReq)
 		assert.Equal(t, tt.wantConsent, result, tt.description)
+
+		if tt.wantError {
+			assert.NotNil(t, err, tt.description)
+		} else {
+			assert.Nil(t, err, tt.description)
+		}
 	}
 }
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 6dab5b00..e679397b 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -1060,6 +1060,7 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 		permissionsError    error
 		userSyncIfAmbiguous bool
 		expectPrivacyLabels metrics.PrivacyLabels
+		expectError         bool
 	}{
 		{
 			description:        "Enforce - TCF Invalid",
@@ -1109,6 +1110,19 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 				GDPRTCFVersion: "",
 			},
 		},
+		{
+			description:        "Enforce - TCF 1; GDPR signal extraction error",
+			gdprAccountEnabled: &trueValue,
+			gdprHostEnabled:    true,
+			gdpr:               "0{",
+			gdprConsent:        "BONV8oqONXwgmADACHENAO7pqzAAppY",
+			gdprScrub:          true,
+			expectPrivacyLabels: metrics.PrivacyLabels{
+				GDPREnforced:   true,
+				GDPRTCFVersion: metrics.TCFVersionV1,
+			},
+			expectError: true,
+		},
 		{
 			description:        "Enforce - TCF 1; account GDPR enabled, host GDPR setting disregarded",
 			gdprAccountEnabled: &trueValue,
@@ -1236,7 +1250,12 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			privacyConfig)
 		result := results[0]
 
-		assert.Nil(t, errs)
+		if test.expectError {
+			assert.NotNil(t, errs)
+		} else {
+			assert.Nil(t, errs)
+		}
+
 		if test.gdprScrub {
 			assert.Equal(t, result.BidRequest.User.BuyerUID, "", test.description+":User.BuyerUID")
 			assert.Equal(t, result.BidRequest.Device.DIDMD5, "", test.description+":Device.DIDMD5")
diff --git a/gdpr/gdpr_test.go b/gdpr/gdpr_test.go
new file mode 100644
index 00000000..902bf14e
--- /dev/null
+++ b/gdpr/gdpr_test.go
@@ -0,0 +1,50 @@
+package gdpr
+
+import (
+	"context"
+	"net/http"
+	"testing"
+
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewPermissions(t *testing.T) {
+	tests := []struct {
+		description  string
+		gdprEnabled  bool
+		hostVendorID int
+		wantType     Permissions
+	}{
+		{
+			gdprEnabled:  false,
+			hostVendorID: 32,
+			wantType:     &AlwaysAllow{},
+		},
+		{
+			gdprEnabled:  true,
+			hostVendorID: 0,
+			wantType:     &AllowHostCookies{},
+		},
+		{
+			gdprEnabled:  true,
+			hostVendorID: 32,
+			wantType:     &permissionsImpl{},
+		},
+	}
+
+	for _, tt := range tests {
+
+		config := config.GDPR{
+			Enabled:      tt.gdprEnabled,
+			HostVendorID: tt.hostVendorID,
+		}
+		vendorIDs := map[openrtb_ext.BidderName]uint16{}
+
+		perms := NewPermissions(context.Background(), config, vendorIDs, &http.Client{})
+
+		assert.IsType(t, tt.wantType, perms, tt.description)
+	}
+}
diff --git a/gdpr/vendorlist-fetching_test.go b/gdpr/vendorlist-fetching_test.go
index e5ad8793..62c6a5f9 100644
--- a/gdpr/vendorlist-fetching_test.go
+++ b/gdpr/vendorlist-fetching_test.go
@@ -596,25 +596,25 @@ func TestVendorListURLMaker(t *testing.T) {
 			description:       "TCF1 - Latest",
 			tcfSpecVersion:    1,
 			vendorListVersion: 0, // Forces latest version.
-			expectedURL:       "https://vendorlist.consensu.org/vendorlist.json",
+			expectedURL:       "https://vendor-list.consensu.org/vendorlist.json",
 		},
 		{
 			description:       "TCF1 - Specific",
 			tcfSpecVersion:    1,
 			vendorListVersion: 42,
-			expectedURL:       "https://vendorlist.consensu.org/v-42/vendorlist.json",
+			expectedURL:       "https://vendor-list.consensu.org/v-42/vendorlist.json",
 		},
 		{
 			description:       "TCF2 - Latest",
 			tcfSpecVersion:    2,
 			vendorListVersion: 0, // Forces latest version.
-			expectedURL:       "https://vendorlist.consensu.org/v2/vendor-list.json",
+			expectedURL:       "https://vendor-list.consensu.org/v2/vendor-list.json",
 		},
 		{
 			description:       "TCF2 - Specific",
 			tcfSpecVersion:    2,
 			vendorListVersion: 42,
-			expectedURL:       "https://vendorlist.consensu.org/v2/archives/vendor-list-v42.json",
+			expectedURL:       "https://vendor-list.consensu.org/v2/archives/vendor-list-v42.json",
 		},
 	}
 
@@ -710,7 +710,7 @@ type serverSettings struct {
 // If the "version" query param doesn't exist, it returns a 400.
 //
 // If the "version" query param points to a version which doesn't exist, it returns a 403.
-// Don't ask why... that's just what the official page is doing. See https://vendorlist.consensu.org/v-9999/vendorlist.json
+// Don't ask why... that's just what the official page is doing. See https://vendor-list.consensu.org/v-9999/vendorlist.json
 func mockServer(settings serverSettings) func(http.ResponseWriter, *http.Request) {
 	return func(w http.ResponseWriter, req *http.Request) {
 		vendorListVersion := req.URL.Query().Get("version")