Repository: prebid/prebid-server
Pull request #1387 (2020-07-09 06:57:07)

Separate "debug" behavior from "billable" behavior
This pull request adds the feature described in issue #745. Separates "debug" behavior from "billable" behavior by making use of a JSON `debug` boolean flag that the publisher must encode in the extension at the bid request level.

With this feature an incoming request can output debug information even if its `test` flag is set to 0. Example:
```json
{
  "test": 0,  //<-- set to zero implicitly or explicitly
  "id": "some-request-id",
  "site": {
    "page": "prebid.org"
  },
  "imp": [
    {
      "id": "some-impression-id",
      "banner": {
        "format": [
          {
            "w": 300,
            "h": 250
          },
          {
            "w": 300,
            "h": 600
          }
        ]
      },
      "ext": {
        "appnexus": {
          "placementId": 10433394
        }
      }
    }
  ],
  "tmax": 500,
  "ext": {"prebid":{"debug":true}} //<-- new debug flag set to true
}
```



guscarreon: Includes #1379's changes so it'd probably be better to merge after said PR.
mansinahar: @guscarreon and I spoke offline and he has kindly agreed to make some changes to this PR. More towards simplification/better readability than changes in the logic. 

Thanks a lot @guscarreon!

Patch:
diff --git a/adapters/adprime/adprime.go b/adapters/adprime/adprime.go
new file mode 100644
index 00000000..007d3c86
--- /dev/null
+++ b/adapters/adprime/adprime.go
@@ -0,0 +1,142 @@
+package adprime
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+
+	"github.com/buger/jsonparser"
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// AdprimeAdapter struct
+type AdprimeAdapter struct {
+	URI string
+}
+
+// NewAdprimeBidder Initializes the Bidder
+func NewAdprimeBidder(endpoint string) *AdprimeAdapter {
+	return &AdprimeAdapter{
+		URI: endpoint,
+	}
+}
+
+type adprimeParams struct {
+	TagID string `json:"TagID"`
+}
+
+// MakeRequests create bid request for adprime demand
+func (a *AdprimeAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	var errs []error
+	var err error
+	var tagID string
+
+	var adapterRequests []*adapters.RequestData
+
+	reqCopy := *request
+	for _, imp := range request.Imp {
+		reqCopy.Imp = []openrtb.Imp{imp}
+
+		tagID, err = jsonparser.GetString(reqCopy.Imp[0].Ext, "bidder", "TagID")
+		if err != nil {
+			errs = append(errs, err)
+			continue
+		}
+
+		reqCopy.Imp[0].TagID = tagID
+
+		adapterReq, errors := a.makeRequest(&reqCopy)
+		if adapterReq != nil {
+			adapterRequests = append(adapterRequests, adapterReq)
+		}
+		errs = append(errs, errors...)
+	}
+	return adapterRequests, errs
+}
+
+func (a *AdprimeAdapter) makeRequest(request *openrtb.BidRequest) (*adapters.RequestData, []error) {
+
+	var errs []error
+
+	reqJSON, err := json.Marshal(request)
+
+	if err != nil {
+		errs = append(errs, err)
+		return nil, errs
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	return &adapters.RequestData{
+		Method:  "POST",
+		Uri:     a.URI,
+		Body:    reqJSON,
+		Headers: headers,
+	}, errs
+}
+
+// MakeBids makes the bids
+func (a *AdprimeAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	var errs []error
+
+	if response.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if response.StatusCode == http.StatusNotFound {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Page not found: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}}
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}}
+	}
+
+	var bidResp openrtb.BidResponse
+
+	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+
+	for _, sb := range bidResp.SeatBid {
+		for i := range sb.Bid {
+			bidType, err := getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp)
+			if err != nil {
+				errs = append(errs, err)
+			} else {
+				b := &adapters.TypedBid{
+					Bid:     &sb.Bid[i],
+					BidType: bidType,
+				}
+				bidResponse.Bids = append(bidResponse.Bids, b)
+			}
+		}
+	}
+	return bidResponse, errs
+}
+
+func getMediaTypeForImp(impID string, imps []openrtb.Imp) (openrtb_ext.BidType, error) {
+	mediaType := openrtb_ext.BidTypeBanner
+	for _, imp := range imps {
+		if imp.ID == impID {
+			if imp.Banner == nil && imp.Video != nil {
+				mediaType = openrtb_ext.BidTypeVideo
+			}
+			return mediaType, nil
+		}
+	}
+
+	// This shouldnt happen. Lets handle it just incase by returning an error.
+	return "", &errortypes.BadInput{
+		Message: fmt.Sprintf("Failed to find impression \"%s\" ", impID),
+	}
+}
diff --git a/adapters/smaato/image.go b/adapters/smaato/image.go
new file mode 100644
index 00000000..582206cc
--- /dev/null
+++ b/adapters/smaato/image.go
@@ -0,0 +1,53 @@
+package smaato
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strings"
+)
+
+type imageAd struct {
+	Image image `json:"image"`
+}
+type image struct {
+	Img                img      `json:"img"`
+	Impressiontrackers []string `json:"impressiontrackers"`
+	Clicktrackers      []string `json:"clicktrackers"`
+}
+type img struct {
+	URL    string `json:"url"`
+	W      int    `json:"w"`
+	H      int    `json:"h"`
+	Ctaurl string `json:"ctaurl"`
+}
+
+func extractAdmImage(adapterResponseAdm string) (string, error) {
+	var imgMarkup string
+	var err error
+
+	var imageAd imageAd
+	err = json.Unmarshal([]byte(adapterResponseAdm), &imageAd)
+	var image = imageAd.Image
+
+	if err == nil {
+		var clickEvent strings.Builder
+		var impressionTracker strings.Builder
+
+		for _, clicktracker := range image.Clicktrackers {
+			clickEvent.WriteString("fetch(decodeURIComponent('" + url.QueryEscape(clicktracker) + "'.replace(/\\+/g, ' ')), " +
+				"{cache: 'no-cache'});")
+		}
+
+		for _, impression := range image.Impressiontrackers {
+
+			impressionTracker.WriteString(fmt.Sprintf(`<img src="%s" alt="" width="0" height="0"/>`, impression))
+		}
+
+		imgMarkup = fmt.Sprintf(`<div style="cursor:pointer" onclick="%s;window.open(decodeURIComponent('%s'.replace(/\+/g, ' ')));"><img src="%s" width="%d" height="%d"/>%s</div>`,
+			&clickEvent, url.QueryEscape(image.Img.Ctaurl), image.
+				Img.URL, image.Img.W, image.Img.
+				H, &impressionTracker)
+	}
+	return imgMarkup, err
+}
diff --git a/adapters/smaato/richmedia.go b/adapters/smaato/richmedia.go
new file mode 100644
index 00000000..1c94a355
--- /dev/null
+++ b/adapters/smaato/richmedia.go
@@ -0,0 +1,52 @@
+package smaato
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strings"
+)
+
+type richMediaAd struct {
+	RichMedia richmedia `json:"richmedia"`
+}
+type mediadata struct {
+	Content string `json:"content"`
+	W       int    `json:"w"`
+	H       int    `json:"h"`
+}
+
+type richmedia struct {
+	MediaData          mediadata `json:"mediadata"`
+	Impressiontrackers []string  `json:"impressiontrackers"`
+	Clicktrackers      []string  `json:"clicktrackers"`
+}
+
+func extractAdmRichMedia(adapterResponseAdm string) (string, error) {
+	var richMediaMarkup string
+	var err error
+
+	var richMediaAd richMediaAd
+	err = json.Unmarshal([]byte(adapterResponseAdm), &richMediaAd)
+	var richMedia = richMediaAd.RichMedia
+
+	if err == nil {
+		var clickEvent strings.Builder
+		var impressionTracker strings.Builder
+
+		for _, clicktracker := range richMedia.Clicktrackers {
+			clickEvent.WriteString("fetch(decodeURIComponent('" + url.QueryEscape(clicktracker) + "'), " +
+				"{cache: 'no-cache'});")
+		}
+		for _, impression := range richMedia.Impressiontrackers {
+
+			impressionTracker.WriteString(fmt.Sprintf(`<img src="%s" alt="" width="0" height="0"/>`, impression))
+		}
+
+		richMediaMarkup = fmt.Sprintf(`<div onclick="%s">%s%s</div>`,
+			&clickEvent,
+			richMedia.MediaData.Content,
+			&impressionTracker)
+	}
+	return richMediaMarkup, err
+}
diff --git a/adapters/smaato/smaato.go b/adapters/smaato/smaato.go
new file mode 100644
index 00000000..06678d77
--- /dev/null
+++ b/adapters/smaato/smaato.go
@@ -0,0 +1,276 @@
+package smaato
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/buger/jsonparser"
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+const clientVersion = "prebid_server_0.1"
+
+type adMarkupType string
+
+const (
+	smtAdTypeImg       adMarkupType = "Img"
+	smtAdTypeRichmedia adMarkupType = "Richmedia"
+)
+
+// SmaatoAdapter describes a Smaato prebid server adapter.
+type SmaatoAdapter struct {
+	URI string
+}
+
+//userExt defines User.Ext object for Smaato
+type userExt struct {
+	Data userExtData `json:"data"`
+}
+
+type userExtData struct {
+	Keywords string `json:"keywords"`
+	Gender   string `json:"gender"`
+	Yob      int64  `json:"yob"`
+}
+
+//userExt defines Site.Ext object for Smaato
+type siteExt struct {
+	Data siteExtData `json:"data"`
+}
+
+type siteExtData struct {
+	Keywords string `json:"keywords"`
+}
+
+// NewSmaatoBidder creates a Smaato bid adapter.
+func NewSmaatoBidder(uri string) *SmaatoAdapter {
+	return &SmaatoAdapter{
+		URI: uri,
+	}
+}
+
+// MakeRequests makes the HTTP requests which should be made to fetch bids.
+func (a *SmaatoAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	errs := make([]error, 0, len(request.Imp))
+	if len(request.Imp) == 0 {
+		errs = append(errs, &errortypes.BadInput{Message: "no impressions in bid request"})
+		return nil, errs
+	}
+
+	// Use bidRequestExt of first imp to retrieve params which are valid for all imps, e.g. publisherId
+	publisherId, err := jsonparser.GetString(request.Imp[0].Ext, "bidder", "publisherId")
+	if err != nil {
+		errs = append(errs, err)
+		return nil, errs
+	}
+
+	for i := 0; i < len(request.Imp); i++ {
+		err := parseImpressionObject(&request.Imp[i])
+		// If the parsing is failed, remove imp and add the error.
+		if err != nil {
+			errs = append(errs, err)
+			request.Imp = append(request.Imp[:i], request.Imp[i+1:]...)
+			i--
+		}
+	}
+	if request.Site != nil {
+		siteCopy := *request.Site
+		siteCopy.Publisher = &openrtb.Publisher{ID: publisherId}
+
+		if request.Site.Ext != nil {
+			var siteExt siteExt
+			err := json.Unmarshal([]byte(request.Site.Ext), &siteExt)
+			if err != nil {
+				errs = append(errs, err)
+				return nil, errs
+			}
+			siteCopy.Keywords = siteExt.Data.Keywords
+			siteCopy.Ext = nil
+		}
+		request.Site = &siteCopy
+	}
+
+	if request.User != nil && request.User.Ext != nil {
+		var userExt userExt
+		var userExtRaw map[string]json.RawMessage
+
+		rawExtErr := json.Unmarshal(request.User.Ext, &userExtRaw)
+		if rawExtErr != nil {
+			errs = append(errs, rawExtErr)
+			return nil, errs
+		}
+
+		userExtErr := json.Unmarshal([]byte(request.User.Ext), &userExt)
+		if userExtErr != nil {
+			errs = append(errs, userExtErr)
+			return nil, errs
+		}
+
+		userCopy := *request.User
+		extractUserExtAttributes(userExt, &userCopy)
+		delete(userExtRaw, "data")
+		userCopy.Ext, err = json.Marshal(userExtRaw)
+		if err != nil {
+			errs = append(errs, err)
+			return nil, errs
+		}
+		request.User = &userCopy
+	}
+
+	// Setting ext client info
+	type bidRequestExt struct {
+		Client string `json:"client"`
+	}
+	request.Ext, err = json.Marshal(bidRequestExt{Client: clientVersion})
+	if err != nil {
+		errs = append(errs, err)
+		return nil, errs
+	}
+	reqJSON, err := json.Marshal(request)
+	if err != nil {
+		errs = append(errs, err)
+		return nil, errs
+	}
+
+	uri := a.URI
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+
+	return []*adapters.RequestData{{
+		Method:  "POST",
+		Uri:     uri,
+		Body:    reqJSON,
+		Headers: headers,
+	}}, errs
+}
+
+// MakeBids unpacks the server's response into Bids.
+func (a *SmaatoAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if response.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if response.StatusCode == http.StatusBadRequest {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}}
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return nil, []error{fmt.Errorf("unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode)}
+	}
+
+	var bidResp openrtb.BidResponse
+	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)
+
+	for _, sb := range bidResp.SeatBid {
+		for i := 0; i < len(sb.Bid); i++ {
+			bid := sb.Bid[i]
+
+			var markupError error
+			bid.AdM, markupError = renderAdMarkup(getAdMarkupType(response, bid.AdM), bid.AdM)
+			if markupError != nil {
+				fmt.Println(markupError)
+				continue // no bid when broken ad markup
+			}
+
+			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+				Bid:     &bid,
+				BidType: openrtb_ext.BidTypeBanner,
+			})
+		}
+	}
+	return bidResponse, nil
+}
+
+func renderAdMarkup(adMarkupType adMarkupType, adMarkup string) (string, error) {
+	var markupError error
+	var adm string
+	switch adMarkupType {
+	case smtAdTypeImg:
+		adm, markupError = extractAdmImage(adMarkup)
+	case smtAdTypeRichmedia:
+		adm, markupError = extractAdmRichMedia(adMarkup)
+	default:
+		return "", fmt.Errorf("Unknown markup type %s", adMarkupType)
+	}
+	return adm, markupError
+}
+
+func getAdMarkupType(response *adapters.ResponseData, adMarkup string) adMarkupType {
+	if admType := adMarkupType(response.Headers.Get("X-SMT-ADTYPE")); admType != "" {
+		return admType
+	}
+	if strings.HasPrefix(adMarkup, `{"image":`) {
+		return smtAdTypeImg
+	}
+	if strings.HasPrefix(adMarkup, `{"richmedia":`) {
+		return smtAdTypeRichmedia
+	}
+	return ""
+}
+
+func assignBannerSize(banner *openrtb.Banner) (*openrtb.Banner, error) {
+	if banner.W != nil && banner.H != nil {
+		return banner, nil
+	}
+	if len(banner.Format) == 0 {
+		return banner, fmt.Errorf("No sizes provided for Banner %v", banner.Format)
+	}
+	bannerCopy := *banner
+	bannerCopy.W = new(uint64)
+	*bannerCopy.W = banner.Format[0].W
+	bannerCopy.H = new(uint64)
+	*bannerCopy.H = banner.Format[0].H
+
+	return &bannerCopy, nil
+}
+
+// parseImpressionObject parse the imp to get it ready to send to smaato
+func parseImpressionObject(imp *openrtb.Imp) error {
+	adSpaceID, err := jsonparser.GetString(imp.Ext, "bidder", "adspaceId")
+	if err != nil {
+		return err
+	}
+
+	// SMAATO supports banner impressions.
+	if imp.Banner != nil {
+		bannerCopy, err := assignBannerSize(imp.Banner)
+		if err != nil {
+			return err
+		}
+		imp.Banner = bannerCopy
+		imp.TagID = adSpaceID
+		imp.Ext = nil
+		return nil
+	}
+	return fmt.Errorf("invalid MediaType. SMAATO only supports Banner. Ignoring ImpID=%s", imp.ID)
+}
+
+func extractUserExtAttributes(userExt userExt, userCopy *openrtb.User) {
+	gender := userExt.Data.Gender
+	if gender != "" {
+		userCopy.Gender = gender
+	}
+
+	yob := userExt.Data.Yob
+	if yob != 0 {
+		userCopy.Yob = yob
+	}
+
+	keywords := userExt.Data.Keywords
+	if keywords != "" {
+		userCopy.Keywords = keywords
+	}
+}
diff --git a/config/config.go b/config/config.go
index 67689d1a..9663b021 100755
--- a/config/config.go
+++ b/config/config.go
@@ -797,6 +797,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.adocean.endpoint", "https://{{.Host}}")
 	v.SetDefault("adapters.adoppler.endpoint", "http://app.trustedmarketplace.io/ads")
 	v.SetDefault("adapters.adpone.endpoint", "http://rtb.adpone.com/bid-request?src=prebid_server")
+	v.SetDefault("adapters.adprime.endpoint", "http://delta.adprime.com/?c=o&m=ortb")
 	v.SetDefault("adapters.adtarget.endpoint", "http://ghb.console.adtarget.com.tr/pbs/ortb")
 	v.SetDefault("adapters.adtelligent.endpoint", "http://ghb.adtelligent.com/pbs/ortb")
 	v.SetDefault("adapters.advangelists.endpoint", "http://nep.advangelists.com/xp/get?pubid={{.PublisherID}}")
@@ -845,6 +846,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.rubicon.disabled", true)
 	v.SetDefault("adapters.rubicon.endpoint", "http://exapi-us-east.rubiconproject.com/a/api/exchange.json")
 	v.SetDefault("adapters.sharethrough.endpoint", "http://btlr.sharethrough.com/FGMrCMMc/v1")
+	v.SetDefault("adapters.smaato.endpoint", "https://prebid.ad.smaato.net/oapi/prebid")
 	v.SetDefault("adapters.smartadserver.endpoint", "https://ssb.smartadserver.com")
 	v.SetDefault("adapters.smartrtb.endpoint", "http://market-east.smrtb.com/json/publisher/rtb?pubid={{.PublisherID}}")
 	v.SetDefault("adapters.somoaudience.endpoint", "http://publisher-east.mobileadtrading.com/rtb/bid")
diff --git a/docs/bidders/smaato.md b/docs/bidders/smaato.md
new file mode 100644
index 00000000..881f8f2a
--- /dev/null
+++ b/docs/bidders/smaato.md
@@ -0,0 +1,42 @@
+
+# Smaato Bidder
+
+```
+Module Name: Smaato Bidder Adapter
+Module Type: Bidder Adapter
+Maintainer: prebid@smaato.com
+```
+
+### Description
+
+Please contact Smaato Support or prebid@smaato.com to get set up with a publisherId and adspaceId.
+
+### Test Parameters:  
+
+Following example includes sample `imp` object with publisherId and adSlot which can be used to test Smaato Adapter
+
+```
+"imp":[
+      {
+         "id":“1C86242D-9535-47D6-9576-7B1FE87F282C,
+         "banner":{
+            "format":[
+               {
+                  "w":300,
+                  "h":50
+               },
+               {
+                  "w":300,
+                  "h":250
+               }
+            ]
+         },
+         "ext":{
+            "smaato":{
+               "publisherId":"100042525",
+               "adspaceId":"130563103"
+            }
+         }
+      }
+   ]
+```
diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go
index 2ecddb83..d056de66 100755
--- a/exchange/adapter_map.go
+++ b/exchange/adapter_map.go
@@ -19,6 +19,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/adocean"
 	"github.com/prebid/prebid-server/adapters/adoppler"
 	"github.com/prebid/prebid-server/adapters/adpone"
+	"github.com/prebid/prebid-server/adapters/adprime"
 	"github.com/prebid/prebid-server/adapters/adtarget"
 	"github.com/prebid/prebid-server/adapters/adtelligent"
 	"github.com/prebid/prebid-server/adapters/advangelists"
@@ -64,6 +65,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/rtbhouse"
 	"github.com/prebid/prebid-server/adapters/rubicon"
 	"github.com/prebid/prebid-server/adapters/sharethrough"
+	"github.com/prebid/prebid-server/adapters/smaato"
 	"github.com/prebid/prebid-server/adapters/smartadserver"
 	"github.com/prebid/prebid-server/adapters/smartrtb"
 	"github.com/prebid/prebid-server/adapters/somoaudience"
@@ -105,6 +107,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter
 		openrtb_ext.BidderAdOcean:      adocean.NewAdOceanBidder(client, cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdOcean))].Endpoint),
 		openrtb_ext.BidderAdoppler:     adoppler.NewAdopplerBidder(cfg.Adapters[string(openrtb_ext.BidderAdoppler)].Endpoint),
 		openrtb_ext.BidderAdpone:       adpone.NewAdponeBidder(cfg.Adapters[string(openrtb_ext.BidderAdpone)].Endpoint),
+		openrtb_ext.BidderAdprime:      adprime.NewAdprimeBidder(cfg.Adapters[string(openrtb_ext.BidderAdprime)].Endpoint),
 		openrtb_ext.BidderAdtarget:     adtarget.NewAdtargetBidder(cfg.Adapters[string(openrtb_ext.BidderAdtarget)].Endpoint),
 		openrtb_ext.BidderAdtelligent:  adtelligent.NewAdtelligentBidder(cfg.Adapters[string(openrtb_ext.BidderAdtelligent)].Endpoint),
 		openrtb_ext.BidderAdvangelists: advangelists.NewAdvangelistsBidder(cfg.Adapters[string(openrtb_ext.BidderAdvangelists)].Endpoint),
@@ -154,6 +157,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter
 			cfg.Adapters[string(openrtb_ext.BidderRubicon)].XAPI.Tracker),
 
 		openrtb_ext.BidderSharethrough:     sharethrough.NewSharethroughBidder(cfg.Adapters[string(openrtb_ext.BidderSharethrough)].Endpoint),
+		openrtb_ext.BidderSmaato:           smaato.NewSmaatoBidder(cfg.Adapters[string(openrtb_ext.BidderSmaato)].Endpoint),
 		openrtb_ext.BidderSmartadserver:    smartadserver.NewSmartadserverBidder(cfg.Adapters[string(openrtb_ext.BidderSmartadserver)].Endpoint),
 		openrtb_ext.BidderSmartRTB:         smartrtb.NewSmartRTBBidder(cfg.Adapters[string(openrtb_ext.BidderSmartRTB)].Endpoint),
 		openrtb_ext.BidderSomoaudience:     somoaudience.NewSomoaudienceBidder(cfg.Adapters[string(openrtb_ext.BidderSomoaudience)].Endpoint),
diff --git a/exchange/bidder.go b/exchange/bidder.go
index 7c39b72b..decad8cc 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -150,7 +150,7 @@ func (bidder *bidderAdapter) requestBid(ctx context.Context, request *openrtb.Bi
 	for i := 0; i < len(reqData); i++ {
 		httpInfo := <-responseChannel
 		// If this is a test bid, capture debugging info from the requests.
-		if request.Test == 1 {
+		if debugInfo := ctx.Value(DebugContextKey); debugInfo != nil && debugInfo.(bool) {
 			seatBid.httpCalls = append(seatBid.httpCalls, makeExt(httpInfo))
 		}
 
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 5001e495..ad591f57 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -27,6 +27,10 @@ import (
 	"github.com/prebid/prebid-server/prebid_cache_client"
 )
 
+type ContextKey string
+
+const DebugContextKey = ContextKey("debugInfo")
+
 // Exchange runs Auctions. Implementations must be threadsafe, and will be shared across many goroutines.
 type Exchange interface {
 	// HoldAuction executes an OpenRTB v2.5 Auction.
@@ -86,12 +90,25 @@ func NewExchange(client *http.Client, cache prebid_cache_client.Client, cfg *con
 }
 
 func (e *exchange) HoldAuction(ctx context.Context, bidRequest *openrtb.BidRequest, usersyncs IdFetcher, labels pbsmetrics.Labels, categoriesFetcher *stored_requests.CategoryFetcher, debugLog *DebugLog) (*openrtb.BidResponse, error) {
-	// Snapshot of resolved bid request for debug if test request
-	resolvedRequest, err := buildResolvedRequest(bidRequest)
+
+	requestExt, err := extractBidRequestExt(bidRequest)
 	if err != nil {
-		glog.Errorf("Error marshalling bid request for debug: %v", err)
+		return nil, err
+	}
+
+	shouldCacheBids, shouldCacheVAST := getExtCacheInfo(requestExt)
+	targData := getExtTargetData(requestExt, shouldCacheBids, shouldCacheVAST)
+	if targData != nil {
+		targData.cacheHost, targData.cachePath = e.cache.GetExtCacheData()
+	}
+
+	debugInfo := getDebugInfo(bidRequest, requestExt)
+	if debugInfo {
+		ctx = e.makeDebugContext(ctx, debugInfo)
 	}
 
+	bidAdjustmentFactors := getExtBidAdjustmentFactors(requestExt)
+
 	for _, impInRequest := range bidRequest.Imp {
 		var impLabels pbsmetrics.ImpLabels = pbsmetrics.ImpLabels{
 			BannerImps: impInRequest.Banner != nil,
@@ -104,46 +121,16 @@ func (e *exchange) HoldAuction(ctx context.Context, bidRequest *openrtb.BidReque
 
 	// Slice of BidRequests, each a copy of the original cleaned to only contain bidder data for the named bidder
 	blabels := make(map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels)
-	cleanRequests, aliases, privacyLabels, errs := cleanOpenRTBRequests(ctx, bidRequest, usersyncs, blabels, labels, e.gDPR, e.UsersyncIfAmbiguous, e.privacyConfig)
+	cleanRequests, aliases, privacyLabels, errs := cleanOpenRTBRequests(ctx, bidRequest, requestExt, usersyncs, blabels, labels, e.gDPR, e.UsersyncIfAmbiguous, e.privacyConfig)
 
 	e.me.RecordRequestPrivacy(privacyLabels)
 
 	// List of bidders we have requests for.
 	liveAdapters := listBiddersWithRequests(cleanRequests)
 
-	// Process the request to check for targeting parameters.
-	var targData *targetData
-	shouldCacheBids := false
-	shouldCacheVAST := false
-	var bidAdjustmentFactors map[string]float64
-	var requestExt openrtb_ext.ExtRequest
-	if len(bidRequest.Ext) > 0 {
-		err := json.Unmarshal(bidRequest.Ext, &requestExt)
-		if err != nil {
-			return nil, fmt.Errorf("Error decoding Request.ext : %s", err.Error())
-		}
-		bidAdjustmentFactors = requestExt.Prebid.BidAdjustmentFactors
-		if requestExt.Prebid.Cache != nil {
-			shouldCacheBids = requestExt.Prebid.Cache.Bids != nil
-			shouldCacheVAST = requestExt.Prebid.Cache.VastXML != nil
-		}
-
-		if requestExt.Prebid.Targeting != nil {
-			targData = &targetData{
-				priceGranularity:  requestExt.Prebid.Targeting.PriceGranularity,
-				includeWinners:    requestExt.Prebid.Targeting.IncludeWinners,
-				includeBidderKeys: requestExt.Prebid.Targeting.IncludeBidderKeys,
-				includeCacheBids:  shouldCacheBids,
-				includeCacheVast:  shouldCacheVAST,
-				includeFormat:     requestExt.Prebid.Targeting.IncludeFormat,
-			}
-			targData.cacheHost, targData.cachePath = e.cache.GetExtCacheData()
-		}
-	}
-
 	// If we need to cache bids, then it will take some time to call prebid cache.
 	// We should reduce the amount of time the bidders have, to compensate.
-	auctionCtx, cancel := e.makeAuctionContext(ctx, shouldCacheBids) //Why no context for `shouldCacheVast`?
+	auctionCtx, cancel := e.makeAuctionContext(ctx, shouldCacheBids)
 	defer cancel()
 
 	// Get currency rates conversions for the auction
@@ -180,7 +167,7 @@ func (e *exchange) HoldAuction(ctx context.Context, bidRequest *openrtb.BidReque
 			}
 
 			if debugLog != nil && debugLog.Enabled {
-				bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, bidRequest, resolvedRequest, errs)
+				bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, bidRequest, debugInfo, errs)
 				if bidRespExtBytes, err := json.Marshal(bidResponseExt); err == nil {
 					debugLog.Data.Response = string(bidRespExtBytes)
 				} else {
@@ -205,7 +192,7 @@ func (e *exchange) HoldAuction(ctx context.Context, bidRequest *openrtb.BidReque
 	}
 
 	// Build the response
-	return e.buildBidResponse(ctx, liveAdapters, adapterBids, bidRequest, resolvedRequest, adapterExtra, auc, bidResponseExt, errs)
+	return e.buildBidResponse(ctx, liveAdapters, adapterBids, bidRequest, adapterExtra, auc, bidResponseExt, errs)
 }
 
 type DealTierInfo struct {
@@ -284,6 +271,11 @@ func updateHbPbCatDur(bid *pbsOrtbBid, dealTierInfo *DealTierInfo, bidCategory m
 	}
 }
 
+func (e *exchange) makeDebugContext(ctx context.Context, debugInfo bool) (debugCtx context.Context) {
+	debugCtx = context.WithValue(ctx, DebugContextKey, debugInfo)
+	return
+}
+
 func (e *exchange) makeAuctionContext(ctx context.Context, needsCache bool) (auctionCtx context.Context, cancel context.CancelFunc) {
 	auctionCtx = ctx
 	cancel = func() {}
@@ -445,7 +437,7 @@ func errsToBidderErrors(errs []error) []openrtb_ext.ExtBidderError {
 }
 
 // This piece takes all the bids supplied by the adapters and crafts an openRTB response to send back to the requester
-func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_ext.BidderName, adapterBids map[openrtb_ext.BidderName]*pbsOrtbSeatBid, bidRequest *openrtb.BidRequest, resolvedRequest json.RawMessage, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, auc *auction, bidResponseExt *openrtb_ext.ExtBidResponse, errList []error) (*openrtb.BidResponse, error) {
+func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_ext.BidderName, adapterBids map[openrtb_ext.BidderName]*pbsOrtbSeatBid, bidRequest *openrtb.BidRequest, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, auc *auction, bidResponseExt *openrtb_ext.ExtBidResponse, errList []error) (*openrtb.BidResponse, error) {
 	bidResponse := new(openrtb.BidResponse)
 
 	bidResponse.ID = bidRequest.ID
@@ -469,7 +461,12 @@ func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_
 	bidResponse.SeatBid = seatBids
 
 	if bidResponseExt == nil {
-		bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, bidRequest, resolvedRequest, errList)
+		contextDebugValue := ctx.Value(DebugContextKey)
+		var debugInfo bool
+		if contextDebugValue != nil {
+			debugInfo = contextDebugValue.(bool)
+		}
+		bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, bidRequest, debugInfo, errList)
 	}
 	buffer := &bytes.Buffer{}
 	enc := json.NewEncoder(buffer)
@@ -480,7 +477,7 @@ func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_
 	return bidResponse, err
 }
 
-func applyCategoryMapping(ctx context.Context, requestExt openrtb_ext.ExtRequest, seatBids map[openrtb_ext.BidderName]*pbsOrtbSeatBid, categoriesFetcher stored_requests.CategoryFetcher, targData *targetData) (map[string]string, map[openrtb_ext.BidderName]*pbsOrtbSeatBid, []string, error) {
+func applyCategoryMapping(ctx context.Context, requestExt *openrtb_ext.ExtRequest, seatBids map[openrtb_ext.BidderName]*pbsOrtbSeatBid, categoriesFetcher stored_requests.CategoryFetcher, targData *targetData) (map[string]string, map[openrtb_ext.BidderName]*pbsOrtbSeatBid, []string, error) {
 	res := make(map[string]string)
 
 	type bidDedupe struct {
@@ -491,6 +488,8 @@ func applyCategoryMapping(ctx context.Context, requestExt openrtb_ext.ExtRequest
 
 	dedupe := make(map[string]bidDedupe)
 
+	// applyCategoryMapping doesn't get called unless
+	// requestExt.Prebid.Targeting != nil && requestExt.Prebid.Targeting.IncludeBrandCategory != nil
 	brandCatExt := requestExt.Prebid.Targeting.IncludeBrandCategory
 
 	//If ext.prebid.targeting.includebrandcategory is present in ext then competitive exclusion feature is on.
@@ -656,24 +655,22 @@ func getPrimaryAdServer(adServerId int) (string, error) {
 }
 
 // Extract all the data from the SeatBids and build the ExtBidResponse
-func (e *exchange) makeExtBidResponse(adapterBids map[openrtb_ext.BidderName]*pbsOrtbSeatBid, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, req *openrtb.BidRequest, resolvedRequest json.RawMessage, errList []error) *openrtb_ext.ExtBidResponse {
+func (e *exchange) makeExtBidResponse(adapterBids map[openrtb_ext.BidderName]*pbsOrtbSeatBid, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, req *openrtb.BidRequest, debugInfo bool, errList []error) *openrtb_ext.ExtBidResponse {
 	bidResponseExt := &openrtb_ext.ExtBidResponse{
 		Errors:               make(map[openrtb_ext.BidderName][]openrtb_ext.ExtBidderError, len(adapterBids)),
 		ResponseTimeMillis:   make(map[openrtb_ext.BidderName]int, len(adapterBids)),
 		RequestTimeoutMillis: req.TMax,
 	}
-	if req.Test == 1 {
+	if debugInfo {
 		bidResponseExt.Debug = &openrtb_ext.ExtResponseDebug{
-			HttpCalls: make(map[openrtb_ext.BidderName][]*openrtb_ext.ExtHttpCall),
-		}
-		if err := json.Unmarshal(resolvedRequest, &bidResponseExt.Debug.ResolvedRequest); err != nil {
-			glog.Errorf("Error unmarshalling bid request snapshot: %v", err)
+			HttpCalls:       make(map[openrtb_ext.BidderName][]*openrtb_ext.ExtHttpCall),
+			ResolvedRequest: req,
 		}
 	}
 
 	for bidderName, responseExtra := range adapterExtra {
 
-		if req.Test == 1 {
+		if debugInfo {
 			bidResponseExt.Debug.HttpCalls[bidderName] = responseExtra.HttpCalls
 		}
 		// Only make an entry for bidder errors if the bidder reported any.
@@ -774,14 +771,6 @@ func (e *exchange) getBidCacheInfo(bid *pbsOrtbBid, auc *auction) (openrtb_ext.E
 	return cacheInfo, found
 }
 
-// Returns a snapshot of resolved bid request for debug if test field is set in the incomming request
-func buildResolvedRequest(bidRequest *openrtb.BidRequest) (json.RawMessage, error) {
-	if bidRequest.Test == 1 {
-		return json.Marshal(bidRequest)
-	}
-	return nil, nil
-}
-
 func listBiddersWithRequests(cleanRequests map[openrtb_ext.BidderName]*openrtb.BidRequest) []openrtb_ext.BidderName {
 	liveAdapters := make([]openrtb_ext.BidderName, len(cleanRequests))
 	i := 0
diff --git a/exchange/utils.go b/exchange/utils.go
index bc1b555e..97fae7b7 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -22,12 +22,8 @@ import (
 func BidderToPrebidSChains(req *openrtb_ext.ExtRequest) (map[string]*openrtb_ext.ExtRequestPrebidSChainSChain, error) {
 	bidderToSChains := make(map[string]*openrtb_ext.ExtRequestPrebidSChainSChain)
 
-	if len(req.Prebid.SChains) == 0 {
-		return bidderToSChains, nil
-	}
-
-	for _, schainWrapper := range req.Prebid.SChains {
-		if schainWrapper != nil && len(schainWrapper.Bidders) > 0 {
+	if req != nil {
+		for _, schainWrapper := range req.Prebid.SChains {
 			for _, bidder := range schainWrapper.Bidders {
 				if _, present := bidderToSChains[bidder]; present {
 					return nil, fmt.Errorf("request.ext.prebid.schains contains multiple schains for bidder %s; "+
@@ -49,6 +45,7 @@ func BidderToPrebidSChains(req *openrtb_ext.ExtRequest) (map[string]*openrtb_ext
 //   3. BidRequest.User.BuyerUID will be set to that Bidder's ID.
 func cleanOpenRTBRequests(ctx context.Context,
 	orig *openrtb.BidRequest,
+	requestExt *openrtb_ext.ExtRequest,
 	usersyncs IdFetcher,
 	blables map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels,
 	labels pbsmetrics.Labels,
@@ -66,7 +63,7 @@ func cleanOpenRTBRequests(ctx context.Context,
 		return
 	}
 
-	requestsByBidder, errs = splitBidRequest(orig, impsByBidder, aliases, usersyncs, blables, labels)
+	requestsByBidder, errs = splitBidRequest(orig, requestExt, impsByBidder, aliases, usersyncs, blables, labels)
 
 	gdpr := extractGDPR(orig, usersyncIfAmbiguous)
 	consent := extractConsent(orig)
@@ -125,6 +122,7 @@ func cleanOpenRTBRequests(ctx context.Context,
 }
 
 func splitBidRequest(req *openrtb.BidRequest,
+	requestExt *openrtb_ext.ExtRequest,
 	impsByBidder map[string][]openrtb.Imp,
 	aliases map[string]string,
 	usersyncs IdFetcher,
@@ -137,20 +135,16 @@ func splitBidRequest(req *openrtb.BidRequest,
 		return nil, []error{err}
 	}
 
-	var requestExt openrtb_ext.ExtRequest
 	var sChainsByBidder map[string]*openrtb_ext.ExtRequestPrebidSChainSChain
-	if len(req.Ext) > 0 {
-		err := json.Unmarshal(req.Ext, &requestExt)
-		if err != nil {
-			return nil, []error{err}
-		}
 
-		sChainsByBidder, err = BidderToPrebidSChains(&requestExt)
-		if err != nil {
-			return nil, []error{err}
-		}
-	} else {
-		sChainsByBidder = make(map[string]*openrtb_ext.ExtRequestPrebidSChainSChain)
+	sChainsByBidder, err = BidderToPrebidSChains(requestExt)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	reqExt, err := getExtJson(req, requestExt)
+	if err != nil {
+		return nil, []error{err}
 	}
 
 	for bidder, imps := range impsByBidder {
@@ -174,23 +168,21 @@ func splitBidRequest(req *openrtb.BidRequest,
 		reqCopy.Imp = imps
 
 		prepareSource(&reqCopy, bidder, sChainsByBidder)
-		prepareExt(&reqCopy, &requestExt)
+		reqCopy.Ext = reqExt
 
 		requestsByBidder[openrtb_ext.BidderName(bidder)] = &reqCopy
 	}
 	return requestsByBidder, nil
 }
 
-func prepareExt(req *openrtb.BidRequest, unpackedExt *openrtb_ext.ExtRequest) {
-	if len(req.Ext) == 0 {
-		return
+func getExtJson(req *openrtb.BidRequest, unpackedExt *openrtb_ext.ExtRequest) (json.RawMessage, error) {
+	if len(req.Ext) == 0 || unpackedExt == nil {
+		return json.RawMessage(``), nil
 	}
+
 	extCopy := *unpackedExt
 	extCopy.Prebid.SChains = nil
-	reqExt, err := json.Marshal(extCopy)
-	if err == nil {
-		req.Ext = reqExt
-	}
+	return json.Marshal(extCopy)
 }
 
 func prepareSource(req *openrtb.BidRequest, bidder string, sChainsByBidder map[string]*openrtb_ext.ExtRequestPrebidSChainSChain) {
@@ -434,3 +426,55 @@ func randomizeList(list []openrtb_ext.BidderName) {
 		list[i], list[j] = list[j], list[i]
 	}
 }
+
+func extractBidRequestExt(bidRequest *openrtb.BidRequest) (*openrtb_ext.ExtRequest, error) {
+	requestExt := &openrtb_ext.ExtRequest{}
+
+	if bidRequest == nil {
+		return requestExt, fmt.Errorf("Error bidRequest should not be nil")
+	}
+
+	if len(bidRequest.Ext) > 0 {
+		err := json.Unmarshal(bidRequest.Ext, &requestExt)
+		if err != nil {
+			return requestExt, fmt.Errorf("Error decoding Request.ext : %s", err.Error())
+		}
+	}
+	return requestExt, nil
+}
+
+func getExtCacheInfo(requestExt *openrtb_ext.ExtRequest) (shouldCacheBids bool, shouldCacheVAST bool) {
+	if requestExt != nil && requestExt.Prebid.Cache != nil {
+		shouldCacheBids = requestExt.Prebid.Cache.Bids != nil
+		shouldCacheVAST = requestExt.Prebid.Cache.VastXML != nil
+	}
+	return
+}
+
+func getExtTargetData(requestExt *openrtb_ext.ExtRequest, shouldCacheBids bool, shouldCacheVAST bool) *targetData {
+	var targData *targetData
+
+	if requestExt != nil && requestExt.Prebid.Targeting != nil {
+		targData = &targetData{
+			priceGranularity:  requestExt.Prebid.Targeting.PriceGranularity,
+			includeWinners:    requestExt.Prebid.Targeting.IncludeWinners,
+			includeBidderKeys: requestExt.Prebid.Targeting.IncludeBidderKeys,
+			includeCacheBids:  shouldCacheBids,
+			includeCacheVast:  shouldCacheVAST,
+			includeFormat:     requestExt.Prebid.Targeting.IncludeFormat,
+		}
+	}
+	return targData
+}
+
+func getDebugInfo(bidRequest *openrtb.BidRequest, requestExt *openrtb_ext.ExtRequest) bool {
+	return (bidRequest != nil && bidRequest.Test == 1) || (requestExt != nil && requestExt.Prebid.Debug)
+}
+
+func getExtBidAdjustmentFactors(requestExt *openrtb_ext.ExtRequest) map[string]float64 {
+	var bidAdjustmentFactors map[string]float64
+	if requestExt != nil {
+		bidAdjustmentFactors = requestExt.Prebid.BidAdjustmentFactors
+	}
+	return bidAdjustmentFactors
+}
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 62fb9750..761f53d4 100755
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -34,6 +34,7 @@ const (
 	BidderAdman            BidderName = "adman"
 	BidderAdmixer          BidderName = "admixer"
 	BidderAdOcean          BidderName = "adocean"
+	BidderAdprime          BidderName = "adprime"
 	BidderAdtarget         BidderName = "adtarget"
 	BidderAdtelligent      BidderName = "adtelligent"
 	BidderAdvangelists     BidderName = "advangelists"
@@ -80,6 +81,7 @@ const (
 	BidderRTBHouse         BidderName = "rtbhouse"
 	BidderRubicon          BidderName = "rubicon"
 	BidderSharethrough     BidderName = "sharethrough"
+	BidderSmaato           BidderName = "smaato"
 	BidderSmartadserver    BidderName = "smartadserver"
 	BidderSmartRTB         BidderName = "smartrtb"
 	BidderSomoaudience     BidderName = "somoaudience"
@@ -115,6 +117,7 @@ var BidderMap = map[string]BidderName{
 	"adman":             BidderAdman,
 	"admixer":           BidderAdmixer,
 	"adocean":           BidderAdOcean,
+	"adprime":           BidderAdprime,
 	"adpone":            BidderAdpone,
 	"adtarget":          BidderAdtarget,
 	"adtelligent":       BidderAdtelligent,
@@ -162,6 +165,7 @@ var BidderMap = map[string]BidderName{
 	"rtbhouse":          BidderRTBHouse,
 	"rubicon":           BidderRubicon,
 	"sharethrough":      BidderSharethrough,
+	"smaato":            BidderSmaato,
 	"smartadserver":     BidderSmartadserver,
 	"smartrtb":          BidderSmartRTB,
 	"somoaudience":      BidderSomoaudience,
diff --git a/openrtb_ext/imp_adprime.go b/openrtb_ext/imp_adprime.go
new file mode 100644
index 00000000..a089b818
--- /dev/null
+++ b/openrtb_ext/imp_adprime.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+// ExtImpAdprime defines adprime specifiec param
+type ExtImpAdprime struct {
+	TagID string `json:"TagID"`
+}
diff --git a/openrtb_ext/imp_smaato.go b/openrtb_ext/imp_smaato.go
new file mode 100644
index 00000000..10de97fb
--- /dev/null
+++ b/openrtb_ext/imp_smaato.go
@@ -0,0 +1,9 @@
+package openrtb_ext
+
+// ExtImpSmaato defines the contract for bidrequest.imp[i].ext.smaato
+// PublisherId and AdSpaceId are mandatory parameters, others are optional parameters
+// AdSpaceId is identifier for specific ad placement or ad tag
+type ExtImpSmaato struct {
+	PublisherID string `json:"publisherId"`
+	AdSpaceID   string `json:"adspaceId"`
+}
diff --git a/openrtb_ext/request.go b/openrtb_ext/request.go
index acfd4a1e..23daaf0f 100644
--- a/openrtb_ext/request.go
+++ b/openrtb_ext/request.go
@@ -19,6 +19,7 @@ type ExtRequestPrebid struct {
 	StoredRequest        *ExtStoredRequest         `json:"storedrequest,omitempty"`
 	Targeting            *ExtRequestTargeting      `json:"targeting,omitempty"`
 	SupportDeals         bool                      `json:"supportdeals,omitempty"`
+	Debug                bool                      `json:"debug,omitempty"`
 }
 
 // ExtRequestPrebid defines the contract for bidrequest.ext.prebid.schains
diff --git a/static/bidder-info/adprime.yaml b/static/bidder-info/adprime.yaml
new file mode 100644
index 00000000..9759ed63
--- /dev/null
+++ b/static/bidder-info/adprime.yaml
@@ -0,0 +1,11 @@
+maintainer:
+  email: "rafal@adprime.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video 
\ No newline at end of file
diff --git a/static/bidder-info/smaato.yaml b/static/bidder-info/smaato.yaml
new file mode 100644
index 00000000..662603fe
--- /dev/null
+++ b/static/bidder-info/smaato.yaml
@@ -0,0 +1,9 @@
+maintainer:
+  email: "prebid@smaato.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+  site:
+    mediaTypes:
+      - banner
\ No newline at end of file
diff --git a/static/bidder-params/adprime.json b/static/bidder-params/adprime.json
new file mode 100644
index 00000000..d5270565
--- /dev/null
+++ b/static/bidder-params/adprime.json
@@ -0,0 +1,14 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "Adprime Adapter Params",
+    "description": "A schema which validates params accepted by the Adprime adapter",
+
+    "type": "object",
+    "properties": {
+      "TagID": {
+        "type": "string",
+        "description": "An ID which identifies the adprime ad tag"
+      }
+    },
+    "required" : [ "TagID" ]
+  }
\ No newline at end of file
diff --git a/static/bidder-params/smaato.json b/static/bidder-params/smaato.json
new file mode 100644
index 00000000..aa91c4ba
--- /dev/null
+++ b/static/bidder-params/smaato.json
@@ -0,0 +1,17 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Smaato Adapter Params",
+  "description": "A schema which validates params accepted by the Smaato adapter",
+  "type": "object",
+  "properties": {
+    "publisherId": {
+      "type": "string",
+      "description": "A unique identifier for this impression within the context of the bid request"
+    },
+    "adspaceId": {
+      "type": "string",
+      "description": "Identifier for specific ad placement is SOMA `adspaceId`"
+    }
+  },
+  "required": ["publisherId","adspaceId"]
+}
\ No newline at end of file


Test patch:
diff --git a/adapters/adprime/adprime_test.go b/adapters/adprime/adprime_test.go
new file mode 100644
index 00000000..2d3ee9b2
--- /dev/null
+++ b/adapters/adprime/adprime_test.go
@@ -0,0 +1,12 @@
+package adprime
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+)
+
+func TestJsonSamples(t *testing.T) {
+	adprimeAdapter := NewAdprimeBidder("http://delta.adprime.com/?c=o&m=ortb")
+	adapterstest.RunJSONBidderTest(t, "adprimetest", adprimeAdapter)
+}
diff --git a/adapters/adprime/adprimetest/exemplary/simple-banner.json b/adapters/adprime/adprimetest/exemplary/simple-banner.json
new file mode 100644
index 00000000..076175c6
--- /dev/null
+++ b/adapters/adprime/adprimetest/exemplary/simple-banner.json
@@ -0,0 +1,134 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+        {
+            "id": "test-imp-id",
+            "banner": {
+                "format": [
+                    {
+                        "w": 300,
+                        "h": 250
+                    },
+                    {
+                        "w": 300,
+                        "h": 600
+                    }
+                ]
+            },
+            "tagid": "1",
+            "ext": {
+                "bidder": {
+                    "TagID": "1"
+                }
+            }
+        }
+    ],
+    "app": {
+        "id": "1",
+        "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+        "ip": "123.123.123.123",
+        "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+},
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://delta.adprime.com/?c=o&m=ortb",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+              {
+                  "id": "test-imp-id",
+                  "banner": {
+                      "format": [
+                          {
+                              "w": 300,
+                              "h": 250
+                          },
+                          {
+                              "w": 300,
+                              "h": 600
+                          }
+                      ]
+                  },
+                  "tagid": "1",
+                  "ext": {
+                      "bidder": {
+                          "TagID": "1"
+                      }
+                  }
+              }
+          ],
+          "app": {
+              "id": "1",
+              "bundle": "com.wls.testwlsapplication"
+          },
+          "device": {
+              "ip": "123.123.123.123",
+              "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          }
+      }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+              {
+                  "bid": [
+                      {
+                          "id": "test_bid_id",
+                          "impid": "test-imp-id",
+                          "price": 0.27543,
+                          "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                          "cid": "test_cid",
+                          "crid": "test_crid",
+                          "dealid": "test_dealid",
+                          "w": 300,
+                          "h": 250,
+                          "ext": {
+                              "prebid": {
+                                  "type": "banner"
+                              }
+                          }
+                      }
+                  ],
+                  "seat": "adprime"
+              }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "prebid": {
+                "type": "banner"
+              }
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adprime/adprimetest/exemplary/simple-video.json b/adapters/adprime/adprimetest/exemplary/simple-video.json
new file mode 100644
index 00000000..3e61c4dd
--- /dev/null
+++ b/adapters/adprime/adprimetest/exemplary/simple-video.json
@@ -0,0 +1,119 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "TagID": "288"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://delta.adprime.com/?c=o&m=ortb",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "tagid": "288",
+              "ext": {
+                "bidder": {
+                  "TagID": "288"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+              {
+                  "bid": [
+                      {
+                          "id": "test_bid_id",
+                          "impid": "test-imp-id",
+                          "price": 0.27543,
+                          "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
+                          "cid": "test_cid",
+                          "crid": "test_crid",
+                          "dealid": "test_dealid",
+                          "ext": {
+                              "prebid": {
+                                  "type": "video"
+                              }
+                          }
+                      }
+                  ],
+                  "seat": "adprime"
+              }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+                          "impid": "test-imp-id",
+                          "price": 0.27543,
+                          "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
+                          "cid": "test_cid",
+                          "crid": "test_crid",
+                          "dealid": "test_dealid",
+                          "ext": {
+                              "prebid": {
+                                  "type": "video"
+                              }
+                          }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adprime/adprimetest/exemplary/simple-web-banner.json b/adapters/adprime/adprimetest/exemplary/simple-web-banner.json
new file mode 100644
index 00000000..a955854f
--- /dev/null
+++ b/adapters/adprime/adprimetest/exemplary/simple-web-banner.json
@@ -0,0 +1,133 @@
+{
+    "mockBidRequest": {
+      "id": "test-request-id",
+      "imp": [
+          {
+              "id": "test-imp-id",
+              "banner": {
+                  "format": [
+                      {
+                          "w": 300,
+                          "h": 250
+                      },
+                      {
+                          "w": 300,
+                          "h": 600
+                      }
+                  ]
+              },
+              "tagid": "1",
+              "ext": {
+                  "bidder": {
+                      "TagID": "1"
+                  }
+              }
+          }
+      ],
+      "site": {
+          "id": "1",
+          "domain": "test.com"
+      },
+      "device": {
+          "ip": "123.123.123.123"
+      }
+  },
+  
+    "httpCalls": [
+      {
+        "expectedRequest": {
+          "uri": "http://delta.adprime.com/?c=o&m=ortb",
+          "body": {
+            "id": "test-request-id",
+            "imp": [
+                {
+                    "id": "test-imp-id",
+                    "banner": {
+                        "format": [
+                            {
+                                "w": 300,
+                                "h": 250
+                            },
+                            {
+                                "w": 300,
+                                "h": 600
+                            }
+                        ]
+                    },
+                    "tagid": "1",
+                    "ext": {
+                        "bidder": {
+                            "TagID": "1"
+                        }
+                    }
+                }
+            ],
+            "site": {
+                "id": "1",
+                "domain": "test.com"
+            },
+            "device": {
+                "ip": "123.123.123.123"
+            }
+        }
+        },
+        "mockResponse": {
+          "status": 200,
+          "body": {
+            "id": "test-request-id",
+            "seatbid": [
+                {
+                    "bid": [
+                        {
+                            "id": "test_bid_id",
+                            "impid": "test-imp-id",
+                            "price": 0.27543,
+                            "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
+                            "cid": "test_cid",
+                            "crid": "test_crid",
+                            "dealid": "test_dealid",
+                            "w": 468,
+                            "h": 60,
+                            "ext": {
+                                "prebid": {
+                                    "type": "banner"
+                                }
+                            }
+                        }
+                    ],
+                    "seat": "adprime"
+                }
+            ],
+            "cur": "USD"
+          }
+        }
+      }
+    ],
+  
+    "expectedBidResponses": [
+      {
+        "bids":[
+          {
+            "bid":  {
+                "id": "test_bid_id",
+                "impid": "test-imp-id",
+                "price": 0.27543,
+                "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
+                "cid": "test_cid",
+                "crid": "test_crid",
+                "dealid": "test_dealid",
+                "w": 468,
+                "h": 60,
+                "ext": {
+                    "prebid": {
+                        "type": "banner"
+                    }
+                }
+            },
+            "type": "banner"
+          }
+        ]
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/params/banner.json b/adapters/adprime/adprimetest/params/banner.json
new file mode 100644
index 00000000..e3f4cb76
--- /dev/null
+++ b/adapters/adprime/adprimetest/params/banner.json
@@ -0,0 +1,3 @@
+{
+    "TagID": "1"
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/params/race/banner.json b/adapters/adprime/adprimetest/params/race/banner.json
new file mode 100644
index 00000000..e3f4cb76
--- /dev/null
+++ b/adapters/adprime/adprimetest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+    "TagID": "1"
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/params/race/video.json b/adapters/adprime/adprimetest/params/race/video.json
new file mode 100644
index 00000000..c8d14757
--- /dev/null
+++ b/adapters/adprime/adprimetest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+    "TagID": "288"
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/params/video.json b/adapters/adprime/adprimetest/params/video.json
new file mode 100644
index 00000000..c8d14757
--- /dev/null
+++ b/adapters/adprime/adprimetest/params/video.json
@@ -0,0 +1,3 @@
+{
+    "TagID": "288"
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/supplemental/bad-imp-ext.json b/adapters/adprime/adprimetest/supplemental/bad-imp-ext.json
new file mode 100644
index 00000000..a95c56e8
--- /dev/null
+++ b/adapters/adprime/adprimetest/supplemental/bad-imp-ext.json
@@ -0,0 +1,42 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+        {
+            "id": "test-imp-id",
+            "banner": {
+                "format": [
+                    {
+                        "w": 300,
+                        "h": 250
+                    },
+                    {
+                        "w": 300,
+                        "h": 600
+                    }
+                ]
+            },
+            "tagid": "1",
+            "ext": {
+                "adprime": {
+                    "TagID": "1"
+                }
+            }
+        }
+    ],
+    "app": {
+        "id": "1",
+        "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+        "ip": "123.123.123.123",
+        "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    }
+},
+"expectedMakeRequestsErrors": [
+  {
+    "value": "Key path not found",
+    "comparison": "literal"
+  }
+]
+}
diff --git a/adapters/adprime/adprimetest/supplemental/bad_response.json b/adapters/adprime/adprimetest/supplemental/bad_response.json
new file mode 100644
index 00000000..329e9c72
--- /dev/null
+++ b/adapters/adprime/adprimetest/supplemental/bad_response.json
@@ -0,0 +1,85 @@
+{
+	"mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "tagid": "17",
+                "ext": {
+                    "bidder": {
+                        "TagID": "17"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+        }
+    },
+	"httpCalls": [{
+		"expectedRequest": {
+			"uri": "http://delta.adprime.com/?c=o&m=ortb",
+			"body": {
+                "id": "test-request-id",
+                "imp": [
+                    {
+                        "id": "test-imp-id",
+                        "banner": {
+                            "format": [
+                                {
+                                    "w": 300,
+                                    "h": 250
+                                },
+                                {
+                                    "w": 300,
+                                    "h": 600
+                                }
+                            ]
+                        },
+                        "tagid": "17",
+                        "ext": {
+                            "bidder": {
+                                "TagID": "17"
+                            }
+                        }
+                    }
+                ],
+                "app": {
+                    "id": "1",
+                    "bundle": "com.wls.testwlsapplication"
+                },
+                "device": {
+                    "ip": "123.123.123.123",
+                    "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+                }
+            }
+		},
+		"mockResponse": {
+			"status": 200,
+			"body": ""
+        }
+    }],
+    "expectedMakeBidsErrors": [
+        {
+          "value": "json: cannot unmarshal string into Go value of type openrtb.BidResponse",
+          "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/adprime/adprimetest/supplemental/no-imp-ext-1.json b/adapters/adprime/adprimetest/supplemental/no-imp-ext-1.json
new file mode 100644
index 00000000..1e38dbe4
--- /dev/null
+++ b/adapters/adprime/adprimetest/supplemental/no-imp-ext-1.json
@@ -0,0 +1,39 @@
+{
+    "mockBidRequest": {
+      "id": "test-request-id",
+      "imp": [
+          {
+              "id": "test-imp-id",
+              "banner": {
+                  "format": [
+                      {
+                          "w": 300,
+                          "h": 250
+                      },
+                      {
+                          "w": 300,
+                          "h": 600
+                      }
+                  ]
+              },
+              "tagid": "1",
+              "ext": ""
+          }
+      ],
+      "app": {
+          "id": "1",
+          "bundle": "com.wls.testwlsapplication"
+      },
+      "device": {
+          "ip": "123.123.123.123",
+          "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+      }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Key path not found",
+      "comparison": "literal"
+    }
+  ]
+  }
+  
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/supplemental/no-imp-ext-2.json b/adapters/adprime/adprimetest/supplemental/no-imp-ext-2.json
new file mode 100644
index 00000000..f9759fae
--- /dev/null
+++ b/adapters/adprime/adprimetest/supplemental/no-imp-ext-2.json
@@ -0,0 +1,39 @@
+{
+    "mockBidRequest": {
+      "id": "test-request-id",
+      "imp": [
+          {
+              "id": "test-imp-id",
+              "banner": {
+                  "format": [
+                      {
+                          "w": 300,
+                          "h": 250
+                      },
+                      {
+                          "w": 300,
+                          "h": 600
+                      }
+                  ]
+              },
+              "tagid": "1",
+              "ext": {}
+          }
+      ],
+      "app": {
+          "id": "1",
+          "bundle": "com.wls.testwlsapplication"
+      },
+      "device": {
+          "ip": "123.123.123.123",
+          "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+      }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Key path not found",
+      "comparison": "literal"
+    }
+  ]
+  }
+  
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/supplemental/status-204.json b/adapters/adprime/adprimetest/supplemental/status-204.json
new file mode 100644
index 00000000..44ee59d4
--- /dev/null
+++ b/adapters/adprime/adprimetest/supplemental/status-204.json
@@ -0,0 +1,79 @@
+{
+	"mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "tagid": "17",
+                "ext": {
+                    "bidder": {
+                        "TagID": "17"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+        }
+    },
+	"httpCalls": [{
+		"expectedRequest": {
+			"uri": "http://delta.adprime.com/?c=o&m=ortb",
+			"body": {
+                "id": "test-request-id",
+                "imp": [
+                    {
+                        "id": "test-imp-id",
+                        "banner": {
+                            "format": [
+                                {
+                                    "w": 300,
+                                    "h": 250
+                                },
+                                {
+                                    "w": 300,
+                                    "h": 600
+                                }
+                            ]
+                        },
+                        "tagid": "17",
+                        "ext": {
+                            "bidder": {
+                                "TagID": "17"
+                            }
+                        }
+                    }
+                ],
+                "app": {
+                    "id": "1",
+                    "bundle": "com.wls.testwlsapplication"
+                },
+                "device": {
+                    "ip": "123.123.123.123",
+                    "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+                }
+            }
+		},
+		"mockResponse": {
+			"status": 204,
+			"body": {}
+		}
+	}]
+}
diff --git a/adapters/adprime/adprimetest/supplemental/status-404.json b/adapters/adprime/adprimetest/supplemental/status-404.json
new file mode 100644
index 00000000..c2b303f0
--- /dev/null
+++ b/adapters/adprime/adprimetest/supplemental/status-404.json
@@ -0,0 +1,85 @@
+{
+	"mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "tagid": "100000000",
+                "ext": {
+                    "bidder": {
+                        "TagID": "100000000"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+        }
+    },
+	"httpCalls": [{
+		"expectedRequest": {
+			"uri": "http://delta.adprime.com/?c=o&m=ortb",
+			"body": {
+                "id": "test-request-id",
+                "imp": [
+                    {
+                        "id": "test-imp-id",
+                        "banner": {
+                            "format": [
+                                {
+                                    "w": 300,
+                                    "h": 250
+                                },
+                                {
+                                    "w": 300,
+                                    "h": 600
+                                }
+                            ]
+                        },
+                        "tagid": "100000000",
+                        "ext": {
+                            "bidder": {
+                                "TagID": "100000000"
+                            }
+                        }
+                    }
+                ],
+                "app": {
+                    "id": "1",
+                    "bundle": "com.wls.testwlsapplication"
+                },
+                "device": {
+                    "ip": "123.123.123.123",
+                    "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+                }
+            }
+		},
+		"mockResponse": {
+			"status": 404,
+			"body": {}
+		}
+    }],
+    "expectedMakeBidsErrors": [
+        {
+          "value": "Page not found: 404. Run with request.debug = 1 for more info",
+          "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/adprime/params_test.go b/adapters/adprime/params_test.go
new file mode 100644
index 00000000..05adad5c
--- /dev/null
+++ b/adapters/adprime/params_test.go
@@ -0,0 +1,46 @@
+package adprime
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// TestValidParams makes sure that the adprime schema accepts all imp.ext fields which we intend to support.
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderAdprime, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected adprime params: %s", validParam)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the adprime schema rejects all the imp.ext fields we don't support.
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderAdprime, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"TagID": "1"}`,
+}
+
+var invalidParams = []string{
+	`{"id": "123"}`,
+	`{"tagid": "123"}`,
+	`{"TagID": 16}`,
+}
diff --git a/adapters/smaato/image_test.go b/adapters/smaato/image_test.go
new file mode 100644
index 00000000..5f39c857
--- /dev/null
+++ b/adapters/smaato/image_test.go
@@ -0,0 +1,44 @@
+package smaato
+
+import (
+	"testing"
+)
+
+func TestRenderAdMarkup(t *testing.T) {
+	type args struct {
+		adType             adMarkupType
+		adapterResponseAdm string
+	}
+	expectedResult := `<div style="cursor:pointer"` +
+		` onclick="fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F1'.replace(/\+/g, ' ')),` +
+		` {cache: 'no-cache'});fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F2'.replace(/\+/g, ' ')),` +
+		` {cache: 'no-cache'});;window.open(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fctaurl%2F1'.replace(/\+/g, ' ')));">` +
+		`<img src="//prebid-test.smaatolabs.net/img/320x50.jpg" width="350" height="50"/>` +
+		`<img src="//prebid-test.smaatolabs.net/track/imp/1" alt="" width="0" height="0"/>` +
+		`<img src="//prebid-test.smaatolabs.net/track/imp/2" alt="" width="0" height="0"/></div>`
+
+	tests := []struct {
+		testName string
+		args     args
+		result   string
+	}{
+		{"imageTest", args{"Img",
+			"{\"image\":{\"img\":{\"url\":\"//prebid-test.smaatolabs.net/img/320x50.jpg\"," +
+				"\"w\":350,\"h\":50,\"ctaurl\":\"//prebid-test.smaatolabs.net/track/ctaurl/1\"}," +
+				"\"impressiontrackers\":[\"//prebid-test.smaatolabs.net/track/imp/1\",\"//prebid-test.smaatolabs.net/track/imp/2\"]," +
+				"\"clicktrackers\":[\"//prebid-test.smaatolabs.net/track/click/1\",\"//prebid-test.smaatolabs.net/track/click/2\"]}}"},
+			expectedResult,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.testName, func(t *testing.T) {
+			got, err := renderAdMarkup(tt.args.adType, tt.args.adapterResponseAdm)
+			if err != nil {
+				t.Errorf("error rendering ad markup: %v", err)
+			}
+			if got != tt.result {
+				t.Errorf("renderAdMarkup() got = %v, result %v", got, tt.result)
+			}
+		})
+	}
+}
diff --git a/adapters/smaato/params_test.go b/adapters/smaato/params_test.go
new file mode 100644
index 00000000..6c71cbe7
--- /dev/null
+++ b/adapters/smaato/params_test.go
@@ -0,0 +1,65 @@
+package smaato
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// This file intends to test static/bidder-params/smaato.json
+
+// These also validate the format of the external API: request.imp[i].bidRequestExt.smaato
+
+// TestValidParams makes sure that the Smaato schema accepts all imp.bidRequestExt fields which Smaato supports.
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderSmaato, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected smaato params: %s \n Error: %s", validParam, err)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the Smaato schema rejects all the imp.bidRequestExt fields which are not support.
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderSmaato, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"publisherId":"test-id-1234-smaato","adspaceId": "1123581321"}`,
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`4.2`,
+	`[]`,
+	`{}`,
+	`{"publisherId":"test-id-1234-smaato"}`,
+	`{"adspaceId": "1123581321"}`,
+	`{"publisherId":false}`,
+	`{"adspaceId":false}`,
+	`{"publisherId":0,"adspaceId": 1123581321}`,
+	`{"publisherId":false,"adspaceId": true}`,
+	`{"instl": 0}`,
+	`{"secure": 0}`,
+	`{"adspaceId": "1123581321","instl": 0,"secure": 0}`,
+	`{"instl": 0,"secure": 0}`,
+	`{"publisherId":"test-id-1234-smaato","instl": 0,"secure": 0}`,
+}
diff --git a/adapters/smaato/richmedia_test.go b/adapters/smaato/richmedia_test.go
new file mode 100644
index 00000000..20fa1ba3
--- /dev/null
+++ b/adapters/smaato/richmedia_test.go
@@ -0,0 +1,39 @@
+package smaato
+
+import (
+	"testing"
+)
+
+func TestExtractAdmRichMedia(t *testing.T) {
+	type args struct {
+		adType             adMarkupType
+		adapterResponseAdm string
+	}
+	expectedResult := `<div onclick="fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F1'),` +
+		` {cache: 'no-cache'});fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F2'),` +
+		` {cache: 'no-cache'});"><div>hello</div><img src="//prebid-test.smaatolabs.net/track/imp/1" alt="" width="0" height="0"/>` +
+		`<img src="//prebid-test.smaatolabs.net/track/imp/2" alt="" width="0" height="0"/></div>`
+	tests := []struct {
+		testName string
+		args     args
+		result   string
+	}{
+		{"richmediaTest", args{"Richmedia", "{\"richmedia\":{\"mediadata\":{\"content\":\"<div>hello</div>\"," +
+			"" + "\"w\":350," +
+			"\"h\":50},\"impressiontrackers\":[\"//prebid-test.smaatolabs.net/track/imp/1\",\"//prebid-test.smaatolabs.net/track/imp/2\"]," +
+			"\"clicktrackers\":[\"//prebid-test.smaatolabs.net/track/click/1\",\"//prebid-test.smaatolabs.net/track/click/2\"]}}"},
+			expectedResult,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.testName, func(t *testing.T) {
+			got, err := renderAdMarkup(tt.args.adType, tt.args.adapterResponseAdm)
+			if err != nil {
+				t.Errorf("error rendering ad markup: %v", err)
+			}
+			if got != tt.result {
+				t.Errorf("renderAdMarkup() got = %v, result %v", got, tt.result)
+			}
+		})
+	}
+}
diff --git a/adapters/smaato/smaato_test.go b/adapters/smaato/smaato_test.go
new file mode 100644
index 00000000..cf76d58d
--- /dev/null
+++ b/adapters/smaato/smaato_test.go
@@ -0,0 +1,11 @@
+package smaato
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+)
+
+func TestJsonSamples(t *testing.T) {
+	adapterstest.RunJSONBidderTest(t, "smaatotest", NewSmaatoBidder("https://prebid/bidder"))
+}
diff --git a/adapters/smaato/smaatotest/exemplary/simple-banner-richMedia.json b/adapters/smaato/smaatotest/exemplary/simple-banner-richMedia.json
new file mode 100644
index 00000000..7b662e88
--- /dev/null
+++ b/adapters/smaato/smaatotest/exemplary/simple-banner-richMedia.json
@@ -0,0 +1,194 @@
+{
+  "mockBidRequest": {
+    "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+    "site": {
+      "publisher": {
+        "id": "1100042525"
+      },
+      "page": "http://localhost:3000/server.html?pbjs_debug=true&endpoint=http://localhost:3000/bidder",
+      "ext": {
+        "data": {
+          "keywords": "power tools",
+          "search": "drill",
+          "content": {
+            "userrating": 4
+          }
+        }
+      }
+    },
+    "imp": [
+      {
+        "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 50
+            },
+            {
+              "w": 320,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "1100042525",
+            "adspaceId": "130563103"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "user": {
+      "ext": {
+        "consent": "gdprConsentString",
+        "data": {
+          "keywords": "a,b",
+          "gender": "M",
+          "yob": 1984,
+          "geo": {
+            "country": "ca"
+          }
+        }
+      }
+    },
+    "regs": {
+      "coppa": 1,
+      "ext": {
+        "gdpr": 1,
+        "us_privacy": "uspConsentString"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ]
+        },
+        "uri": "https://prebid/bidder",
+        "body": {
+          "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+          "imp": [
+            {
+              "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+              "tagid": "130563103",
+              "banner": {
+                "h": 50,
+                "w": 320,
+                "format": [
+                  {
+                    "w": 320,
+                    "h": 50
+                  },
+                  {
+                    "w": 320,
+                    "h": 250
+                  }
+                ]
+              }
+            }
+          ],
+          "user": {
+            "gender": "M",
+            "keywords": "a,b",
+            "yob": 1984,
+            "ext": {
+              "consent": "gdprConsentString"
+            }
+          },
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "regs": {
+            "coppa": 1,
+            "ext": {
+              "gdpr": 1,
+              "us_privacy": "uspConsentString"
+            }
+          },
+          "site": {
+            "publisher": {
+              "id": "1100042525"
+            },
+            "page": "http://localhost:3000/server.html?pbjs_debug=true&endpoint=http://localhost:3000/bidder",
+            "keywords": "power tools"
+          },
+          "ext": {
+            "client": "prebid_server_0.1"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "5ebea288-f13a-4754-be6d-4ade66c68877",
+          "seatbid": [
+            {
+              "seat": "CM6523",
+              "bid": [
+                {
+                  "adm": "{\"richmedia\":{\"mediadata\":{\"content\":\"<div>hello</div>\", \"w\":350,\"h\":50},\"impressiontrackers\":[\"//prebid-test.smaatolabs.net/track/imp/1\",\"//prebid-test.smaatolabs.net/track/imp/2\"],\"clicktrackers\":[\"//prebid-test.smaatolabs.net/track/click/1\",\"//prebid-test.smaatolabs.net/track/click/2\"]}}",
+                  "adomain": [
+                    "smaato.com"
+                  ],
+                  "bidderName": "smaato",
+                  "cid": "CM6523",
+                  "crid": "CR69381",
+                  "id": "6906aae8-7f74-4edd-9a4f-f49379a3cadd",
+                  "impid": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+                  "iurl": "https://bidstalkcreatives.s3.amazonaws.com/1x1.png",
+                  "nurl": "https://ets-eu-west-1.track.smaato.net/v1/view?sessionId=e4e17adb-9599-42b1-bb5f-a1f1b3bee572&adSourceId=6906aae8-7f74-4edd-9a4f-f49379a3cadd&originalRequestTime=1552310449698&expires=1552311350698&winurl=ama8JbpJVpFWxvEja5viE3cLXFu58qRI8dGUh23xtsOn3N2-5UU0IwkgNEmR82pI37fcMXejL5IWTNAoW6Cnsjf-Dxl_vx2dUqMrVEevX-Vdx2VVnf-D5f73gZhvi4t36iPL8Dsw4aACekoLvVOV7-eXDjz7GHy60QFqcwKf5g2AlKPOInyZ6vJg_fn4qA9argvCRgwVybXE9Ndm2W0v8La4uFYWpJBOUveDDUrSQfzal7RsYvLb_OyaMlPHdrd_bwA9qqZWuyJXd-L9lxr7RQ%3D%3D%7CMw3kt91KJR0Uy5L-oNztAg%3D%3D&dpid=4XVofb_lH-__hr2JNGhKfg%3D%3D%7Cr9ciCU1cx3zmHXihItKO0g%3D%3D",
+                  "price": 0.01,
+                  "w": 350,
+                  "h": 50
+                }
+              ]
+            }
+          ],
+          "bidid": "04db8629-179d-4bcd-acce-e54722969006",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "adm": "<div onclick=\"fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F1'), {cache: 'no-cache'});fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F2'), {cache: 'no-cache'});\"><div>hello</div><img src=\"//prebid-test.smaatolabs.net/track/imp/1\" alt=\"\" width=\"0\" height=\"0\"/><img src=\"//prebid-test.smaatolabs.net/track/imp/2\" alt=\"\" width=\"0\" height=\"0\"/></div>",
+            "adomain": [
+              "smaato.com"
+            ],
+            "cid": "CM6523",
+            "crid": "CR69381",
+            "id": "6906aae8-7f74-4edd-9a4f-f49379a3cadd",
+            "impid": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+            "iurl": "https://bidstalkcreatives.s3.amazonaws.com/1x1.png",
+            "nurl": "https://ets-eu-west-1.track.smaato.net/v1/view?sessionId=e4e17adb-9599-42b1-bb5f-a1f1b3bee572&adSourceId=6906aae8-7f74-4edd-9a4f-f49379a3cadd&originalRequestTime=1552310449698&expires=1552311350698&winurl=ama8JbpJVpFWxvEja5viE3cLXFu58qRI8dGUh23xtsOn3N2-5UU0IwkgNEmR82pI37fcMXejL5IWTNAoW6Cnsjf-Dxl_vx2dUqMrVEevX-Vdx2VVnf-D5f73gZhvi4t36iPL8Dsw4aACekoLvVOV7-eXDjz7GHy60QFqcwKf5g2AlKPOInyZ6vJg_fn4qA9argvCRgwVybXE9Ndm2W0v8La4uFYWpJBOUveDDUrSQfzal7RsYvLb_OyaMlPHdrd_bwA9qqZWuyJXd-L9lxr7RQ%3D%3D%7CMw3kt91KJR0Uy5L-oNztAg%3D%3D&dpid=4XVofb_lH-__hr2JNGhKfg%3D%3D%7Cr9ciCU1cx3zmHXihItKO0g%3D%3D",
+            "price": 0.01,
+            "w": 350,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/smaato/smaatotest/exemplary/simple-banner.json b/adapters/smaato/smaatotest/exemplary/simple-banner.json
new file mode 100644
index 00000000..a50fd928
--- /dev/null
+++ b/adapters/smaato/smaatotest/exemplary/simple-banner.json
@@ -0,0 +1,190 @@
+{
+  "mockBidRequest": {
+    "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+    "site": {
+      "publisher": {
+        "id": "1100042525"
+      },
+      "page": "http://localhost:3000/server.html?pbjs_debug=true&endpoint=http://localhost:3000/bidder",
+      "ext": {
+        "data": {
+          "keywords": "power tools",
+          "search": "drill",
+          "content": {
+            "userrating": 4
+          }
+        }
+      }
+    },
+    "imp": [
+      {
+        "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 50
+            },
+            {
+              "w": 320,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "1100042525",
+            "adspaceId": "130563103"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "user": {
+      "ext": {
+        "consent": "gdprConsentString",
+        "data": {
+          "keywords": "a,b",
+          "gender": "M",
+          "yob": 1984,
+          "geo": {
+            "country": "ca"
+          }
+        }
+      }
+    },
+    "regs": {
+      "coppa": 1,
+      "ext": {
+        "gdpr": 1,
+        "us_privacy": "uspConsentString"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": ["application/json;charset=utf-8"],
+          "Accept": ["application/json"]
+        },
+        "uri": "https://prebid/bidder",
+        "body": {
+          "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+          "imp": [
+            {
+              "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+              "tagid": "130563103",
+              "banner": {
+                "h": 50,
+                "w": 320,
+                "format": [
+                  {
+                    "w": 320,
+                    "h": 50
+                  },
+                  {
+                    "w": 320,
+                    "h": 250
+                  }
+                ]
+              }
+            }
+          ],
+          "user": {
+            "ext": {
+              "consent": "gdprConsentString"
+            },
+            "gender": "M",
+            "keywords": "a,b",
+            "yob": 1984
+          },
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "regs": {
+            "coppa": 1,
+            "ext": {
+              "gdpr": 1,
+              "us_privacy": "uspConsentString"
+            }
+          },
+          "site": {
+            "publisher": {
+              "id": "1100042525"
+            },
+            "page": "http://localhost:3000/server.html?pbjs_debug=true&endpoint=http://localhost:3000/bidder",
+            "keywords": "power tools"
+          },
+          "ext": {
+            "client": "prebid_server_0.1"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "5ebea288-f13a-4754-be6d-4ade66c68877",
+          "seatbid": [
+            {
+              "seat": "CM6523",
+              "bid": [
+                {
+                  "adm": "{\"image\":{\"img\":{\"url\":\"//prebid-test.smaatolabs.net/img/320x50.jpg\",\"w\":350,\"h\":50,\"ctaurl\":\"//prebid-test.smaatolabs.net/track/ctaurl/1\"},\"impressiontrackers\":[\"//prebid-test.smaatolabs.net/track/imp/1\",\"//prebid-test.smaatolabs.net/track/imp/2\"],\"clicktrackers\":[\"//prebid-test.smaatolabs.net/track/click/1\",\"//prebid-test.smaatolabs.net/track/click/2\"]}}",
+                  "adomain": [
+                    "smaato.com"
+                  ],
+                  "bidderName": "smaato",
+                  "cid": "CM6523",
+                  "crid": "CR69381",
+                  "id": "6906aae8-7f74-4edd-9a4f-f49379a3cadd",
+                  "impid": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+                  "iurl": "https://bidstalkcreatives.s3.amazonaws.com/1x1.png",
+                  "nurl": "https://ets-eu-west-1.track.smaato.net/v1/view?sessionId=e4e17adb-9599-42b1-bb5f-a1f1b3bee572&adSourceId=6906aae8-7f74-4edd-9a4f-f49379a3cadd&originalRequestTime=1552310449698&expires=1552311350698&winurl=ama8JbpJVpFWxvEja5viE3cLXFu58qRI8dGUh23xtsOn3N2-5UU0IwkgNEmR82pI37fcMXejL5IWTNAoW6Cnsjf-Dxl_vx2dUqMrVEevX-Vdx2VVnf-D5f73gZhvi4t36iPL8Dsw4aACekoLvVOV7-eXDjz7GHy60QFqcwKf5g2AlKPOInyZ6vJg_fn4qA9argvCRgwVybXE9Ndm2W0v8La4uFYWpJBOUveDDUrSQfzal7RsYvLb_OyaMlPHdrd_bwA9qqZWuyJXd-L9lxr7RQ%3D%3D%7CMw3kt91KJR0Uy5L-oNztAg%3D%3D&dpid=4XVofb_lH-__hr2JNGhKfg%3D%3D%7Cr9ciCU1cx3zmHXihItKO0g%3D%3D",
+                  "price": 0.01,
+                  "w": 350,
+                  "h": 50
+                }
+              ]
+            }
+          ],
+          "bidid": "04db8629-179d-4bcd-acce-e54722969006",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "adm": "<div style=\"cursor:pointer\" onclick=\"fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F1'.replace(/\\+/g, ' ')), {cache: 'no-cache'});fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F2'.replace(/\\+/g, ' ')), {cache: 'no-cache'});;window.open(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fctaurl%2F1'.replace(/\\+/g, ' ')));\"><img src=\"//prebid-test.smaatolabs.net/img/320x50.jpg\" width=\"350\" height=\"50\"/><img src=\"//prebid-test.smaatolabs.net/track/imp/1\" alt=\"\" width=\"0\" height=\"0\"/><img src=\"//prebid-test.smaatolabs.net/track/imp/2\" alt=\"\" width=\"0\" height=\"0\"/></div>",
+            "adomain": [
+              "smaato.com"
+            ],
+            "cid": "CM6523",
+            "crid": "CR69381",
+            "id": "6906aae8-7f74-4edd-9a4f-f49379a3cadd",
+            "impid": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+            "iurl": "https://bidstalkcreatives.s3.amazonaws.com/1x1.png",
+            "nurl": "https://ets-eu-west-1.track.smaato.net/v1/view?sessionId=e4e17adb-9599-42b1-bb5f-a1f1b3bee572&adSourceId=6906aae8-7f74-4edd-9a4f-f49379a3cadd&originalRequestTime=1552310449698&expires=1552311350698&winurl=ama8JbpJVpFWxvEja5viE3cLXFu58qRI8dGUh23xtsOn3N2-5UU0IwkgNEmR82pI37fcMXejL5IWTNAoW6Cnsjf-Dxl_vx2dUqMrVEevX-Vdx2VVnf-D5f73gZhvi4t36iPL8Dsw4aACekoLvVOV7-eXDjz7GHy60QFqcwKf5g2AlKPOInyZ6vJg_fn4qA9argvCRgwVybXE9Ndm2W0v8La4uFYWpJBOUveDDUrSQfzal7RsYvLb_OyaMlPHdrd_bwA9qqZWuyJXd-L9lxr7RQ%3D%3D%7CMw3kt91KJR0Uy5L-oNztAg%3D%3D&dpid=4XVofb_lH-__hr2JNGhKfg%3D%3D%7Cr9ciCU1cx3zmHXihItKO0g%3D%3D",
+            "price": 0.01,
+            "w": 350,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/smaato/smaatotest/params/banner.json b/adapters/smaato/smaatotest/params/banner.json
new file mode 100644
index 00000000..a84c44d4
--- /dev/null
+++ b/adapters/smaato/smaatotest/params/banner.json
@@ -0,0 +1,4 @@
+{
+  "publisherId": "1100042525",
+  "adspaceId": "130563103"
+}
\ No newline at end of file
diff --git a/adapters/smaato/smaatotest/supplemental/bad-adm-response.json b/adapters/smaato/smaatotest/supplemental/bad-adm-response.json
new file mode 100644
index 00000000..6d4990e9
--- /dev/null
+++ b/adapters/smaato/smaatotest/supplemental/bad-adm-response.json
@@ -0,0 +1,166 @@
+{
+  "mockBidRequest": {
+    "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+    "site": {
+      "publisher": {
+        "id": "1100042525"
+      },
+      "page": "http://localhost:3000/server.html?pbjs_debug=true&endpoint=http://localhost:3000/bidder",
+      "ext": {
+        "data": {
+          "keywords": "power tools",
+          "search": "drill",
+          "content": {
+            "userrating": 4
+          }
+        }
+      }
+    },
+    "imp": [
+      {
+        "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 50
+            },
+            {
+              "w": 320,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "1100042525",
+            "adspaceId": "130563103"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "user": {
+      "ext": {
+        "consent": "gdprConsentString",
+        "data": {
+          "keywords": "a,b",
+          "gender": "M",
+          "yob": 1984,
+          "geo": {
+            "country": "ca"
+          }
+        }
+      }
+    },
+    "regs": {
+      "coppa": 1,
+      "ext": {
+        "gdpr": 1,
+        "us_privacy": "uspConsentString"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": ["application/json;charset=utf-8"],
+          "Accept": ["application/json"]
+        },
+        "uri": "https://prebid/bidder",
+        "body": {
+          "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+          "imp": [
+            {
+              "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+              "tagid": "130563103",
+              "banner": {
+                "h": 50,
+                "w": 320,
+                "format": [
+                  {
+                    "w": 320,
+                    "h": 50
+                  },
+                  {
+                    "w": 320,
+                    "h": 250
+                  }
+                ]
+              }
+            }
+          ],
+          "user": {
+            "ext": {
+              "consent": "gdprConsentString"
+            },
+            "gender": "M",
+            "keywords": "a,b",
+            "yob": 1984
+          },
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "regs": {
+            "coppa": 1,
+            "ext": {
+              "gdpr": 1,
+              "us_privacy": "uspConsentString"
+            }
+          },
+          "site": {
+            "publisher": {
+              "id": "1100042525"
+            },
+            "page": "http://localhost:3000/server.html?pbjs_debug=true&endpoint=http://localhost:3000/bidder",
+            "keywords": "power tools"
+          },
+          "ext": {
+            "client": "prebid_server_0.1"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "5ebea288-f13a-4754-be6d-4ade66c68877",
+          "seatbid": [
+            {
+              "seat": "CM6523",
+              "bid": [
+                {
+                  "adm": "{\"badmedia\":{\"mediadata\":{\"content\":\"<div>hello</div>\", \"w\":350,\"h\":50},\"impressiontrackers\":[\"//prebid-test.smaatolabs.net/track/imp/1\",\"//prebid-test.smaatolabs.net/track/imp/2\"],\"clicktrackers\":[\"//prebid-test.smaatolabs.net/track/click/1\",\"//prebid-test.smaatolabs.net/track/click/2\"]}}",
+                  "adomain": [
+                    "smaato.com"
+                  ],
+                  "bidderName": "smaato",
+                  "cid": "CM6523",
+                  "crid": "CR69381",
+                  "id": "6906aae8-7f74-4edd-9a4f-f49379a3cadd",
+                  "impid": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+                  "iurl": "https://bidstalkcreatives.s3.amazonaws.com/1x1.png",
+                  "nurl": "https://ets-eu-west-1.track.smaato.net/v1/view?sessionId=e4e17adb-9599-42b1-bb5f-a1f1b3bee572&adSourceId=6906aae8-7f74-4edd-9a4f-f49379a3cadd&originalRequestTime=1552310449698&expires=1552311350698&winurl=ama8JbpJVpFWxvEja5viE3cLXFu58qRI8dGUh23xtsOn3N2-5UU0IwkgNEmR82pI37fcMXejL5IWTNAoW6Cnsjf-Dxl_vx2dUqMrVEevX-Vdx2VVnf-D5f73gZhvi4t36iPL8Dsw4aACekoLvVOV7-eXDjz7GHy60QFqcwKf5g2AlKPOInyZ6vJg_fn4qA9argvCRgwVybXE9Ndm2W0v8La4uFYWpJBOUveDDUrSQfzal7RsYvLb_OyaMlPHdrd_bwA9qqZWuyJXd-L9lxr7RQ%3D%3D%7CMw3kt91KJR0Uy5L-oNztAg%3D%3D&dpid=4XVofb_lH-__hr2JNGhKfg%3D%3D%7Cr9ciCU1cx3zmHXihItKO0g%3D%3D",
+                  "price": 0.01,
+                  "w": 350,
+                  "h": 50
+                }
+              ]
+            }
+          ],
+          "bidid": "04db8629-179d-4bcd-acce-e54722969006",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/smaato/smaatotest/supplemental/bad-ext-req.json b/adapters/smaato/smaatotest/supplemental/bad-ext-req.json
new file mode 100644
index 00000000..0c970fc5
--- /dev/null
+++ b/adapters/smaato/smaatotest/supplemental/bad-ext-req.json
@@ -0,0 +1,54 @@
+{
+  "mockBidRequest": {
+    "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+    "site": {
+      "page": "prebid.org",
+      "publisher": {
+        "id": "1"
+      }
+    },
+    "imp": [
+      {
+        "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 50
+            },
+            {
+              "w": 320,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+        }
+      }
+    ],
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "user": {
+      "ext": {
+        "consent": "gdprConsentString"
+      }
+    },
+    "regs": {
+      "coppa": 1,
+      "ext": {
+        "gdpr": 1,
+        "us_privacy": "uspConsentString"
+      }
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Key path not found",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/smaato/smaatotest/supplemental/bad-imp-banner-format-req.json b/adapters/smaato/smaatotest/supplemental/bad-imp-banner-format-req.json
new file mode 100644
index 00000000..b9560f0f
--- /dev/null
+++ b/adapters/smaato/smaatotest/supplemental/bad-imp-banner-format-req.json
@@ -0,0 +1,61 @@
+{
+  "mockBidRequest": {
+    "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+    "imp": [
+      {
+        "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+        "banner": {
+          "format": []
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "1100042525",
+            "adspaceId": "130563103"
+          }
+        }
+      }
+    ],
+    "site": {
+      "page": "prebid.org",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": ["application/json;charset=utf-8"],
+          "Accept": ["application/json"]
+        },
+        "uri": "https://prebid/bidder",
+        "body": {
+          "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+          "imp": [],
+          "site": {
+            "page": "prebid.org",
+            "publisher": {
+              "id": "1100042525"
+            }
+          },
+          "ext": {
+            "client": "prebid_server_0.1"
+          }
+        }
+      }
+    }
+  ],
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "No sizes provided for Banner []",
+      "comparison": "literal"
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "unexpected status code: 0. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/smaato/smaatotest/supplemental/bad-user-ext-data-req.json b/adapters/smaato/smaatotest/supplemental/bad-user-ext-data-req.json
new file mode 100644
index 00000000..9e65fce1
--- /dev/null
+++ b/adapters/smaato/smaatotest/supplemental/bad-user-ext-data-req.json
@@ -0,0 +1,67 @@
+{
+  "mockBidRequest": {
+    "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+    "site": {
+      "page": "prebid.org",
+      "publisher": {
+        "id": "1"
+      }
+    },
+    "imp": [
+      {
+        "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 50
+            },
+            {
+              "w": 320,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "1100042525",
+            "adspaceId": "130563103"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "user": {
+      "gender": "M",
+      "ext": {
+        "data": {
+          "keywords":"a,b",
+          "gender": "M",
+          "yob": "",
+          "geo": {
+            "country": "ca"
+          }
+        },
+        "consent":"yes"
+      }
+    },
+    "regs": {
+      "coppa": 1,
+      "ext": {
+        "gdpr": 1,
+        "us_privacy": "uspConsentString"
+      }
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "json: cannot unmarshal string into Go struct field userExtData.data.yob of type int64",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/smaato/smaatotest/supplemental/bad-user-ext-req.json b/adapters/smaato/smaatotest/supplemental/bad-user-ext-req.json
new file mode 100644
index 00000000..7f05b2df
--- /dev/null
+++ b/adapters/smaato/smaatotest/supplemental/bad-user-ext-req.json
@@ -0,0 +1,57 @@
+{
+  "mockBidRequest": {
+    "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+    "site": {
+      "page": "prebid.org",
+      "publisher": {
+        "id": "1"
+      }
+    },
+    "imp": [
+      {
+        "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 50
+            },
+            {
+              "w": 320,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "1100042525",
+            "adspaceId": "130563103"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "user": {
+      "gender": "M",
+      "ext": 99
+    },
+    "regs": {
+      "coppa": 1,
+      "ext": {
+        "gdpr": 1,
+        "us_privacy": "uspConsentString"
+      }
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "json: cannot unmarshal number into Go value of type map[string]json.RawMessage",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/smaato/smaatotest/supplemental/no-consent-info.json b/adapters/smaato/smaatotest/supplemental/no-consent-info.json
new file mode 100644
index 00000000..9e0ccfdc
--- /dev/null
+++ b/adapters/smaato/smaatotest/supplemental/no-consent-info.json
@@ -0,0 +1,137 @@
+{
+  "mockBidRequest": {
+    "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+    "site": {
+      "page": "prebid.org",
+      "publisher": {
+        "id": "1"
+      }
+    },
+    "imp": [
+      {
+        "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+        "banner": {
+          "format": [
+            {
+              "w": 320,
+              "h": 50
+            },
+            {
+              "w": 320,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "1100042525",
+            "adspaceId": "130563103"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ]
+        },
+        "uri": "https://prebid/bidder",
+        "body": {
+          "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+          "imp": [
+            {
+              "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+              "tagid": "130563103",
+              "banner": {
+                "h": 50,
+                "w": 320,
+                "format": [
+                  {
+                    "w": 320,
+                    "h": 50
+                  },
+                  {
+                    "w": 320,
+                    "h": 250
+                  }
+                ]
+              }
+            }
+          ],
+          "site": {
+            "page": "prebid.org",
+            "publisher": {
+              "id": "1100042525"
+            }
+          },
+          "ext": {
+            "client": "prebid_server_0.1"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "5ebea288-f13a-4754-be6d-4ade66c68877",
+          "seatbid": [
+            {
+              "seat": "CM6523",
+              "bid": [
+                {
+                  "adm": "{\"image\":{\"img\":{\"url\":\"//prebid-test.smaatolabs.net/img/320x50.jpg\",\"w\":350,\"h\":50,\"ctaurl\":\"//prebid-test.smaatolabs.net/track/ctaurl/1\"},\"impressiontrackers\":[\"//prebid-test.smaatolabs.net/track/imp/1\",\"//prebid-test.smaatolabs.net/track/imp/2\"],\"clicktrackers\":[\"//prebid-test.smaatolabs.net/track/click/1\",\"//prebid-test.smaatolabs.net/track/click/2\"]}}",
+                  "adomain": [
+                    "smaato.com"
+                  ],
+                  "bidderName": "smaato",
+                  "cid": "CM6523",
+                  "crid": "CR69381",
+                  "id": "6906aae8-7f74-4edd-9a4f-f49379a3cadd",
+                  "impid": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+                  "iurl": "https://bidstalkcreatives.s3.amazonaws.com/1x1.png",
+                  "nurl": "https://ets-eu-west-1.track.smaato.net/v1/view?sessionId=e4e17adb-9599-42b1-bb5f-a1f1b3bee572&adSourceId=6906aae8-7f74-4edd-9a4f-f49379a3cadd&originalRequestTime=1552310449698&expires=1552311350698&winurl=ama8JbpJVpFWxvEja5viE3cLXFu58qRI8dGUh23xtsOn3N2-5UU0IwkgNEmR82pI37fcMXejL5IWTNAoW6Cnsjf-Dxl_vx2dUqMrVEevX-Vdx2VVnf-D5f73gZhvi4t36iPL8Dsw4aACekoLvVOV7-eXDjz7GHy60QFqcwKf5g2AlKPOInyZ6vJg_fn4qA9argvCRgwVybXE9Ndm2W0v8La4uFYWpJBOUveDDUrSQfzal7RsYvLb_OyaMlPHdrd_bwA9qqZWuyJXd-L9lxr7RQ%3D%3D%7CMw3kt91KJR0Uy5L-oNztAg%3D%3D&dpid=4XVofb_lH-__hr2JNGhKfg%3D%3D%7Cr9ciCU1cx3zmHXihItKO0g%3D%3D",
+                  "price": 0.01,
+                  "w": 350,
+                  "h": 50
+                }
+              ]
+            }
+          ],
+          "bidid": "04db8629-179d-4bcd-acce-e54722969006",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "adm": "<div style=\"cursor:pointer\" onclick=\"fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F1'.replace(/\\+/g, ' ')), {cache: 'no-cache'});fetch(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fclick%2F2'.replace(/\\+/g, ' ')), {cache: 'no-cache'});;window.open(decodeURIComponent('%2F%2Fprebid-test.smaatolabs.net%2Ftrack%2Fctaurl%2F1'.replace(/\\+/g, ' ')));\"><img src=\"//prebid-test.smaatolabs.net/img/320x50.jpg\" width=\"350\" height=\"50\"/><img src=\"//prebid-test.smaatolabs.net/track/imp/1\" alt=\"\" width=\"0\" height=\"0\"/><img src=\"//prebid-test.smaatolabs.net/track/imp/2\" alt=\"\" width=\"0\" height=\"0\"/></div>",
+            "adomain": [
+              "smaato.com"
+            ],
+            "cid": "CM6523",
+            "crid": "CR69381",
+            "id": "6906aae8-7f74-4edd-9a4f-f49379a3cadd",
+            "impid": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+            "iurl": "https://bidstalkcreatives.s3.amazonaws.com/1x1.png",
+            "nurl": "https://ets-eu-west-1.track.smaato.net/v1/view?sessionId=e4e17adb-9599-42b1-bb5f-a1f1b3bee572&adSourceId=6906aae8-7f74-4edd-9a4f-f49379a3cadd&originalRequestTime=1552310449698&expires=1552311350698&winurl=ama8JbpJVpFWxvEja5viE3cLXFu58qRI8dGUh23xtsOn3N2-5UU0IwkgNEmR82pI37fcMXejL5IWTNAoW6Cnsjf-Dxl_vx2dUqMrVEevX-Vdx2VVnf-D5f73gZhvi4t36iPL8Dsw4aACekoLvVOV7-eXDjz7GHy60QFqcwKf5g2AlKPOInyZ6vJg_fn4qA9argvCRgwVybXE9Ndm2W0v8La4uFYWpJBOUveDDUrSQfzal7RsYvLb_OyaMlPHdrd_bwA9qqZWuyJXd-L9lxr7RQ%3D%3D%7CMw3kt91KJR0Uy5L-oNztAg%3D%3D&dpid=4XVofb_lH-__hr2JNGhKfg%3D%3D%7Cr9ciCU1cx3zmHXihItKO0g%3D%3D",
+            "price": 0.01,
+            "w": 350,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/smaato/smaatotest/supplemental/no-imp-req.json b/adapters/smaato/smaatotest/supplemental/no-imp-req.json
new file mode 100644
index 00000000..bfaf51e6
--- /dev/null
+++ b/adapters/smaato/smaatotest/supplemental/no-imp-req.json
@@ -0,0 +1,17 @@
+{
+  "mockBidRequest": {
+    "id": "1C86242D-9535-47D6-9576-7B1FE87F282C",
+    "site": {
+      "page": "prebid.org",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "no impressions in bid request",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go
index 1a27b72a..7ae96c09 100644
--- a/exchange/bidder_test.go
+++ b/exchange/bidder_test.go
@@ -938,54 +938,6 @@ func TestSuccessfulResponseLogging(t *testing.T) {
 	}
 }
 
-// TestServerCallDebugging makes sure that we log the server calls made by the Bidder on test bids.
-func TestServerCallDebugging(t *testing.T) {
-	respBody := "{\"bid\":false}"
-	respStatus := 200
-	server := httptest.NewServer(mockHandler(respStatus, "getBody", respBody))
-	defer server.Close()
-
-	reqBody := "{\"key\":\"val\"}"
-	reqUrl := server.URL
-	bidderImpl := &goodSingleBidder{
-		httpRequest: &adapters.RequestData{
-			Method:  "POST",
-			Uri:     reqUrl,
-			Body:    []byte(reqBody),
-			Headers: http.Header{},
-		},
-	}
-	bidder := adaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderAppnexus)
-	currencyConverter := currencies.NewRateConverterDefault()
-
-	bids, _ := bidder.requestBid(
-		context.Background(),
-		&openrtb.BidRequest{
-			Test: 1,
-		},
-		"test",
-		1.0,
-		currencyConverter.Rates(),
-		&adapters.ExtraRequestInfo{},
-	)
-
-	if len(bids.httpCalls) != 1 {
-		t.Errorf("We should log the server call if this is a test bid. Got %d", len(bids.httpCalls))
-	}
-	if bids.httpCalls[0].Uri != reqUrl {
-		t.Errorf("Wrong httpcalls URI. Expected %s, got %s", reqUrl, bids.httpCalls[0].Uri)
-	}
-	if bids.httpCalls[0].RequestBody != reqBody {
-		t.Errorf("Wrong httpcalls RequestBody. Expected %s, got %s", reqBody, bids.httpCalls[0].RequestBody)
-	}
-	if bids.httpCalls[0].ResponseBody != respBody {
-		t.Errorf("Wrong httpcalls ResponseBody. Expected %s, got %s", respBody, bids.httpCalls[0].ResponseBody)
-	}
-	if bids.httpCalls[0].Status != respStatus {
-		t.Errorf("Wrong httpcalls Status. Expected %d, got %d", respStatus, bids.httpCalls[0].Status)
-	}
-}
-
 func TestMobileNativeTypes(t *testing.T) {
 	respBody := "{\"bid\":false}"
 	respStatus := 200
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 96f740de..7da7b62e 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -22,6 +22,7 @@ import (
 	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/prebid/prebid-server/pbsmetrics"
 	metricsConf "github.com/prebid/prebid-server/pbsmetrics/config"
+	metricsConfig "github.com/prebid/prebid-server/pbsmetrics/config"
 	pbc "github.com/prebid/prebid-server/prebid_cache_client"
 	"github.com/prebid/prebid-server/stored_requests"
 	"github.com/prebid/prebid-server/stored_requests/backends/file_fetcher"
@@ -112,9 +113,6 @@ func TestCharacterEscape(t *testing.T) {
 		Ext:    json.RawMessage(`{"id": "some-request-id","site": {"page": "prebid.org"},"imp": [{"id": "some-impression-id","banner": {"format": [{"w": 300,"h": 250},{"w": 300,"h": 600}]},"ext": {"appnexus": {"placementId": 1}}}],"tmax": 500}`),
 	}
 
-	//resolvedRequest json.RawMessage
-	resolvedRequest := json.RawMessage(`{"id": "some-request-id","site": {"page": "prebid.org"},"imp": [{"id": "some-impression-id","banner": {"format": [{"w": 300,"h": 250},{"w": 300,"h": 600}]},"ext": {"appnexus": {"placementId": 1}}}],"tmax": 500}`)
-
 	//adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra,
 	adapterExtra := make(map[openrtb_ext.BidderName]*seatResponseExtra, 1)
 	adapterExtra["appnexus"] = &seatResponseExtra{
@@ -126,7 +124,7 @@ func TestCharacterEscape(t *testing.T) {
 	var errList []error
 
 	/* 	4) Build bid response 									*/
-	bidResp, err := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, resolvedRequest, adapterExtra, nil, nil, errList)
+	bidResp, err := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, nil, nil, errList)
 
 	/* 	5) Assert we have no errors and one '&' character as we are supposed to 	*/
 	if err != nil {
@@ -140,6 +138,137 @@ func TestCharacterEscape(t *testing.T) {
 	}
 }
 
+// TestDebugBehaviour asserts the HttpCalls object is included inside the json "debug" field of the bidResponse extension when the
+// openrtb.BidRequest "Test" value is set to 1 or the openrtb.BidRequest.Ext.Debug boolean field is set to true
+func TestDebugBehaviour(t *testing.T) {
+
+	// Define test cases
+	type inTest struct {
+		test  int8
+		debug bool
+	}
+	type outTest struct {
+		debugInfoIncluded bool
+	}
+	type aTest struct {
+		desc string
+		in   inTest
+		out  outTest
+	}
+	testCases := []aTest{
+		{
+			desc: "test flag equals zero, ext debug flag false, no debug info expected",
+			in:   inTest{test: 0, debug: false},
+			out:  outTest{debugInfoIncluded: false},
+		},
+		{
+			desc: "test flag equals zero, ext debug flag true, debug info expected",
+			in:   inTest{test: 0, debug: true},
+			out:  outTest{debugInfoIncluded: true},
+		},
+		{
+			desc: "test flag equals 1, ext debug flag false, debug info expected",
+			in:   inTest{test: 1, debug: false},
+			out:  outTest{debugInfoIncluded: true},
+		},
+		{
+			desc: "test flag equals 1, ext debug flag true, debug info expected",
+			in:   inTest{test: 1, debug: true},
+			out:  outTest{debugInfoIncluded: true},
+		},
+		{
+			desc: "test flag not equal to 0 nor 1, ext debug flag false, no debug info expected",
+			in:   inTest{test: 2, debug: false},
+			out:  outTest{debugInfoIncluded: false},
+		},
+		{
+			desc: "test flag not equal to 0 nor 1, ext debug flag true, debug info expected",
+			in:   inTest{test: -1, debug: true},
+			out:  outTest{debugInfoIncluded: true},
+		},
+	}
+
+	// Set up test
+	noBidServer := func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(204)
+	}
+	server := httptest.NewServer(http.HandlerFunc(noBidServer))
+	defer server.Close()
+
+	categoriesFetcher, error := newCategoryFetcher("./test/category-mapping")
+	if error != nil {
+		t.Errorf("Failed to create a category Fetcher: %v", error)
+	}
+
+	bidRequest := &openrtb.BidRequest{
+		ID: "some-request-id",
+		Imp: []openrtb.Imp{{
+			ID:     "some-impression-id",
+			Banner: &openrtb.Banner{Format: []openrtb.Format{{W: 300, H: 250}, {W: 300, H: 600}}},
+			Ext:    json.RawMessage(`{"appnexus": {"placementId": 1}}`),
+		}},
+		Site:   &openrtb.Site{Page: "prebid.org", Ext: json.RawMessage(`{"amp":0}`)},
+		Device: &openrtb.Device{UA: "curl/7.54.0", IP: "::1"},
+		AT:     1,
+		TMax:   500,
+	}
+
+	bidderImpl := &goodSingleBidder{
+		httpRequest: &adapters.RequestData{
+			Method:  "POST",
+			Uri:     server.URL,
+			Body:    []byte("{\"key\":\"val\"}"),
+			Headers: http.Header{},
+		},
+		bidResponse: &adapters.BidderResponse{},
+	}
+
+	e := new(exchange)
+	e.adapterMap = map[openrtb_ext.BidderName]adaptedBidder{
+		openrtb_ext.BidderAppnexus: adaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderAppnexus),
+	}
+	e.cache = &wellBehavedCache{}
+	e.me = &metricsConf.DummyMetricsEngine{}
+	e.gDPR = gdpr.AlwaysAllow{}
+	e.currencyConverter = currencies.NewRateConverterDefault()
+
+	// Run tests
+	for _, test := range testCases {
+		bidRequest.Test = test.in.test
+
+		if test.in.debug {
+			bidRequest.Ext = json.RawMessage(`{"prebid":{"debug":true}}`)
+		} else {
+			bidRequest.Ext = nil
+		}
+
+		// Run test
+		outBidResponse, err := e.HoldAuction(context.Background(), bidRequest, &emptyUsersync{}, pbsmetrics.Labels{}, &categoriesFetcher, nil)
+
+		// Assert no HoldAuction error
+		assert.NoErrorf(t, err, "%s. ex.HoldAuction returned an error: %v \n", test.desc, err)
+		assert.NotNilf(t, outBidResponse.Ext, "%s. outBidResponse.Ext should not be nil \n", test.desc)
+
+		actualExt := &openrtb_ext.ExtBidResponse{}
+		err = json.Unmarshal(outBidResponse.Ext, actualExt)
+		assert.NoErrorf(t, err, "%s. \"ext\" JSON field could not be unmarshaled. err: \"%v\" \n outBidResponse.Ext: \"%s\" \n", test.desc, err, outBidResponse.Ext)
+
+		if test.out.debugInfoIncluded {
+			assert.NotNilf(t, actualExt, "%s. ext.debug field is expected to be included in this outBidResponse.Ext and not be nil.  outBidResponse.Ext.Debug = %v \n", test.desc, actualExt.Debug)
+
+			// Assert "Debug fields
+			assert.Greater(t, len(actualExt.Debug.HttpCalls), 0, "%s. ext.debug.httpcalls array should not be empty\n", test.desc)
+			assert.Equal(t, server.URL, actualExt.Debug.HttpCalls["appnexus"][0].Uri, "%s. ext.debug.httpcalls array should not be empty\n", test.desc)
+			assert.NotNilf(t, actualExt.Debug.ResolvedRequest, "%s. ext.debug.resolvedrequest field is expected to be included in this outBidResponse.Ext and not be nil.  outBidResponse.Ext.Debug = %v \n", test.desc, actualExt.Debug)
+
+			// If not nil, assert bid extension
+			if test.in.debug {
+				diffJson(t, test.desc, bidRequest.Ext, actualExt.Debug.ResolvedRequest.Ext)
+			}
+		}
+	}
+}
+
 func TestGetBidCacheInfo(t *testing.T) {
 	testUUID := "CACHE_UUID_1234"
 	testExternalCacheHost := "https://www.externalprebidcache.net"
@@ -230,9 +359,6 @@ func TestGetBidCacheInfo(t *testing.T) {
 		},
 	}
 
-	//resolvedRequest json.RawMessage
-	resolvedRequest := json.RawMessage(`{"id": "some-request-id","site": {"page": "prebid.org"},"imp": [{"id": "some-impression-id","banner": {"format": [{"w": 300,"h": 250},{"w": 300,"h": 600}]},"ext": {"appnexus": {"placementId": 1}}}],"tmax": 500}`)
-
 	//adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra,
 	adapterExtra := map[openrtb_ext.BidderName]*seatResponseExtra{
 		bidderName: {
@@ -278,7 +404,7 @@ func TestGetBidCacheInfo(t *testing.T) {
 	var errList []error
 
 	/* 	4) Build bid response 									*/
-	bid_resp, err := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, resolvedRequest, adapterExtra, auc, nil, errList)
+	bid_resp, err := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, auc, nil, errList)
 
 	/* 	5) Assert we have no errors and the bid response we expected*/
 	assert.NoError(t, err, "[TestGetBidCacheInfo] buildBidResponse() threw an error")
@@ -342,8 +468,6 @@ func TestBidResponseCurrency(t *testing.T) {
 		Ext:    json.RawMessage(`{"id": "some-request-id","site": {"page": "prebid.org"},"imp": [{"id": "some-impression-id","banner": {"format": [{"w": 300,"h": 250},{"w": 300,"h": 600}]},"ext": {"appnexus": {"placementId": 10433394}}}],"tmax": 500}`),
 	}
 
-	resolvedRequest := json.RawMessage(`{"id": "some-request-id","site": {"page": "prebid.org"},"imp": [{"id": "some-impression-id","banner": {"format": [{"w": 300,"h": 250},{"w": 300,"h": 600}]},"ext": {"appnexus": {"placementId": 1}}}],"tmax": 500}`)
-
 	adapterExtra := map[openrtb_ext.BidderName]*seatResponseExtra{
 		"appnexus": {ResponseTimeMillis: 5},
 	}
@@ -449,7 +573,7 @@ func TestBidResponseCurrency(t *testing.T) {
 
 	// Run tests
 	for i := range testCases {
-		actualBidResp, err := e.buildBidResponse(context.Background(), liveAdapters, testCases[i].adapterBids, bidRequest, resolvedRequest, adapterExtra, nil, nil, errList)
+		actualBidResp, err := e.buildBidResponse(context.Background(), liveAdapters, testCases[i].adapterBids, bidRequest, adapterExtra, nil, nil, errList)
 		assert.NoError(t, err, fmt.Sprintf("[TEST_FAILED] e.buildBidResponse resturns error in test: %s Error message: %s \n", testCases[i].description, err))
 		assert.Equalf(t, testCases[i].expectedBidResponse, actualBidResp, fmt.Sprintf("[TEST_FAILED] Objects must be equal for test: %s \n Expected: >>%s<< \n Actual: >>%s<< ", testCases[i].description, testCases[i].expectedBidResponse.Ext, actualBidResp.Ext))
 	}
@@ -702,6 +826,38 @@ func TestTimeoutComputation(t *testing.T) {
 	}
 }
 
+func TestSetDebugContextKey(t *testing.T) {
+	// Test cases
+	testCases := []struct {
+		desc              string
+		inDebugInfo       bool
+		expectedDebugInfo bool
+	}{
+		{
+			desc:              "debugInfo flag on, we expect to find DebugContextKey key in context",
+			inDebugInfo:       true,
+			expectedDebugInfo: true,
+		},
+		{
+			desc:              "debugInfo flag off, we don't expect to find DebugContextKey key in context",
+			inDebugInfo:       false,
+			expectedDebugInfo: false,
+		},
+	}
+
+	// Setup test
+	ex := exchange{}
+
+	// Run tests
+	for _, test := range testCases {
+		auctionCtx := ex.makeDebugContext(context.Background(), test.inDebugInfo)
+
+		debugInfo := auctionCtx.Value(DebugContextKey)
+		assert.NotNil(t, debugInfo, "%s. Flag set, `debugInfo` shouldn't be nil")
+		assert.Equal(t, test.expectedDebugInfo, debugInfo.(bool), "Desc: %s. Incorrect value mapped to DebugContextKey(`debugInfo`) in the context\n", test.desc)
+	}
+}
+
 // TestExchangeJSON executes tests for all the *.json files in exchangetest.
 func TestExchangeJSON(t *testing.T) {
 	if specFiles, err := ioutil.ReadDir("./exchangetest"); err == nil {
@@ -974,7 +1130,7 @@ func TestCategoryMapping(t *testing.T) {
 
 	adapterBids[bidderName1] = &seatBid
 
-	bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, requestExt, adapterBids, categoriesFetcher, targData)
+	bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, &requestExt, adapterBids, categoriesFetcher, targData)
 
 	assert.Equal(t, nil, err, "Category mapping error should be empty")
 	assert.Equal(t, 1, len(rejections), "There should be 1 bid rejection message")
@@ -1029,7 +1185,7 @@ func TestCategoryMappingNoIncludeBrandCategory(t *testing.T) {
 
 	adapterBids[bidderName1] = &seatBid
 
-	bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, requestExt, adapterBids, categoriesFetcher, targData)
+	bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, &requestExt, adapterBids, categoriesFetcher, targData)
 
 	assert.Equal(t, nil, err, "Category mapping error should be empty")
 	assert.Empty(t, rejections, "There should be no bid rejection messages")
@@ -1081,7 +1237,7 @@ func TestCategoryMappingTranslateCategoriesNil(t *testing.T) {
 
 	adapterBids[bidderName1] = &seatBid
 
-	bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, requestExt, adapterBids, categoriesFetcher, targData)
+	bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, &requestExt, adapterBids, categoriesFetcher, targData)
 
 	assert.Equal(t, nil, err, "Category mapping error should be empty")
 	assert.Equal(t, 1, len(rejections), "There should be 1 bid rejection message")
@@ -1163,7 +1319,7 @@ func TestCategoryMappingTranslateCategoriesFalse(t *testing.T) {
 
 	adapterBids[bidderName1] = &seatBid
 
-	bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, requestExt, adapterBids, categoriesFetcher, targData)
+	bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, &requestExt, adapterBids, categoriesFetcher, targData)
 
 	assert.Equal(t, nil, err, "Category mapping error should be empty")
 	assert.Empty(t, rejections, "There should be no bid rejection messages")
@@ -1229,7 +1385,7 @@ func TestCategoryDedupe(t *testing.T) {
 
 		adapterBids[bidderName1] = &seatBid
 
-		bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, requestExt, adapterBids, categoriesFetcher, targData)
+		bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, &requestExt, adapterBids, categoriesFetcher, targData)
 
 		assert.Equal(t, nil, err, "Category mapping error should be empty")
 		assert.Equal(t, 2, len(rejections), "There should be 2 bid rejection messages")
@@ -1340,7 +1496,7 @@ func TestBidRejectionErrors(t *testing.T) {
 
 		adapterBids[bidderName] = &seatBid
 
-		bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, test.reqExt, adapterBids, categoriesFetcher, targData)
+		bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, &test.reqExt, adapterBids, categoriesFetcher, targData)
 
 		if len(test.expectedCatDur) > 0 {
 			// Bid deduplication case
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 608e6a17..3b919d3d 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -3,6 +3,7 @@ package exchange
 import (
 	"context"
 	"encoding/json"
+	"fmt"
 	"testing"
 
 	"github.com/mxmCherry/openrtb"
@@ -79,7 +80,7 @@ func TestCleanOpenRTBRequests(t *testing.T) {
 	}
 
 	for _, test := range testCases {
-		reqByBidders, _, _, err := cleanOpenRTBRequests(context.Background(), test.req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig)
+		reqByBidders, _, _, err := cleanOpenRTBRequests(context.Background(), test.req, nil, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig)
 		if test.hasError {
 			assert.NotNil(t, err, "Error shouldn't be nil")
 		} else {
@@ -141,7 +142,7 @@ func TestCleanOpenRTBRequestsCCPA(t *testing.T) {
 			},
 		}
 
-		results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig)
+		results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, nil, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig)
 		result := results["appnexus"]
 
 		assert.Nil(t, errs)
@@ -185,7 +186,7 @@ func TestCleanOpenRTBRequestsCOPPA(t *testing.T) {
 		req := newBidRequest(t)
 		req.Regs = &openrtb.Regs{COPPA: test.coppa}
 
-		results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, config.Privacy{})
+		results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, nil, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, config.Privacy{})
 		result := results["appnexus"]
 
 		assert.Nil(t, errs)
@@ -202,77 +203,92 @@ func TestCleanOpenRTBRequestsCOPPA(t *testing.T) {
 
 func TestCleanOpenRTBRequestsSChain(t *testing.T) {
 	testCases := []struct {
-		description  string
-		inSourceExt  json.RawMessage
-		inExt        json.RawMessage
-		outSourceExt json.RawMessage
-		outExt       json.RawMessage
-		hasError     bool
+		description   string
+		inExt         json.RawMessage
+		inSourceExt   json.RawMessage
+		outSourceExt  json.RawMessage
+		outRequestExt json.RawMessage
+		hasError      bool
 	}{
 		{
-			description:  "Empty root ext and source ext",
-			inSourceExt:  json.RawMessage(``),
-			inExt:        json.RawMessage(``),
-			outSourceExt: json.RawMessage(``),
-			outExt:       json.RawMessage(``),
-			hasError:     false,
+			description:   "Empty root ext and source ext, nil unmarshaled ext",
+			inExt:         nil,
+			inSourceExt:   json.RawMessage(``),
+			outSourceExt:  json.RawMessage(``),
+			outRequestExt: json.RawMessage(``),
+			hasError:      false,
 		},
 		{
-			description:  "No schains in root ext and empty source ext",
-			inSourceExt:  json.RawMessage(``),
-			inExt:        json.RawMessage(`{"prebid":{"schains":[]}}`),
-			outSourceExt: json.RawMessage(``),
-			outExt:       json.RawMessage(`{"prebid":{}}`),
-			hasError:     false,
+			description:   "Empty root ext, source ext, and unmarshaled ext",
+			inExt:         json.RawMessage(``),
+			inSourceExt:   json.RawMessage(``),
+			outSourceExt:  json.RawMessage(``),
+			outRequestExt: json.RawMessage(``),
+			hasError:      false,
 		},
 		{
-			description:  "Use source schain -- no bidder schain or wildcard schain in ext.prebid.schains",
-			inSourceExt:  json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"example.com","sid":"example1","rid":"ExampleReq1","hp":1}],"ver":"1.0"}}`),
-			inExt:        json.RawMessage(`{"prebid":{"schains":[{"bidders":["bidder1"],"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}]}}`),
-			outSourceExt: json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"example.com","sid":"example1","rid":"ExampleReq1","hp":1}],"ver":"1.0"}}`),
-			outExt:       json.RawMessage(`{"prebid":{}}`),
-			hasError:     false,
+			description:   "No schains in root ext and empty source ext. Unmarshaled ext is equivalent to root ext",
+			inSourceExt:   json.RawMessage(``),
+			inExt:         json.RawMessage(`{"prebid":{"schains":[]}}`),
+			outSourceExt:  json.RawMessage(``),
+			outRequestExt: json.RawMessage(`{"prebid":{}}`),
+			hasError:      false,
 		},
 		{
-			description:  "Use schain for bidder in ext.prebid.schains",
-			inSourceExt:  json.RawMessage(``),
-			inExt:        json.RawMessage(`{"prebid":{"schains":[{"bidders":["appnexus"],"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}]}}`),
-			outSourceExt: json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}`),
-			outExt:       json.RawMessage(`{"prebid":{}}`),
-			hasError:     false,
+			description:   "Use source schain -- no bidder schain or wildcard schain in ext.prebid.schains. Unmarshaled ext is equivalent to root ext",
+			inSourceExt:   json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"example.com","sid":"example1","rid":"ExampleReq1","hp":1}],"ver":"1.0"}}`),
+			inExt:         json.RawMessage(`{"prebid":{"schains":[{"bidders":["bidder1"],"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}]}}`),
+			outSourceExt:  json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"example.com","sid":"example1","rid":"ExampleReq1","hp":1}],"ver":"1.0"}}`),
+			outRequestExt: json.RawMessage(`{"prebid":{}}`),
+			hasError:      false,
 		},
 		{
-			description:  "Use wildcard schain in ext.prebid.schains",
-			inSourceExt:  json.RawMessage(``),
-			inExt:        json.RawMessage(`{"prebid":{"schains":[{"bidders":["*"],"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}]}}`),
-			outSourceExt: json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}`),
-			outExt:       json.RawMessage(`{"prebid":{}}`),
-			hasError:     false,
+			description:   "Use schain for bidder in ext.prebid.schains. Unmarshaled ext is equivalent to root ext",
+			inSourceExt:   json.RawMessage(``),
+			inExt:         json.RawMessage(`{"prebid":{"schains":[{"bidders":["appnexus"],"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}]}}`),
+			outSourceExt:  json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}`),
+			outRequestExt: json.RawMessage(`{"prebid":{}}`),
+			hasError:      false,
 		},
 		{
-			description:  "Use schain for bidder in ext.prebid.schains instead of wildcard",
-			inSourceExt:  json.RawMessage(``),
-			inExt:        json.RawMessage(`{"prebid":{"aliases":{"appnexus":"alias1"},"schains":[{"bidders":["appnexus"],"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}, {"bidders":["*"],"schain":{"complete":1,"nodes":[{"asi":"wildcard.com","sid":"wildcard1","rid":"WildcardReq1","hp":1}],"ver":"1.0"}} ]}}`),
-			outSourceExt: json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}`),
-			outExt:       json.RawMessage(`{"prebid":{"aliases":{"appnexus":"alias1"}}}`),
-			hasError:     false,
+			description:   "Use wildcard schain in ext.prebid.schains. Unmarshaled ext is equivalent to root ext",
+			inSourceExt:   json.RawMessage(``),
+			inExt:         json.RawMessage(`{"prebid":{"schains":[{"bidders":["*"],"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}]}}`),
+			outSourceExt:  json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}`),
+			outRequestExt: json.RawMessage(`{"prebid":{}}`),
+			hasError:      false,
 		},
 		{
-			description:  "Use source schain -- multiple (two) bidder schains in ext.prebid.schains",
-			inSourceExt:  json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"example.com","sid":"example1","rid":"ExampleReq1","hp":1}],"ver":"1.0"}}`),
-			inExt:        json.RawMessage(`{"prebid":{"schains":[{"bidders":["appnexus"],"schain":{"complete":1,"nodes":[{"asi":"directseller1.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}, {"bidders":["appnexus"],"schain":{"complete":1,"nodes":[{"asi":"directseller2.com","sid":"00002","rid":"BidRequest2","hp":1}],"ver":"1.0"}}]}}`),
-			outSourceExt: nil,
-			outExt:       nil,
-			hasError:     true,
+			description:   "Use schain for bidder in ext.prebid.schains instead of wildcard. Unmarshaled ext is equivalent to root ext",
+			inSourceExt:   json.RawMessage(``),
+			inExt:         json.RawMessage(`{"prebid":{"aliases":{"appnexus":"alias1"},"schains":[{"bidders":["appnexus"],"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}, {"bidders":["*"],"schain":{"complete":1,"nodes":[{"asi":"wildcard.com","sid":"wildcard1","rid":"WildcardReq1","hp":1}],"ver":"1.0"}} ]}}`),
+			outSourceExt:  json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"directseller.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}`),
+			outRequestExt: json.RawMessage(`{"prebid":{"aliases":{"appnexus":"alias1"}}}`),
+			hasError:      false,
+		},
+		{
+			description:   "Use source schain -- multiple (two) bidder schains in ext.prebid.schains. Unmarshaled ext is equivalent to root ext",
+			inSourceExt:   json.RawMessage(`{"schain":{"complete":1,"nodes":[{"asi":"example.com","sid":"example1","rid":"ExampleReq1","hp":1}],"ver":"1.0"}}`),
+			inExt:         json.RawMessage(`{"prebid":{"schains":[{"bidders":["appnexus"],"schain":{"complete":1,"nodes":[{"asi":"directseller1.com","sid":"00001","rid":"BidRequest1","hp":1}],"ver":"1.0"}}, {"bidders":["appnexus"],"schain":{"complete":1,"nodes":[{"asi":"directseller2.com","sid":"00002","rid":"BidRequest2","hp":1}],"ver":"1.0"}}]}}`),
+			outSourceExt:  nil,
+			outRequestExt: nil,
+			hasError:      true,
 		},
 	}
 
 	for _, test := range testCases {
 		req := newBidRequest(t)
 		req.Source.Ext = test.inSourceExt
-		req.Ext = test.inExt
 
-		results, _, _, errs := cleanOpenRTBRequests(context.Background(), req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{}, true, config.Privacy{})
+		var extRequest *openrtb_ext.ExtRequest
+		if test.inExt != nil {
+			req.Ext = test.inExt
+			unmarshaledExt, err := extractBidRequestExt(req)
+			assert.NoErrorf(t, err, test.description+":Error unmarshaling inExt")
+			extRequest = unmarshaledExt
+		}
+
+		results, _, _, errs := cleanOpenRTBRequests(context.Background(), req, extRequest, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{}, true, config.Privacy{})
 		result := results["appnexus"]
 
 		if test.hasError == true {
@@ -281,11 +297,295 @@ func TestCleanOpenRTBRequestsSChain(t *testing.T) {
 		} else {
 			assert.Nil(t, errs)
 			assert.Equal(t, test.outSourceExt, result.Source.Ext, test.description+":Source.Ext")
-			assert.Equal(t, test.outExt, result.Ext, test.description+":Ext")
+			assert.Equal(t, test.outRequestExt, result.Ext, test.description+":Ext")
 		}
 	}
 }
 
+func TestExtractBidRequesteExt(t *testing.T) {
+	testCases := []struct {
+		desc          string
+		inBidRequest  *openrtb.BidRequest
+		outRequestExt *openrtb_ext.ExtRequest
+		outError      error
+	}{
+		{
+			desc:          "Valid",
+			inBidRequest:  &openrtb.BidRequest{Ext: json.RawMessage(`{"prebid":{"debug":true}}`)},
+			outRequestExt: &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Debug: true}},
+			outError:      nil,
+		},
+		{
+			desc:          "bidRequest nil, we expect an error",
+			inBidRequest:  nil,
+			outRequestExt: &openrtb_ext.ExtRequest{},
+			outError:      fmt.Errorf("Error bidRequest should not be nil"),
+		},
+		{
+			desc:          "Non-nil bidRequest with empty Ext, we expect a blank requestExt",
+			inBidRequest:  &openrtb.BidRequest{},
+			outRequestExt: &openrtb_ext.ExtRequest{},
+			outError:      nil,
+		},
+		{
+			desc:          "Non-nil bidRequest with non-empty, invalid Ext, we expect unmarshaling error",
+			inBidRequest:  &openrtb.BidRequest{Ext: json.RawMessage(`invalid`)},
+			outRequestExt: &openrtb_ext.ExtRequest{},
+			outError:      fmt.Errorf("Error decoding Request.ext : invalid character 'i' looking for beginning of value"),
+		},
+	}
+	for _, test := range testCases {
+		actualRequestExt, actualErr := extractBidRequestExt(test.inBidRequest)
+
+		assert.Equal(t, test.outRequestExt, actualRequestExt, "%s. Unexpected RequestExt value. \n", test.desc)
+		assert.Equal(t, test.outError, actualErr, "%s. Unexpected error value. \n", test.desc)
+	}
+}
+
+func TestGetExtCacheInfo(t *testing.T) {
+	testCases := []struct {
+		desc         string
+		inRequestExt *openrtb_ext.ExtRequest
+		outCacheBids bool
+		outCacheVAST bool
+	}{
+		{
+			desc:         "Nil inRequestExt, both cache flags false",
+			inRequestExt: nil,
+			outCacheBids: false,
+			outCacheVAST: false,
+		},
+		{
+			desc:         "Non-nil inRequestExt, nil Cache info, both cache flags false",
+			inRequestExt: &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Cache: nil}},
+			outCacheBids: false,
+			outCacheVAST: false,
+		},
+		{
+			desc: "Non-nil inRequestExt, non-nil Cache info, both ExtRequestPrebidCacheBids and ExtRequestPrebidCacheVAST nil",
+			inRequestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Cache: &openrtb_ext.ExtRequestPrebidCache{
+						Bids:    nil,
+						VastXML: nil,
+					},
+				},
+			},
+			outCacheBids: false,
+			outCacheVAST: false,
+		},
+		{
+			desc: "Non-nil inRequestExt, non-nil Cache info, both ExtRequestPrebidCacheBids nil, shouldCacheVast true",
+			inRequestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Cache: &openrtb_ext.ExtRequestPrebidCache{
+						Bids:    nil,
+						VastXML: &openrtb_ext.ExtRequestPrebidCacheVAST{},
+					},
+				},
+			},
+			outCacheBids: false,
+			outCacheVAST: true,
+		},
+		{
+			desc: "Non-nil inRequestExt, non-nil Cache info, both ExtRequestPrebidCacheVAST nil, shouldCacheBids true",
+			inRequestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Cache: &openrtb_ext.ExtRequestPrebidCache{
+						Bids:    &openrtb_ext.ExtRequestPrebidCacheBids{},
+						VastXML: nil,
+					},
+				},
+			},
+			outCacheBids: true,
+			outCacheVAST: false,
+		},
+		{
+			desc: "Non-nil inRequestExt, non-nil Cache info values, both shouldCacheBids and shouldCacheVAST return true",
+			inRequestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Cache: &openrtb_ext.ExtRequestPrebidCache{
+						Bids:    &openrtb_ext.ExtRequestPrebidCacheBids{},
+						VastXML: &openrtb_ext.ExtRequestPrebidCacheVAST{},
+					},
+				},
+			},
+			outCacheBids: true,
+			outCacheVAST: true,
+		},
+	}
+	for _, test := range testCases {
+		shouldCacheBids, shouldCacheVAST := getExtCacheInfo(test.inRequestExt)
+
+		assert.Equal(t, test.outCacheBids, shouldCacheBids, "%s. Unexpected shouldCacheBids value. \n", test.desc)
+		assert.Equal(t, test.outCacheVAST, shouldCacheVAST, "%s. Unexpected shouldCacheVAST value. \n", test.desc)
+	}
+}
+
+func TestGetExtTargetData(t *testing.T) {
+	type inTest struct {
+		requestExt      *openrtb_ext.ExtRequest
+		shouldCacheBids bool
+		shouldCacheVAST bool
+	}
+	type outTest struct {
+		targetData    *targetData
+		nilTargetData bool
+	}
+	testCases := []struct {
+		desc string
+		in   inTest
+		out  outTest
+	}{
+		{
+			"nil requestExt, nil outTargetData",
+			inTest{
+				requestExt:      nil,
+				shouldCacheBids: true,
+				shouldCacheVAST: true,
+			},
+			outTest{targetData: nil, nilTargetData: true},
+		},
+		{
+			"Valid requestExt, nil Targeting field, nil outTargetData",
+			inTest{
+				requestExt: &openrtb_ext.ExtRequest{
+					Prebid: openrtb_ext.ExtRequestPrebid{
+						Targeting: nil,
+					},
+				},
+				shouldCacheBids: true,
+				shouldCacheVAST: true,
+			},
+			outTest{targetData: nil, nilTargetData: true},
+		},
+		{
+			"Valid targeting data in requestExt, valid outTargetData",
+			inTest{
+				requestExt: &openrtb_ext.ExtRequest{
+					Prebid: openrtb_ext.ExtRequestPrebid{
+						Targeting: &openrtb_ext.ExtRequestTargeting{
+							PriceGranularity: openrtb_ext.PriceGranularity{
+								Precision: 2,
+								Ranges:    []openrtb_ext.GranularityRange{{Min: 0.00, Max: 5.00, Increment: 1.00}},
+							},
+							IncludeWinners:    true,
+							IncludeBidderKeys: true,
+						},
+					},
+				},
+				shouldCacheBids: true,
+				shouldCacheVAST: true,
+			},
+			outTest{
+				targetData: &targetData{
+					priceGranularity: openrtb_ext.PriceGranularity{
+						Precision: 2,
+						Ranges:    []openrtb_ext.GranularityRange{{Min: 0.00, Max: 5.00, Increment: 1.00}},
+					},
+					includeWinners:    true,
+					includeBidderKeys: true,
+					includeCacheBids:  true,
+					includeCacheVast:  true,
+				},
+				nilTargetData: false,
+			},
+		},
+	}
+	for _, test := range testCases {
+		actualTargetData := getExtTargetData(test.in.requestExt, test.in.shouldCacheBids, test.in.shouldCacheVAST)
+
+		if test.out.nilTargetData {
+			assert.Nil(t, actualTargetData, "%s. Targeting data should be nil. \n", test.desc)
+		} else {
+			assert.NotNil(t, actualTargetData, "%s. Targeting data should NOT be nil. \n", test.desc)
+			assert.Equal(t, *test.out.targetData, *actualTargetData, "%s. Unexpected targeting data value. \n", test.desc)
+		}
+	}
+}
+
+func TestGetDebugInfo(t *testing.T) {
+	type inTest struct {
+		bidRequest *openrtb.BidRequest
+		requestExt *openrtb_ext.ExtRequest
+	}
+	testCases := []struct {
+		desc string
+		in   inTest
+		out  bool
+	}{
+		{
+			desc: "Nil bid request, nil requestExt",
+			in:   inTest{nil, nil},
+			out:  false,
+		},
+		{
+			desc: "bid request test == 0, nil requestExt",
+			in:   inTest{&openrtb.BidRequest{Test: 0}, nil},
+			out:  false,
+		},
+		{
+			desc: "Nil bid request, requestExt debug flag false",
+			in:   inTest{nil, &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Debug: false}}},
+			out:  false,
+		},
+		{
+			desc: "bid request test == 0, requestExt debug flag false",
+			in:   inTest{&openrtb.BidRequest{Test: 0}, &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Debug: false}}},
+			out:  false,
+		},
+		{
+			desc: "bid request test == 1, requestExt debug flag false",
+			in:   inTest{&openrtb.BidRequest{Test: 1}, &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Debug: false}}},
+			out:  true,
+		},
+		{
+			desc: "bid request test == 0, requestExt debug flag true",
+			in:   inTest{&openrtb.BidRequest{Test: 0}, &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Debug: true}}},
+			out:  true,
+		},
+		{
+			desc: "bid request test == 1, requestExt debug flag true",
+			in:   inTest{&openrtb.BidRequest{Test: 1}, &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Debug: true}}},
+			out:  true,
+		},
+	}
+	for _, test := range testCases {
+		actualDebugInfo := getDebugInfo(test.in.bidRequest, test.in.requestExt)
+
+		assert.Equal(t, test.out, actualDebugInfo, "%s. Unexpected debug value. \n", test.desc)
+	}
+}
+
+func TestGetExtBidAdjustmentFactors(t *testing.T) {
+	testCases := []struct {
+		desc                    string
+		inRequestExt            *openrtb_ext.ExtRequest
+		outBidAdjustmentFactors map[string]float64
+	}{
+		{
+			desc:                    "Nil request ext",
+			inRequestExt:            nil,
+			outBidAdjustmentFactors: nil,
+		},
+		{
+			desc:                    "Non-nil request ext, nil BidAdjustmentFactors field",
+			inRequestExt:            &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{BidAdjustmentFactors: nil}},
+			outBidAdjustmentFactors: nil,
+		},
+		{
+			desc:                    "Non-nil request ext, valid BidAdjustmentFactors field",
+			inRequestExt:            &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{BidAdjustmentFactors: map[string]float64{"bid-factor": 1.0}}},
+			outBidAdjustmentFactors: map[string]float64{"bid-factor": 1.0},
+		},
+	}
+	for _, test := range testCases {
+		actualBidAdjustmentFactors := getExtBidAdjustmentFactors(test.inRequestExt)
+
+		assert.Equal(t, test.outBidAdjustmentFactors, actualBidAdjustmentFactors, "%s. Unexpected BidAdjustmentFactors value. \n", test.desc)
+	}
+}
+
 func TestCleanOpenRTBRequestsLMT(t *testing.T) {
 	var (
 		enabled  int8 = 1
@@ -346,7 +646,7 @@ func TestCleanOpenRTBRequestsLMT(t *testing.T) {
 			},
 		}
 
-		results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig)
+		results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, nil, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig)
 		result := results["appnexus"]
 
 		assert.Nil(t, errs)
@@ -427,7 +727,7 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			},
 		}
 
-		results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: !test.gdprScrub}, true, privacyConfig)
+		results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, nil, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: !test.gdprScrub}, true, privacyConfig)
 		result := results["appnexus"]
 
 		assert.Nil(t, errs)
diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go
index 32ab2e73..9197ed95 100755
--- a/usersync/usersyncers/syncer_test.go
+++ b/usersync/usersyncers/syncer_test.go
@@ -93,8 +93,10 @@ func TestNewSyncerMap(t *testing.T) {
 		openrtb_ext.BidderMobileFuse:   true,
 		openrtb_ext.BidderOrbidder:     true,
 		openrtb_ext.BidderPubnative:    true,
+		openrtb_ext.BidderSmaato:       true,
 		openrtb_ext.BidderTappx:        true,
 		openrtb_ext.BidderYeahmobi:     true,
+		openrtb_ext.BidderAdprime:      true,
 	}
 
 	for bidder, config := range cfg.Adapters {