Repository: prebid/prebid-server
Pull request #1346 (2020-06-10 08:38:08)

Adding Smartadserver adapter
Hello,

I have created this PR to add the Smart Adserver adapter. 

Thanks for reviewing it :)


Patch:
diff --git a/.travis.yml b/.travis.yml
index ea2c46c4..692141f7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,8 @@
 language: go
 
 go:
-  - '1.12'
   - '1.13'
-  - '1.14'
+  - '1.14.2'
 
 go_import_path: github.com/prebid/prebid-server
 
diff --git a/Dockerfile b/Dockerfile
index a8fea9c3..2c60b9e3 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,8 +3,8 @@ RUN apt-get update && \
     apt-get -y upgrade && \
     apt-get install -y wget
 RUN cd /tmp && \
-    wget https://dl.google.com/go/go1.12.7.linux-amd64.tar.gz && \
-    tar -xf go1.12.7.linux-amd64.tar.gz && \
+    wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz && \
+    tar -xf go1.14.2.linux-amd64.tar.gz && \
     mv go /usr/local
 RUN mkdir -p /app/prebid-server/
 WORKDIR /app/prebid-server/
diff --git a/README.md b/README.md
index a59bf5f6..b69e7e76 100644
--- a/README.md
+++ b/README.md
@@ -18,9 +18,10 @@ For more information, see:
 
 ## Installation
 
-First install [Go 1.12](https://golang.org/doc/install) latest version.
+First install [Go](https://golang.org/doc/install) version 1.13 or newer.
+
 Note that prebid-server is using [Go modules](https://blog.golang.org/using-go-modules).
-If using Go version <1.13 and are inside GOPATH `GO111MODULE` needs to be set to `GO111MODULE=on`.
+We officially support the most recent two major versions of the Go runtime. However, if you'd like to use a version <1.13 and are inside GOPATH `GO111MODULE` needs to be set to `GO111MODULE=on`.
 
 Download and prepare Prebid Server:
 
diff --git a/adapters/adocean/adocean.go b/adapters/adocean/adocean.go
index 514aeb38..8740712b 100644
--- a/adapters/adocean/adocean.go
+++ b/adapters/adocean/adocean.go
@@ -7,6 +7,7 @@ import (
 	"net/http"
 	"net/url"
 	"regexp"
+	"sort"
 	"strconv"
 	"strings"
 	"text/template"
@@ -19,7 +20,7 @@ import (
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
-const adapterVersion = "1.0.0"
+const adapterVersion = "1.1.0"
 const maxUriLength = 8000
 const measurementCode = `
 	<script>
@@ -51,6 +52,12 @@ type ResponseAdUnit struct {
 	Error    string `json:"error"`
 }
 
+type requestData struct {
+	Url        *url.URL
+	Headers    *http.Header
+	SlaveSizes map[string]string
+}
+
 func NewAdOceanBidder(client *http.Client, endpointTemplateString string) *AdOceanAdapter {
 	a := &adapters.HTTPAdapter{Client: client}
 	endpointTemplate, err := template.New("endpointTemplate").Parse(endpointTemplateString)
@@ -89,44 +96,59 @@ func (a *AdOceanAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adap
 		}
 	}
 
-	var httpRequests []*adapters.RequestData
 	var errors []error
-
+	var err error
+	requestsData := make([]*requestData, 0, len(request.Imp))
 	for _, auction := range request.Imp {
-		newHttpRequest, err := a.makeRequest(httpRequests, &auction, request, consentString)
+		requestsData, err = a.addNewBid(requestsData, &auction, request, consentString)
 		if err != nil {
 			errors = append(errors, err)
-		} else if newHttpRequest != nil {
-			httpRequests = append(httpRequests, newHttpRequest)
 		}
 	}
 
+	httpRequests := make([]*adapters.RequestData, 0, len(requestsData))
+	for _, requestData := range requestsData {
+		httpRequests = append(httpRequests, &adapters.RequestData{
+			Method:  "GET",
+			Uri:     requestData.Url.String(),
+			Headers: *requestData.Headers,
+		})
+	}
+
 	return httpRequests, errors
 }
 
-func (a *AdOceanAdapter) makeRequest(existingRequests []*adapters.RequestData, imp *openrtb.Imp, request *openrtb.BidRequest, consentString string) (*adapters.RequestData, error) {
+func (a *AdOceanAdapter) addNewBid(
+	requestsData []*requestData,
+	imp *openrtb.Imp,
+	request *openrtb.BidRequest,
+	consentString string,
+) ([]*requestData, error) {
 	var bidderExt adapters.ExtImpBidder
 	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
-		return nil, &errortypes.BadInput{
+		return requestsData, &errortypes.BadInput{
 			Message: "Error parsing bidderExt object",
 		}
 	}
 
 	var adOceanExt openrtb_ext.ExtImpAdOcean
 	if err := json.Unmarshal(bidderExt.Bidder, &adOceanExt); err != nil {
-		return nil, &errortypes.BadInput{
+		return requestsData, &errortypes.BadInput{
 			Message: "Error parsing adOceanExt parameters",
 		}
 	}
 
-	addedToExistingRequest := addToExistingRequest(existingRequests, &adOceanExt, imp.ID)
+	addedToExistingRequest := addToExistingRequest(requestsData, &adOceanExt, imp, (request.Test == 1))
 	if addedToExistingRequest {
-		return nil, nil
+		return requestsData, nil
 	}
 
-	url, err := a.makeURL(&adOceanExt, imp.ID, request, consentString)
+	slaveSizes := map[string]string{}
+	slaveSizes[adOceanExt.SlaveID] = getImpSizes(imp)
+
+	url, err := a.makeURL(&adOceanExt, imp, request, slaveSizes, consentString)
 	if err != nil {
-		return nil, err
+		return requestsData, err
 	}
 
 	headers := http.Header{}
@@ -147,54 +169,63 @@ func (a *AdOceanAdapter) makeRequest(existingRequests []*adapters.RequestData, i
 		headers.Add("Referer", request.Site.Page)
 	}
 
-	return &adapters.RequestData{
-		Method:  "GET",
-		Uri:     url,
-		Headers: headers,
-	}, nil
+	requestsData = append(requestsData, &requestData{
+		Url:        url,
+		Headers:    &headers,
+		SlaveSizes: slaveSizes,
+	})
+
+	return requestsData, nil
 }
 
-func addToExistingRequest(existingRequests []*adapters.RequestData, newParams *openrtb_ext.ExtImpAdOcean, auctionID string) bool {
-requestsLoop:
-	for _, request := range existingRequests {
-		endpointURL, _ := url.Parse(request.Uri)
-		queryParams := endpointURL.Query()
+func addToExistingRequest(requestsData []*requestData, newParams *openrtb_ext.ExtImpAdOcean, imp *openrtb.Imp, testImp bool) bool {
+	auctionID := imp.ID
+
+	for _, requestData := range requestsData {
+		queryParams := requestData.Url.Query()
 		masterID := queryParams["id"][0]
 
 		if masterID == newParams.MasterID {
-			aids := queryParams["aid"]
-			for _, aid := range aids {
-				slaveID := strings.SplitN(aid, ":", 2)[0]
-				if slaveID == newParams.SlaveID {
-					continue requestsLoop
-				}
+			if _, has := requestData.SlaveSizes[newParams.SlaveID]; has {
+				continue
 			}
 
 			queryParams.Add("aid", newParams.SlaveID+":"+auctionID)
-			endpointURL.RawQuery = queryParams.Encode()
-			newUri := endpointURL.String()
-			if len(newUri) < maxUriLength {
-				request.Uri = newUri
+			requestData.SlaveSizes[newParams.SlaveID] = getImpSizes(imp)
+			setSlaveSizesParam(&queryParams, requestData.SlaveSizes, testImp)
+
+			newUrl := *(requestData.Url)
+			newUrl.RawQuery = queryParams.Encode()
+			if len(newUrl.String()) < maxUriLength {
+				requestData.Url = &newUrl
 				return true
 			}
+
+			delete(requestData.SlaveSizes, newParams.SlaveID)
 		}
 	}
 
 	return false
 }
 
-func (a *AdOceanAdapter) makeURL(params *openrtb_ext.ExtImpAdOcean, auctionID string, request *openrtb.BidRequest, consentString string) (string, error) {
+func (a *AdOceanAdapter) makeURL(
+	params *openrtb_ext.ExtImpAdOcean,
+	imp *openrtb.Imp,
+	request *openrtb.BidRequest,
+	slaveSizes map[string]string,
+	consentString string,
+) (*url.URL, error) {
 	endpointParams := macros.EndpointTemplateParams{Host: params.EmitterDomain}
 	host, err := macros.ResolveMacros(a.endpointTemplate, endpointParams)
 	if err != nil {
-		return "", &errortypes.BadInput{
+		return nil, &errortypes.BadInput{
 			Message: "Unable to parse endpoint url template: " + err.Error(),
 		}
 	}
 
 	endpointURL, err := url.Parse(host)
 	if err != nil {
-		return "", &errortypes.BadInput{
+		return nil, &errortypes.BadInput{
 			Message: "Malformed URL: " + err.Error(),
 		}
 	}
@@ -205,6 +236,7 @@ func (a *AdOceanAdapter) makeURL(params *openrtb_ext.ExtImpAdOcean, auctionID st
 	}
 	endpointURL.Path = "/_" + strconv.Itoa(randomizedPart) + "/ad.json"
 
+	auctionID := imp.ID
 	queryParams := url.Values{}
 	queryParams.Add("pbsrv_v", adapterVersion)
 	queryParams.Add("id", params.MasterID)
@@ -218,9 +250,58 @@ func (a *AdOceanAdapter) makeURL(params *openrtb_ext.ExtImpAdOcean, auctionID st
 	if request.User != nil && request.User.BuyerUID != "" {
 		queryParams.Add("hcuserid", request.User.BuyerUID)
 	}
+
+	setSlaveSizesParam(&queryParams, slaveSizes, (request.Test == 1))
 	endpointURL.RawQuery = queryParams.Encode()
 
-	return endpointURL.String(), nil
+	return endpointURL, nil
+}
+
+func getImpSizes(imp *openrtb.Imp) string {
+	if imp.Banner == nil {
+		return ""
+	}
+
+	if len(imp.Banner.Format) > 0 {
+		sizes := make([]string, len(imp.Banner.Format))
+		for i, format := range imp.Banner.Format {
+			sizes[i] = strconv.FormatUint(format.W, 10) + "x" + strconv.FormatUint(format.H, 10)
+		}
+
+		return strings.Join(sizes, "_")
+	}
+
+	if imp.Banner.W != nil && imp.Banner.H != nil {
+		return strconv.FormatUint(*imp.Banner.W, 10) + "x" + strconv.FormatUint(*imp.Banner.H, 10)
+	}
+
+	return ""
+}
+
+func setSlaveSizesParam(queryParams *url.Values, slaveSizes map[string]string, orderByKey bool) {
+	sizeValues := make([]string, 0, len(slaveSizes))
+	slaveIDs := make([]string, 0, len(slaveSizes))
+	for k := range slaveSizes {
+		slaveIDs = append(slaveIDs, k)
+	}
+
+	if orderByKey {
+		sort.Strings(slaveIDs)
+	}
+
+	for _, slaveID := range slaveIDs {
+		sizes := slaveSizes[slaveID]
+		if sizes == "" {
+			continue
+		}
+
+		rawSlaveID := strings.Replace(slaveID, "adocean", "", 1)
+		sizeValues = append(sizeValues, rawSlaveID+"~"+sizes)
+	}
+
+	if len(sizeValues) > 0 {
+		queryParams.Set("aosspsizes", strings.Join(sizeValues, "-"))
+	}
 }
 
 func (a *AdOceanAdapter) MakeBids(
diff --git a/adapters/avocet/avocet.go b/adapters/avocet/avocet.go
new file mode 100644
index 00000000..918fc23e
--- /dev/null
+++ b/adapters/avocet/avocet.go
@@ -0,0 +1,124 @@
+package avocet
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// AvocetAdapter implements a adapters.Bidder compatible with the Avocet advertising platform.
+type AvocetAdapter struct {
+	// Endpoint is a http endpoint to use when making requests to the Avocet advertising platform.
+	Endpoint string
+}
+
+func (a *AvocetAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	if len(request.Imp) == 0 {
+		return nil, nil
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	body, err := json.Marshal(request)
+	if err != nil {
+		return nil, []error{&errortypes.FailedToRequestBids{
+			Message: err.Error(),
+		}}
+	}
+	reqData := &adapters.RequestData{
+		Method:  http.MethodPost,
+		Uri:     a.Endpoint,
+		Body:    body,
+		Headers: headers,
+	}
+	return []*adapters.RequestData{reqData}, nil
+}
+
+type avocetBidExt struct {
+	Avocet avocetBidExtension `json:"avocet"`
+}
+
+type avocetBidExtension struct {
+	Duration     int `json:"duration"`
+	DealPriority int `json:"deal_priority"`
+}
+
+func (a *AvocetAdapter) 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.StatusOK {
+		var errStr string
+		if len(response.Body) > 0 {
+			errStr = string(response.Body)
+		} else {
+			errStr = "no response body"
+		}
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("received status code: %v error: %s", response.StatusCode, errStr),
+		}}
+	}
+
+	var br openrtb.BidResponse
+	err := json.Unmarshal(response.Body, &br)
+	if err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: err.Error(),
+		}}
+	}
+	var errs []error
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)
+	for i := range br.SeatBid {
+		for j := range br.SeatBid[i].Bid {
+			var ext avocetBidExt
+			if len(br.SeatBid[i].Bid[j].Ext) > 0 {
+				err := json.Unmarshal(br.SeatBid[i].Bid[j].Ext, &ext)
+				if err != nil {
+					errs = append(errs, err)
+					continue
+				}
+			}
+			tbid := &adapters.TypedBid{
+				Bid:          &br.SeatBid[i].Bid[j],
+				DealPriority: ext.Avocet.DealPriority,
+			}
+			tbid.BidType = getBidType(br.SeatBid[i].Bid[j], ext)
+			if tbid.BidType == openrtb_ext.BidTypeVideo {
+				tbid.BidVideo = &openrtb_ext.ExtBidPrebidVideo{
+					Duration: ext.Avocet.Duration,
+				}
+			}
+			bidResponse.Bids = append(bidResponse.Bids, tbid)
+		}
+	}
+	return bidResponse, nil
+}
+
+// getBidType returns the openrtb_ext.BidType for the provided bid.
+func getBidType(bid openrtb.Bid, ext avocetBidExt) openrtb_ext.BidType {
+	if ext.Avocet.Duration != 0 {
+		return openrtb_ext.BidTypeVideo
+	}
+	switch bid.API {
+	case openrtb.APIFrameworkVPAID10, openrtb.APIFrameworkVPAID20:
+		return openrtb_ext.BidTypeVideo
+	default:
+		return openrtb_ext.BidTypeBanner
+	}
+}
+
+// NewAvocetAdapter returns a new AvocetAdapter using the provided endpoint.
+func NewAvocetAdapter(endpoint string) *AvocetAdapter {
+	return &AvocetAdapter{
+		Endpoint: endpoint,
+	}
+}
diff --git a/adapters/avocet/avocet/exemplary/banner.json b/adapters/avocet/avocet/exemplary/banner.json
new file mode 100644
index 00000000..b5e308ea
--- /dev/null
+++ b/adapters/avocet/avocet/exemplary/banner.json
@@ -0,0 +1,106 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "placement": "5ea9601ac865f911007f1b6a"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placement": "5ea9601ac865f911007f1b6a"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "bidid": "dd87f80c-16a0-43c8-a673-b94b3ea4d417",
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "adm": "<iframe src=\"http://ads.staging.avct.cloud/sv?pp=${AUCTION_PRICE}&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5b51e49634f2021f127ff7c9&tacid=5b51e4ed89654741306813a8&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=1&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591874537316649768&h=250&w=300&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&ck=1_5d99a849\" height=\"250\" width=\"300\" marginwidth=0 marginheight=0 hspace=0 vspace=0 frameborder=0 scrolling=\"no\"></iframe>",
+                  "adomain": ["avocet.io"],
+                  "cid": "5b51e2d689654741306813a4",
+                  "crid": "5b51e49634f2021f127ff7c9",
+                  "h": 250,
+                  "id": "bc708396-9202-437b-b726-08b9864cb8b8",
+                  "impid": "test-imp-id",
+                  "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg",
+                  "language": "en",
+                  "price": 15.64434783,
+                  "w": 300
+                }
+              ],
+              "seat": "TEST_SEAT_ID"
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBids": [
+    {
+      "bid": {
+        "adm": "<iframe src=\"http://ads.staging.avct.cloud/sv?pp=${AUCTION_PRICE}&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5b51e49634f2021f127ff7c9&tacid=5b51e4ed89654741306813a8&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=1&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591874537316649768&h=250&w=300&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&ck=1_5d99a849\" height=\"250\" width=\"300\" marginwidth=0 marginheight=0 hspace=0 vspace=0 frameborder=0 scrolling=\"no\"></iframe>",
+        "adomain": ["avocet.io"],
+        "cid": "5b51e2d689654741306813a4",
+        "crid": "5b51e49634f2021f127ff7c9",
+        "h": 250,
+        "id": "bc708396-9202-437b-b726-08b9864cb8b8",
+        "impid": "test-imp-id",
+        "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg",
+        "language": "en",
+        "price": 15.64434783,
+        "w": 300
+      },
+      "type": "banner"
+    }
+  ]
+}
diff --git a/adapters/avocet/avocet/exemplary/video.json b/adapters/avocet/avocet/exemplary/video.json
new file mode 100644
index 00000000..2398256b
--- /dev/null
+++ b/adapters/avocet/avocet/exemplary/video.json
@@ -0,0 +1,104 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1920,
+          "h": 1080
+        },
+        "ext": {
+          "bidder": {
+            "placement": "5ea9601ac865f911007f1b6a"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1920,
+                "h": 1080
+              },
+              "ext": {
+                "bidder": {
+                  "placement": "5ea9601ac865f911007f1b6a"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "bidid": "a0eec3aa-f9f6-42fb-9aa4-f1b5656d4f42",
+          "id": "749d36d7-c993-455f-aefd-ffd8a7e3ccf",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "adm": "<VAST version=\"3.0\"><Ad id=\"5ec530e32d57fe1100f17d87\"><Wrapper><AdSystem>Avocet</AdSystem><VASTAdTagURI><![CDATA[http://ads.staging.avct.cloud/vast?x=1&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5ec530e32d57fe1100f17d87&tacid=5ec531d32d57fe1100f17d89&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=2&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591875033134290518&h=396&w=600&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&pixel=1&ck=1_c343bf14]]></VASTAdTagURI><Impression><![CDATA[http://ads.staging.avct.cloud/sv?pp=${AUCTION_PRICE}&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5ec530e32d57fe1100f17d87&tacid=5ec531d32d57fe1100f17d89&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=2&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591875033134290518&h=396&w=600&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&pixel=1&ck=1_c343bf14]]></Impression><Creatives><Creative AdId=\"5ec530e32d57fe1100f17d87\"><Linear><TrackingEvents></TrackingEvents><VideoClicks></VideoClicks></Linear></Creative></Creatives></Wrapper></Ad></VAST>",
+                  "adomain": ["avocet.io"],
+                  "cid": "5b51e2d689654741306813a4",
+                  "crid": "5ec530e32d57fe1100f17d87",
+                  "h": 396,
+                  "id": "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f",
+                  "impid": "dfp-ad--top-above-nav",
+                  "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg",
+                  "language": "en",
+                  "price": 15.64434783,
+                  "w": 600,
+                  "ext": {
+                    "avocet": {
+                      "duration": 30
+                    }
+                  }
+                }
+              ],
+              "seat": "TEST_SEAT_ID"
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBids": [
+    {
+      "bid": {
+        "adm": "<VAST version=\"3.0\"><Ad id=\"5ec530e32d57fe1100f17d87\"><Wrapper><AdSystem>Avocet</AdSystem><VASTAdTagURI><![CDATA[http://ads.staging.avct.cloud/vast?x=1&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5ec530e32d57fe1100f17d87&tacid=5ec531d32d57fe1100f17d89&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=2&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591875033134290518&h=396&w=600&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&pixel=1&ck=1_c343bf14]]></VASTAdTagURI><Impression><![CDATA[http://ads.staging.avct.cloud/sv?pp=${AUCTION_PRICE}&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5ec530e32d57fe1100f17d87&tacid=5ec531d32d57fe1100f17d89&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=2&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591875033134290518&h=396&w=600&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&pixel=1&ck=1_c343bf14]]></Impression><Creatives><Creative AdId=\"5ec530e32d57fe1100f17d87\"><Linear><TrackingEvents></TrackingEvents><VideoClicks></VideoClicks></Linear></Creative></Creatives></Wrapper></Ad></VAST>",
+        "adomain": ["avocet.io"],
+        "cid": "5b51e2d689654741306813a4",
+        "crid": "5ec530e32d57fe1100f17d87",
+        "h": 396,
+        "id": "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f",
+        "impid": "dfp-ad--top-above-nav",
+        "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg",
+        "language": "en",
+        "price": 15.64434783,
+        "w": 600,
+        "ext": {
+          "avocet": {
+            "duration": 30
+          }
+        }
+      },
+      "type": "video"
+    }
+  ]
+}
diff --git a/adapters/avocet/usersync.go b/adapters/avocet/usersync.go
new file mode 100644
index 00000000..f1075ab3
--- /dev/null
+++ b/adapters/avocet/usersync.go
@@ -0,0 +1,12 @@
+package avocet
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewAvocetSyncer(temp *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("avocet", 63, temp, adapters.SyncTypeRedirect)
+}
diff --git a/adapters/consumable/consumable.go b/adapters/consumable/consumable.go
index 1fa23377..243f1b80 100644
--- a/adapters/consumable/consumable.go
+++ b/adapters/consumable/consumable.go
@@ -268,8 +268,11 @@ func (a *ConsumableAdapter) MakeBids(
 			//bid.referrer = utils.getTopWindowUrl();
 
 			bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
-				Bid:     &bid,
-				BidType: getMediaTypeForImp(getImp(bid.ImpID, internalRequest.Imp)),
+				Bid: &bid,
+				// Consumable units are always HTML, never VAST.
+				// From Prebid's point of view, this means that Consumable units
+				// are always "banners".
+				BidType: openrtb_ext.BidTypeBanner,
 			})
 		}
 	}
@@ -303,16 +306,6 @@ func extractExtensions(impression openrtb.Imp) (*adapters.ExtImpBidder, *openrtb
 	return &bidderExt, &consumableExt, nil
 }
 
-func getMediaTypeForImp(imp *openrtb.Imp) openrtb_ext.BidType {
-	// TODO: Whatever logic we need here possibly as follows - may always be Video when we bid
-	if imp.Banner != nil {
-		return openrtb_ext.BidTypeBanner
-	} else if imp.Video != nil {
-		return openrtb_ext.BidTypeVideo
-	}
-	return openrtb_ext.BidTypeVideo
-}
-
 func testConsumableBidder(testClock instant, endpoint string) *ConsumableAdapter {
 	return &ConsumableAdapter{testClock, endpoint}
 }
diff --git a/adapters/smartadserver/smartadserver.go b/adapters/smartadserver/smartadserver.go
new file mode 100644
index 00000000..c35b749c
--- /dev/null
+++ b/adapters/smartadserver/smartadserver.go
@@ -0,0 +1,179 @@
+package smartadserver
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/url"
+	"path"
+	"strconv"
+
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+type SmartAdserverAdapter struct {
+	host string
+}
+
+func NewSmartadserverBidder(host string) *SmartAdserverAdapter {
+	return &SmartAdserverAdapter{
+		host: host,
+	}
+}
+
+// MakeRequests makes the HTTP requests which should be made to fetch bids.
+func (a *SmartAdserverAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	if len(request.Imp) == 0 {
+		return nil, []error{&errortypes.BadInput{
+			Message: "No impression in the bid request",
+		}}
+	}
+
+	var adapterRequests []*adapters.RequestData
+	var errs []error
+
+	// We copy the original request.
+	smartRequest := *request
+
+	// We create or copy the Site object.
+	if smartRequest.Site == nil {
+		smartRequest.Site = &openrtb.Site{}
+	} else {
+		site := *smartRequest.Site
+		smartRequest.Site = &site
+	}
+
+	// We create or copy the Publisher object.
+	if smartRequest.Site.Publisher == nil {
+		smartRequest.Site.Publisher = &openrtb.Publisher{}
+	} else {
+		publisher := *smartRequest.Site.Publisher
+		smartRequest.Site.Publisher = &publisher
+	}
+
+	// We send one serialized "smartRequest" per impression of the original request.
+	for _, imp := range request.Imp {
+		var bidderExt adapters.ExtImpBidder
+		if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+			errs = append(errs, &errortypes.BadInput{
+				Message: "Error parsing bidderExt object",
+			})
+			continue
+		}
+
+		var smartadserverExt openrtb_ext.ExtImpSmartadserver
+		if err := json.Unmarshal(bidderExt.Bidder, &smartadserverExt); err != nil {
+			errs = append(errs, &errortypes.BadInput{
+				Message: "Error parsing smartadserverExt parameters",
+			})
+			continue
+		}
+
+		// Adding publisher id.
+		smartRequest.Site.Publisher.ID = strconv.Itoa(smartadserverExt.NetworkID)
+
+		// We send one request for each impression.
+		smartRequest.Imp = []openrtb.Imp{imp}
+
+		var errMarshal error
+		if imp.Ext, errMarshal = json.Marshal(smartadserverExt); errMarshal != nil {
+			errs = append(errs, &errortypes.BadInput{
+				Message: errMarshal.Error(),
+			})
+			continue
+		}
+
+		reqJSON, err := json.Marshal(smartRequest)
+		if err != nil {
+			errs = append(errs, &errortypes.BadInput{
+				Message: "Error parsing reqJSON object",
+			})
+			continue
+		}
+
+		url, err := a.BuildEndpointURL(&smartadserverExt)
+		if url == "" {
+			errs = append(errs, err)
+			continue
+		}
+
+		headers := http.Header{}
+		headers.Add("Content-Type", "application/json;charset=utf-8")
+		headers.Add("Accept", "application/json")
+		adapterRequests = append(adapterRequests, &adapters.RequestData{
+			Method:  "POST",
+			Uri:     url,
+			Body:    reqJSON,
+			Headers: headers,
+		})
+	}
+	return adapterRequests, errs
+}
+
+// MakeBids unpacks the server's response into Bids.
+func (a *SmartAdserverAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if response.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if response.StatusCode == http.StatusBadRequest {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}}
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Unexpected status code: " + strconv.Itoa(response.StatusCode) + ". Run with request.debug = 1 for more info",
+		}}
+	}
+
+	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]
+			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+				Bid:     &bid,
+				BidType: getMediaTypeForImp(bid.ImpID, internalRequest.Imp),
+			})
+
+		}
+	}
+	return bidResponse, []error{}
+}
+
+// BuildEndpointURL : Builds endpoint url
+func (a *SmartAdserverAdapter) BuildEndpointURL(params *openrtb_ext.ExtImpSmartadserver) (string, error) {
+	uri, err := url.Parse(a.host)
+	if err != nil || uri.Scheme == "" || uri.Host == "" {
+		return "", &errortypes.BadInput{
+			Message: "Malformed URL: " + a.host + ".",
+		}
+	}
+
+	uri.Path = path.Join(uri.Path, "api/bid")
+	uri.RawQuery = "callerId=5"
+
+	return uri.String(), nil
+}
+
+func getMediaTypeForImp(impID string, imps []openrtb.Imp) openrtb_ext.BidType {
+	for _, imp := range imps {
+		if imp.ID == impID {
+			if imp.Video != nil {
+				return openrtb_ext.BidTypeVideo
+			}
+			return openrtb_ext.BidTypeBanner
+		}
+	}
+	return openrtb_ext.BidTypeBanner
+}
diff --git a/adapters/smartadserver/usersync.go b/adapters/smartadserver/usersync.go
new file mode 100644
index 00000000..95b305ff
--- /dev/null
+++ b/adapters/smartadserver/usersync.go
@@ -0,0 +1,12 @@
+package smartadserver
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewSmartadserverSyncer(temp *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("smartadserver", 45, temp, adapters.SyncTypeRedirect)
+}
diff --git a/config/config.go b/config/config.go
index 07384f9d..c50118e2 100755
--- a/config/config.go
+++ b/config/config.go
@@ -49,6 +49,7 @@ type Configuration struct {
 	AMPTimeoutAdjustment int64              `mapstructure:"amp_timeout_adjustment_ms"`
 	GDPR                 GDPR               `mapstructure:"gdpr"`
 	CCPA                 CCPA               `mapstructure:"ccpa"`
+	LMT                  LMT                `mapstructure:"lmt"`
 	CurrencyConverter    CurrencyConverter  `mapstructure:"currency_converter"`
 	DefReqConfig         DefReqConfig       `mapstructure:"default_request"`
 
@@ -139,6 +140,13 @@ func (cfg *AuctionTimeouts) LimitAuctionTimeout(requested time.Duration) time.Du
 	return requested
 }
 
+// Privacy is a grouping of privacy related configs to assist in dependency injection.
+type Privacy struct {
+	CCPA CCPA
+	GDPR GDPR
+	LMT  LMT
+}
+
 type GDPR struct {
 	HostVendorID            int          `mapstructure:"host_vendor_id"`
 	UsersyncIfAmbiguous     bool         `mapstructure:"usersync_if_ambiguous"`
@@ -193,6 +201,10 @@ type CCPA struct {
 	Enforce bool `mapstructure:"enforce"`
 }
 
+type LMT struct {
+	Enforce bool `mapstructure:"enforce"`
+}
+
 type Analytics struct {
 	File FileLogs `mapstructure:"file"`
 }
@@ -555,6 +567,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdvangelists, "https://nep.advangelists.com/xp/user-sync?acctid={aid}&&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadvangelists%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAJA, "https://ad.as.amanad.adtdp.com/v1/sync/ssp?ssp=4&gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Daja%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%25s")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAppnexus, "https://ib.adnxs.com/getuid?"+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadnxs%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAvocet, "https://ads.avct.cloud/getuid?&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Davocet%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7B%7BUUID%7D%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeachfront, "https://sync.bfmio.com/sync_s2s?gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeachfront%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bio_cid%5D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeintoo, "https://ib.beintoo.com/um?ssp=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeintoo%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBrightroll, "https://pr-bh.ybp.yahoo.com/sync/appnexusprebidserver/?gdpr={{.GDPR}}&euconsent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbrightroll%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
@@ -587,6 +600,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	// openrtb_ext.BidderRTBHouse doesn't have a good default.
 	// openrtb_ext.BidderRubicon doesn't have a good default.
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSharethrough, "https://match.sharethrough.com/FGMrCMMc/v1?redirectUri="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsharethrough%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSmartadserver, "https://ssbsync.smartadserver.com/api/sync?callerId=5&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirectUri="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsmartadserver%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bssb_sync_pid%5D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSmartRTB, "https://market-global.smrtb.com/sync/all?nid=smartrtb&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&rr="+url.QueryEscape(externalURL)+"%252Fsetuid%253Fbidder%253Dsmartrtb%2526gdpr%253D{{.GDPR}}%2526gdpr_consent%253D{{.GDPRConsent}}%2526uid%253D%257BXID%257D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSomoaudience, "https://publisher-east.mobileadtrading.com/usersync?ru="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsomoaudience%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUID%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSonobi, "https://sync.go.sonobi.com/us.gif?loc="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsonobi%26consent_string%3D{{.GDPR}}%26gdpr%3D{{.GDPRConsent}}%26uid%3D%5BUID%5D")
@@ -760,6 +774,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.applogy.endpoint", "http://rtb.applogy.com/v1/prebid")
 	v.SetDefault("adapters.appnexus.endpoint", "http://ib.adnxs.com/openrtb2") // Docs: https://wiki.appnexus.com/display/supply/Incoming+Bid+Request+from+SSPs
 	v.SetDefault("adapters.appnexus.platform_id", "5")
+	v.SetDefault("adapters.avocet.disabled", true)
 	v.SetDefault("adapters.beachfront.endpoint", "https://display.bfmio.com/prebid_display")
 	v.SetDefault("adapters.beachfront.extra_info", "{\"video_endpoint\":\"https://reachms.bfmio.com/bid.json?exchange_id\"}")
 	v.SetDefault("adapters.beintoo.endpoint", "https://ib.beintoo.com/um")
@@ -796,6 +811,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.rtbhouse.endpoint", "http://prebidserver-s2s-ams.creativecdn.com/bidder/prebidserver/bids")
 	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.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")
 	v.SetDefault("adapters.sonobi.endpoint", "https://apex.go.sonobi.com/prebid?partnerid=71d9d3d8af")
@@ -805,7 +821,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.telaria.endpoint", "https://ads.tremorhub.com/ad/rtb/prebid")
 	v.SetDefault("adapters.triplelift_native.disabled", true)
 	v.SetDefault("adapters.triplelift_native.extra_info", "{\"publisher_whitelist\":[]}")
-	v.SetDefault("adapters.triplelift.endpoint", "https://tlx.3lift.com/s2s/auction?supplier_id=20")
+	v.SetDefault("adapters.triplelift.endpoint", "https://tlx.3lift.com/s2s/auction?sra=1&supplier_id=20")
 	v.SetDefault("adapters.ucfunnel.endpoint", "http://apac-hk-adx.aralego.com/prebid")
 	v.SetDefault("adapters.unruly.endpoint", "http://targeting.unrulymedia.com/openrtb/2.2")
 	v.SetDefault("adapters.valueimpression.endpoint", "https://rtb.valueimpression.com/endpoint")
@@ -836,6 +852,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("gdpr.tcf2.purpose_one_treatement.access_allowed", true)
 	v.SetDefault("gdpr.amp_exception", false)
 	v.SetDefault("ccpa.enforce", false)
+	v.SetDefault("lmt.enforce", true)
 	v.SetDefault("currency_converter.fetch_url", "https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json")
 	v.SetDefault("currency_converter.fetch_interval_seconds", 1800) // fetch currency rates every 30 minutes
 	v.SetDefault("default_request.type", "")
diff --git a/docs/bidders/avocet.md b/docs/bidders/avocet.md
new file mode 100644
index 00000000..6aa67391
--- /dev/null
+++ b/docs/bidders/avocet.md
@@ -0,0 +1,5 @@
+# Avocet Bidder
+
+Please contact Avocet at info@avocet.io if you would like to get started selling inventory via the Avocet platform.
+
+**Note:** Avocet is disabled by default. Please enable it in the app config if you wish to use it. This can be done by setting `adapters.avocet.disabled` to `false` and by setting `adapters.avocet.endpoint` to a valid Avocet endpoint url.
\ No newline at end of file
diff --git a/docs/bidders/smartAdserver.md b/docs/bidders/smartAdserver.md
new file mode 100644
index 00000000..4d2663f8
--- /dev/null
+++ b/docs/bidders/smartAdserver.md
@@ -0,0 +1,59 @@
+# Smart Adserver Bidder
+
+## Parameters
+The `ext.smartadserver` object of impression bid requests supports the following parameters :
+- "networkId" - Required. The network identifier you have been provided with.
+- "siteId" - Optional. The site identifier from your campaign configuration.
+- "pageId" - Optional. The page identifier from your campaign configuration.
+- "formatId" - Optional. The format identifier from your campaign configuration.
+
+The network identifier is provided by your Account Manager.
+**Note:** The site, page and format identifiers have to all be provided or all empty.
+
+## Examples
+
+Without site/page/format : 
+```
+	"imp": [{
+		"id": "some-impression-id",
+		"banner": {
+			"format": [{
+				"w": 600,
+				"h": 500
+			}, {
+				"w": 300,
+				"h": 600
+			}]
+		},
+		"ext": {
+			"smartadserver": {
+				"networkId": 73
+			}
+		}
+	}]
+```
+
+With site/page/format : 
+
+```
+	"imp": [{
+		"id": "some-impression-id",
+		"banner": {
+			"format": [{
+				"w": 600,
+				"h": 500
+			}, {
+				"w": 300,
+				"h": 600
+			}]
+		},
+		"ext": {
+			"smartadserver": {
+                "networkId": 73
+                "siteId": 1,
+                "pageId": 2,
+                "formatId": 3
+			}
+		}
+	}]
+```
\ No newline at end of file
diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go
index 586481dd..2dcd572c 100644
--- a/endpoints/openrtb2/amp_auction.go
+++ b/endpoints/openrtb2/amp_auction.go
@@ -407,31 +407,34 @@ func (deps *endpointDeps) overrideWithParams(httpRequest *http.Request, req *ope
 }
 
 func makeFormatReplacement(overrideWidth uint64, overrideHeight uint64, width uint64, height uint64, multisize string) []openrtb.Format {
+	var formats []openrtb.Format
 	if overrideWidth != 0 && overrideHeight != 0 {
-		return []openrtb.Format{{
+		formats = []openrtb.Format{{
 			W: overrideWidth,
 			H: overrideHeight,
 		}}
 	} else if overrideWidth != 0 && height != 0 {
-		return []openrtb.Format{{
+		formats = []openrtb.Format{{
 			W: overrideWidth,
 			H: height,
 		}}
 	} else if width != 0 && overrideHeight != 0 {
-		return []openrtb.Format{{
+		formats = []openrtb.Format{{
 			W: width,
 			H: overrideHeight,
 		}}
-	} else if parsedSizes := parseMultisize(multisize); len(parsedSizes) != 0 {
-		return parsedSizes
 	} else if width != 0 && height != 0 {
-		return []openrtb.Format{{
+		formats = []openrtb.Format{{
 			W: width,
 			H: height,
 		}}
 	}
 
-	return nil
+	if parsedSizes := parseMultisize(multisize); len(parsedSizes) != 0 {
+		formats = append(formats, parsedSizes...)
+	}
+
+	return formats
 }
 
 func setWidths(formats []openrtb.Format, width uint64) {
diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go
index 2ea8f7fb..44054df0 100755
--- a/exchange/adapter_map.go
+++ b/exchange/adapter_map.go
@@ -25,6 +25,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/applogy"
 	"github.com/prebid/prebid-server/adapters/appnexus"
 	"github.com/prebid/prebid-server/adapters/audienceNetwork"
+	"github.com/prebid/prebid-server/adapters/avocet"
 	"github.com/prebid/prebid-server/adapters/beachfront"
 	"github.com/prebid/prebid-server/adapters/beintoo"
 	"github.com/prebid/prebid-server/adapters/brightroll"
@@ -61,6 +62,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/smartadserver"
 	"github.com/prebid/prebid-server/adapters/smartrtb"
 	"github.com/prebid/prebid-server/adapters/somoaudience"
 	"github.com/prebid/prebid-server/adapters/sonobi"
@@ -106,6 +108,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter
 		openrtb_ext.BidderAJA:          aja.NewAJABidder(cfg.Adapters[string(openrtb_ext.BidderAJA)].Endpoint),
 		openrtb_ext.BidderApplogy:      applogy.NewApplogyBidder(cfg.Adapters[string(openrtb_ext.BidderApplogy)].Endpoint),
 		openrtb_ext.BidderAppnexus:     appnexus.NewAppNexusBidder(client, cfg.Adapters[string(openrtb_ext.BidderAppnexus)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderAppnexus)].PlatformID),
+		openrtb_ext.BidderAvocet:       avocet.NewAvocetAdapter(cfg.Adapters[string(openrtb_ext.BidderAvocet)].Endpoint),
 		openrtb_ext.BidderBeachfront:   beachfront.NewBeachfrontBidder(cfg.Adapters[string(openrtb_ext.BidderBeachfront)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderBeachfront)].ExtraAdapterInfo),
 		openrtb_ext.BidderBeintoo:      beintoo.NewBeintooBidder(cfg.Adapters[string(openrtb_ext.BidderBeintoo)].Endpoint),
 		openrtb_ext.BidderBrightroll:   brightroll.NewBrightrollBidder(cfg.Adapters[string(openrtb_ext.BidderBrightroll)].Endpoint),
@@ -148,6 +151,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.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),
 		openrtb_ext.BidderSonobi:           sonobi.NewSonobiBidder(client, cfg.Adapters[string(openrtb_ext.BidderSonobi)].Endpoint),
diff --git a/exchange/bidder.go b/exchange/bidder.go
index f9b4a522..df9f0a3b 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -389,7 +389,20 @@ func (bidder *bidderAdapter) doTimeoutNotification(timeoutBidder adapters.Timeou
 			}
 		} else {
 			bidder.me.RecordTimeoutNotice(false)
+			if bidder.DebugConfig.TimeoutNotification.Log {
+				msg := fmt.Sprintf("TimeoutNotification: Failed to make timeout request: method(%s), uri(%s), error(%s)", toReq.Method, toReq.Uri, err.Error())
+				util.LogRandomSample(msg, glog.Warningf, bidder.DebugConfig.TimeoutNotification.SamplingRate)
+			}
+		}
+	} else if bidder.DebugConfig.TimeoutNotification.Log {
+		reqJSON, err := json.Marshal(req)
+		var msg string
+		if err == nil {
+			msg = fmt.Sprintf("TimeoutNotification: Failed to generate timeout request: error(%s), bidder request(%s)", errL[0].Error(), string(reqJSON))
+		} else {
+			msg = fmt.Sprintf("TimeoutNotification: Failed to generate timeout request: error(%s), bidder request marshal failed(%s)", errL[0].Error(), err.Error())
 		}
+		util.LogRandomSample(msg, glog.Warningf, bidder.DebugConfig.TimeoutNotification.SamplingRate)
 	}
 
 }
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 660beb64..d7eab0f4 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -48,7 +48,7 @@ type exchange struct {
 	currencyConverter   *currencies.RateConverter
 	UsersyncIfAmbiguous bool
 	defaultTTLs         config.DefaultTTLs
-	enforceCCPA         bool
+	privacyConfig       config.Privacy
 }
 
 // Container to pass out response ext data from the GetAllBids goroutines back into the main thread
@@ -77,7 +77,11 @@ func NewExchange(client *http.Client, cache prebid_cache_client.Client, cfg *con
 	e.currencyConverter = currencyConverter
 	e.UsersyncIfAmbiguous = cfg.GDPR.UsersyncIfAmbiguous
 	e.defaultTTLs = cfg.CacheURL.DefaultTTLs
-	e.enforceCCPA = cfg.CCPA.Enforce
+	e.privacyConfig = config.Privacy{
+		CCPA: cfg.CCPA,
+		GDPR: cfg.GDPR,
+		LMT:  cfg.LMT,
+	}
 	return e
 }
 
@@ -100,7 +104,7 @@ 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, errs := cleanOpenRTBRequests(ctx, bidRequest, usersyncs, blabels, labels, e.gDPR, e.UsersyncIfAmbiguous, e.enforceCCPA)
+	cleanRequests, aliases, errs := cleanOpenRTBRequests(ctx, bidRequest, usersyncs, blabels, labels, e.gDPR, e.UsersyncIfAmbiguous, e.privacyConfig)
 
 	// List of bidders we have requests for.
 	liveAdapters := listBiddersWithRequests(cleanRequests)
@@ -299,7 +303,7 @@ func (e *exchange) getAllBids(ctx context.Context, cleanRequests map[openrtb_ext
 	for bidderName, req := range cleanRequests {
 		// Here we actually call the adapters and collect the bids.
 		coreBidder := resolveBidder(string(bidderName), aliases)
-		bidderRunner := e.recoverSafely(func(aName openrtb_ext.BidderName, coreBidder openrtb_ext.BidderName, request *openrtb.BidRequest, bidlabels *pbsmetrics.AdapterLabels, conversions currencies.Conversions) {
+		bidderRunner := e.recoverSafely(cleanRequests, func(aName openrtb_ext.BidderName, coreBidder openrtb_ext.BidderName, request *openrtb.BidRequest, bidlabels *pbsmetrics.AdapterLabels, conversions currencies.Conversions) {
 			// Passing in aName so a doesn't change out from under the go routine
 			if bidlabels.Adapter == "" {
 				glog.Errorf("Exchange: bidlables for %s (%s) missing adapter string", aName, coreBidder)
@@ -369,11 +373,24 @@ func (e *exchange) getAllBids(ctx context.Context, cleanRequests map[openrtb_ext
 	return adapterBids, adapterExtra, bidsFound
 }
 
-func (e *exchange) recoverSafely(inner func(openrtb_ext.BidderName, openrtb_ext.BidderName, *openrtb.BidRequest, *pbsmetrics.AdapterLabels, currencies.Conversions), chBids chan *bidResponseWrapper) func(openrtb_ext.BidderName, openrtb_ext.BidderName, *openrtb.BidRequest, *pbsmetrics.AdapterLabels, currencies.Conversions) {
+func (e *exchange) recoverSafely(cleanRequests map[openrtb_ext.BidderName]*openrtb.BidRequest, inner func(openrtb_ext.BidderName, openrtb_ext.BidderName, *openrtb.BidRequest, *pbsmetrics.AdapterLabels, currencies.Conversions), chBids chan *bidResponseWrapper) func(openrtb_ext.BidderName, openrtb_ext.BidderName, *openrtb.BidRequest, *pbsmetrics.AdapterLabels, currencies.Conversions) {
 	return func(aName openrtb_ext.BidderName, coreBidder openrtb_ext.BidderName, request *openrtb.BidRequest, bidlabels *pbsmetrics.AdapterLabels, conversions currencies.Conversions) {
 		defer func() {
 			if r := recover(); r != nil {
-				glog.Errorf("OpenRTB auction recovered panic from Bidder %s: %v. Stack trace is: %v", coreBidder, r, string(debug.Stack()))
+
+				allBidders := ""
+				sb := strings.Builder{}
+				for k := range cleanRequests {
+					sb.WriteString(string(k))
+					sb.WriteString(",")
+				}
+				if sb.Len() > 0 {
+					allBidders = sb.String()[:sb.Len()-1]
+				}
+
+				glog.Errorf("OpenRTB auction recovered panic from Bidder %s: %v. "+
+					"Account id: %s, All Bidders: %s, Stack trace is: %v",
+					coreBidder, r, bidlabels.PubID, allBidders, string(debug.Stack()))
 				e.me.RecordAdapterPanic(*bidlabels)
 				// Let the master request know that there is no data here
 				brw := new(bidResponseWrapper)
diff --git a/exchange/utils.go b/exchange/utils.go
index f602d1e8..54122d13 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -8,11 +8,13 @@ import (
 
 	"github.com/buger/jsonparser"
 	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/gdpr"
 	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/prebid/prebid-server/pbsmetrics"
 	"github.com/prebid/prebid-server/privacy"
 	"github.com/prebid/prebid-server/privacy/ccpa"
+	"github.com/prebid/prebid-server/privacy/lmt"
 )
 
 // cleanOpenRTBRequests splits the input request into requests which are sanitized for each bidder. Intended behavior is:
@@ -26,8 +28,8 @@ func cleanOpenRTBRequests(ctx context.Context,
 	blables map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels,
 	labels pbsmetrics.Labels,
 	gDPR gdpr.Permissions,
-	usersyncIfAmbiguous,
-	enforceCCPA bool) (requestsByBidder map[openrtb_ext.BidderName]*openrtb.BidRequest, aliases map[string]string, errs []error) {
+	usersyncIfAmbiguous bool,
+	privacyConfig config.Privacy) (requestsByBidder map[openrtb_ext.BidderName]*openrtb.BidRequest, aliases map[string]string, errs []error) {
 
 	impsByBidder, errs := splitImps(orig.Imp)
 	if len(errs) > 0 {
@@ -45,15 +47,24 @@ func cleanOpenRTBRequests(ctx context.Context,
 	consent := extractConsent(orig)
 	ampGDPRException := (labels.RType == pbsmetrics.ReqTypeAMP) && gDPR.AMPException()
 
-	privacyEnforcement := privacy.Enforcement{
-		COPPA: orig.Regs != nil && orig.Regs.COPPA == 1,
+	var ccpaPolicy ccpa.Policy
+	if privacyConfig.CCPA.Enforce {
+		ccpaPolicy, _ = ccpa.ReadPolicy(orig)
+	}
+
+	var lmtPolicy lmt.Policy
+	if privacyConfig.LMT.Enforce {
+		lmtPolicy = lmt.ReadPolicy(orig)
 	}
 
-	if enforceCCPA {
-		ccpaPolicy, _ := ccpa.ReadPolicy(orig)
-		privacyEnforcement.CCPA = ccpaPolicy.ShouldEnforce()
+	// request level privacy policies
+	privacyEnforcement := privacy.Enforcement{
+		CCPA:  ccpaPolicy.ShouldEnforce(),
+		COPPA: orig.Regs != nil && orig.Regs.COPPA == 1,
+		LMT:   lmtPolicy.ShouldEnforce(),
 	}
 
+	// bidder level privacy policies
 	for bidder, bidReq := range requestsByBidder {
 
 		if gdpr == 1 {
diff --git a/go.mod b/go.mod
index 0224057e..72bb9b74 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/prebid/prebid-server
 
-go 1.12
+go 1.13
 
 require (
 	github.com/BurntSushi/toml v0.3.1 // indirect
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 659c6616..1f9cffb9 100755
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -40,6 +40,7 @@ const (
 	BidderApplogy          BidderName = "applogy"
 	BidderAppnexus         BidderName = "appnexus"
 	BidderAdoppler         BidderName = "adoppler"
+	BidderAvocet           BidderName = "avocet"
 	BidderBeachfront       BidderName = "beachfront"
 	BidderBeintoo          BidderName = "beintoo"
 	BidderBrightroll       BidderName = "brightroll"
@@ -77,6 +78,7 @@ const (
 	BidderRTBHouse         BidderName = "rtbhouse"
 	BidderRubicon          BidderName = "rubicon"
 	BidderSharethrough     BidderName = "sharethrough"
+	BidderSmartadserver    BidderName = "smartadserver"
 	BidderSmartRTB         BidderName = "smartrtb"
 	BidderSomoaudience     BidderName = "somoaudience"
 	BidderSonobi           BidderName = "sonobi"
@@ -118,6 +120,7 @@ var BidderMap = map[string]BidderName{
 	"applogy":           BidderApplogy,
 	"appnexus":          BidderAppnexus,
 	"adoppler":          BidderAdoppler,
+	"avocet":            BidderAvocet,
 	"beachfront":        BidderBeachfront,
 	"beintoo":           BidderBeintoo,
 	"brightroll":        BidderBrightroll,
@@ -155,6 +158,7 @@ var BidderMap = map[string]BidderName{
 	"rtbhouse":          BidderRTBHouse,
 	"rubicon":           BidderRubicon,
 	"sharethrough":      BidderSharethrough,
+	"smartadserver":     BidderSmartadserver,
 	"smartrtb":          BidderSmartRTB,
 	"somoaudience":      BidderSomoaudience,
 	"sonobi":            BidderSonobi,
diff --git a/openrtb_ext/imp_avocet.go b/openrtb_ext/imp_avocet.go
new file mode 100644
index 00000000..7c9ca8c6
--- /dev/null
+++ b/openrtb_ext/imp_avocet.go
@@ -0,0 +1,7 @@
+package openrtb_ext
+
+// ExtImpAvocet defines the contract for bidrequest.imp[i].ext.avocet
+type ExtImpAvocet struct {
+	Placement     string `json:"placement,omitempty"`
+	PlacementCode string `json:"placement_code,omitempty"`
+}
diff --git a/openrtb_ext/imp_smartadserver.go b/openrtb_ext/imp_smartadserver.go
new file mode 100644
index 00000000..d542e0ff
--- /dev/null
+++ b/openrtb_ext/imp_smartadserver.go
@@ -0,0 +1,9 @@
+package openrtb_ext
+
+// ExtImpSmartadserver defines the contract for bidrequest.imp[i].ext.smartadserver
+type ExtImpSmartadserver struct {
+	SiteID    int `json:"siteId"`
+	PageID    int `json:"pageId"`
+	FormatID  int `json:"formatId"`
+	NetworkID int `json:"networkId"`
+}
diff --git a/privacy/enforcement.go b/privacy/enforcement.go
index d302192e..8a5d201f 100644
--- a/privacy/enforcement.go
+++ b/privacy/enforcement.go
@@ -10,11 +10,12 @@ type Enforcement struct {
 	COPPA   bool
 	GDPR    bool
 	GDPRGeo bool
+	LMT     bool
 }
 
 // Any returns true if at least one privacy policy requires enforcement.
 func (e Enforcement) Any() bool {
-	return e.CCPA || e.COPPA || e.GDPR || e.GDPRGeo
+	return e.CCPA || e.COPPA || e.GDPR || e.GDPRGeo || e.LMT
 }
 
 // Apply cleans personally identifiable information from an OpenRTB bid request.
@@ -34,7 +35,7 @@ func (e Enforcement) getIPv6ScrubStrategy() ScrubStrategyIPV6 {
 		return ScrubStrategyIPV6Lowest32
 	}
 
-	if e.GDPR || e.CCPA {
+	if e.GDPR || e.CCPA || e.LMT {
 		return ScrubStrategyIPV6Lowest16
 	}
 
@@ -46,7 +47,7 @@ func (e Enforcement) getGeoScrubStrategy() ScrubStrategyGeo {
 		return ScrubStrategyGeoFull
 	}
 
-	if e.GDPRGeo || e.CCPA {
+	if e.GDPRGeo || e.CCPA || e.LMT {
 		return ScrubStrategyGeoReducedPrecision
 	}
 
@@ -63,7 +64,7 @@ func (e Enforcement) getUserScrubStrategy(ampGDPRException bool) ScrubStrategyUs
 	}
 
 	// If no user scrubbing is needed, then return none, else scrub ID (COPPA checked above)
-	if e.CCPA || e.GDPR {
+	if e.CCPA || e.GDPR || e.LMT {
 		return ScrubStrategyUserID
 	}
 
diff --git a/privacy/lmt/policy.go b/privacy/lmt/policy.go
new file mode 100644
index 00000000..79425bf5
--- /dev/null
+++ b/privacy/lmt/policy.go
@@ -0,0 +1,33 @@
+package lmt
+
+import (
+	"github.com/mxmCherry/openrtb"
+)
+
+const (
+	trackingUnrestricted = 0
+	trackingRestricted   = 1
+)
+
+// Policy represents the LMT (Limit Ad Tracking) policy for an OpenRTB bid request.
+type Policy struct {
+	Signal         int
+	SignalProvided bool
+}
+
+// ReadPolicy extracts the LMT (Limit Ad Tracking) policy from an OpenRTB bid request.
+func ReadPolicy(req *openrtb.BidRequest) Policy {
+	policy := Policy{}
+
+	if req != nil && req.Device != nil && req.Device.Lmt != nil {
+		policy.Signal = int(*req.Device.Lmt)
+		policy.SignalProvided = true
+	}
+
+	return policy
+}
+
+// ShouldEnforce returns true when the LMT (Limit Ad Tracking) policy is in effect.
+func (p Policy) ShouldEnforce() bool {
+	return p.SignalProvided && p.Signal == trackingRestricted
+}
diff --git a/static/adapter/appnexus/opts.json b/static/adapter/appnexus/opts.json
index 7bb297e0..41ee3c8f 100644
--- a/static/adapter/appnexus/opts.json
+++ b/static/adapter/appnexus/opts.json
@@ -5,13 +5,14 @@
     "3": "IAB10-1",
     "4": "IAB2-3",
     "5": "IAB19-8",
+    "6": "IAB22-1",
     "7": "IAB18-1",
-    "8": "IAB14-1",
+    "8": "IAB12-3",
     "9": "IAB5-1",
     "10": "IAB4-5",
     "11": "IAB13-4",
-    "13": "IAB19-2",
     "12": "IAB8-7",
+    "13": "IAB9-7",
     "14": "IAB7-1",
     "15": "IAB20-18",
     "16": "IAB10-7",
@@ -20,33 +21,79 @@
     "19": "IAB18-4",
     "20": "IAB1-5",
     "21": "IAB1-6",
-    "22": "IAB19-28",
+    "22": "IAB3-4",
     "23": "IAB19-13",
     "24": "IAB22-2",
     "25": "IAB3-9",
-    "26": "IAB17-26",
+    "26": "IAB17-18",
     "27": "IAB19-6",
     "28": "IAB1-7",
-    "29": "IAB9-5",
+    "29": "IAB9-30",
     "30": "IAB20-7",
     "31": "IAB20-17",
     "32": "IAB7-32",
     "33": "IAB16-5",
     "34": "IAB19-34",
+    "35": "IAB11-5",
+    "36": "IAB12-3",
     "37": "IAB11-4",
+    "38": "IAB12-3",
     "39": "IAB9-30",
     "41": "IAB7-44",
+    "42": "IAB7-1",
+    "43": "IAB7-30",
+    "50": "IAB19-30",
     "51": "IAB17-12",
+    "52": "IAB19-30",
     "53": "IAB3-1",
     "55": "IAB13-2",
+    "56": "IAB19-30",
+    "57": "IAB19-30",
+    "58": "IAB7-39",
+    "59": "IAB22-1",
+    "60": "IAB7-39",
     "61": "IAB21-3",
-    "62": "IAB6-4",
-    "63": "IAB15-10",
+    "62": "IAB5-1",
+    "63": "IAB12-3",
+    "64": "IAB20-18",
     "65": "IAB11-2",
+    "66": "IAB17-18",
     "67": "IAB9-9",
-    "69": "IAB7-1",
-    "71": "IAB22-2",
+    "68": "IAB9-5",
+    "69": "IAB7-44",
+    "71": "IAB22-3",
+    "73": "IAB19-30",
     "74": "IAB8-5",
-    "87": "IAB3-7"
-  }
+    "78": "IAB22-1",
+    "85": "IAB12-2",
+    "86": "IAB22-3",
+    "87": "IAB11-3",
+    "112": "IAB7-32",
+    "113": "IAB7-32",
+    "114": "IAB7-32",
+    "115": "IAB7-32",
+    "118": "IAB9-5",
+    "119": "IAB9-5",
+    "120": "IAB9-5",
+    "121": "IAB9-5",
+    "122": "IAB9-5",
+    "123": "IAB9-5",
+    "124": "IAB9-5",
+    "125": "IAB9-5",
+    "126": "IAB9-5",
+    "127": "IAB22-1",
+    "132": "IAB1-2",
+    "133": "IAB19-30",
+    "137": "IAB3-9",
+    "138": "IAB19-3",
+    "140": "IAB2-3",
+    "141": "IAB2-1",
+    "142": "IAB2-3",
+    "143": "IAB17-13",
+    "166": "IAB11-4",
+    "175": "IAB3-1",
+    "176": "IAB13-4",
+    "182": "IAB8-9",
+    "183": "IAB3-5"
+    }
 }
diff --git a/static/bidder-info/avocet.yaml b/static/bidder-info/avocet.yaml
new file mode 100644
index 00000000..ea98982d
--- /dev/null
+++ b/static/bidder-info/avocet.yaml
@@ -0,0 +1,11 @@
+maintainer:
+  email: "developers@avocet.io"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video
diff --git a/static/bidder-info/smartadserver.yaml b/static/bidder-info/smartadserver.yaml
new file mode 100644
index 00000000..626b7dac
--- /dev/null
+++ b/static/bidder-info/smartadserver.yaml
@@ -0,0 +1,11 @@
+maintainer:
+  email: "support@smartadserver.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video
diff --git a/static/bidder-params/avocet.json b/static/bidder-params/avocet.json
new file mode 100644
index 00000000..f27e5950
--- /dev/null
+++ b/static/bidder-params/avocet.json
@@ -0,0 +1,24 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Avocet Adapter Params",
+  "description": "A schema which validates params accepted by the Avocet adapter",
+  "type": "object",
+  "properties": {
+    "placement": {
+      "type": "string",
+      "description": "An Avocet placement ID"
+    },
+    "placement_code": {
+      "type": "string",
+      "description": "An Avocet placement external code"
+    }
+  },
+  "oneOf": [
+    {
+      "required": ["placement"]
+    },
+    {
+      "required": ["placement_code"]
+    }
+  ]
+}
diff --git a/static/bidder-params/smartadserver.json b/static/bidder-params/smartadserver.json
new file mode 100644
index 00000000..b76a3bd6
--- /dev/null
+++ b/static/bidder-params/smartadserver.json
@@ -0,0 +1,35 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Smartadserver Adapter Params",
+  "description": "A schema which validates params accepted by the Smartadserver adapter",
+
+  "type": "object",
+  "properties": {
+    "siteId": {
+      "type": "integer",
+      "description": "The site id.",
+      "minimum": 1
+    },
+    "pageId": {
+      "type": "integer",
+      "description": "The page id.",
+      "minimum": 1
+    },
+    "formatId": {
+      "type": "integer",
+      "description": "The format id.",
+      "minimum": 1
+    },
+    "networkId": {
+      "type": "integer",
+      "description": "The network id.",
+      "minimum": 1
+    }
+  },
+  "dependencies": {
+    "siteId": { "required": ["pageId", "formatId"] },
+    "pageId": { "required": ["siteId", "formatId"] },
+    "formatId": { "required": ["siteId", "pageId"] }
+  },
+  "required": ["networkId"]
+}
\ No newline at end of file
diff --git a/static/category-mapping/freewheel/freewheel.json b/static/category-mapping/freewheel/freewheel.json
index 7eebcce0..1c4a4fa2 100644
--- a/static/category-mapping/freewheel/freewheel.json
+++ b/static/category-mapping/freewheel/freewheel.json
@@ -3,1176 +3,1180 @@
     "id": "404",
     "name": "Publishing"
   },
-  "IAB1-2": {
-    "id": "392",
-    "name": "Entertainment"
-  },
-  "IAB1-5": {
-    "id": "419",
-    "name": "Filmed Entertainment"
-  },
-  "IAB1-6": {
-    "id": "392",
-    "name": "Entertainment"
-  },
-  "IAB1-7": {
-    "id": "392",
-    "name": "Entertainment"
-  },
-  "IAB2-1": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-2": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-3": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-4": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-5": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-6": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-7": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-8": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-9": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-10": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-11": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-12": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-13": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-14": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-15": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-16": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-17": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-18": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-19": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-20": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-21": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-22": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB2-23": {
-    "id": "399",
-    "name": "Automotive"
-  },
-  "IAB3-1": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB3-2": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB3-3": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB3-4": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB3-5": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB3-6": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB3-7": {
-    "id": "398",
-    "name": "Government/Municipal"
-  },
-  "IAB3-8": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB3-9": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB3-10": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB3-11": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB3-12": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB4-1": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB4-2": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB4-3": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB4-4": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB4-5": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB4-6": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB4-7": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB4-8": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB4-9": {
-    "id": "417",
-    "name": "Telecommunications"
-  },
-  "IAB4-10": {
-    "id": "429",
-    "name": "Military"
-  },
-  "IAB4-11": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB5-1": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-2": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-3": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-4": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-5": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-6": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-7": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-8": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-9": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-10": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-11": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-12": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-13": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-14": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB5-15": {
-    "id": "405",
-    "name": "Educational Services"
-  },
-  "IAB7-1": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-2": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-3": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-4": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-5": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-6": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-7": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-8": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-9": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-10": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-11": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-12": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-13": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-14": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-15": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-16": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-17": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-18": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-19": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-20": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-21": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-22": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-23": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-24": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-25": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-26": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-27": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-28": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-29": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-30": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-31": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-32": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-33": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-34": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-35": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-36": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-37": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-38": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-39": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-40": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-41": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-42": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-43": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-44": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB7-45": {
-    "id": "406",
-    "name": "Health Care Services"
-  },
-  "IAB8-1": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-2": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-3": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-4": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-5": {
-    "id": "400",
-    "name": "Beer/Wine/Liquor"
-  },
-  "IAB8-6": {
-    "id": "401",
-    "name": "Beverages"
-  },
-  "IAB8-7": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-8": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-9": {
-    "id": "407",
-    "name": "Restaurant/Fast Food"
-  },
-  "IAB8-10": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-11": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-12": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-13": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-14": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-15": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-16": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-17": {
-    "id": "394",
-    "name": "Food"
-  },
-  "IAB8-18": {
-    "id": "400",
-    "name": "Beer/Wine/Liquor"
-  },
-  "IAB9-1": {
-    "id": "392",
-    "name": "Entertainment"
-  },
-  "IAB9-3": {
-    "id": "418",
-    "name": "Jewelry"
-  },
-  "IAB9-5": {
-    "id": "413",
-    "name": "Gaming"
-  },
-  "IAB9-6": {
-    "id": "412",
-    "name": "Household Products"
-  },
-  "IAB9-9": {
-    "id": "426",
-    "name": "Tobacco"
-  },
-  "IAB9-11": {
-    "id": "404",
-    "name": "Publishing"
-  },
-  "IAB9-15": {
-    "id": "404",
-    "name": "Publishing"
-  },
-  "IAB9-16": {
-    "id": "392",
-    "name": "Entertainment"
-  },
-  "IAB9-18": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB9-19": {
-    "id": "418",
-    "name": "Jewelry"
-  },
-  "IAB9-23": {
-    "id": "424",
-    "name": "Photographic Equipment"
-  },
-  "IAB9-24": {
-    "id": "392",
-    "name": "Entertainment"
-  },
-  "IAB9-25": {
-    "id": "392",
-    "name": "Entertainment"
-  },
-  "IAB9-30": {
-    "id": "413",
-    "name": "Gaming"
-  },
-  "IAB10-1": {
-    "id": "415",
-    "name": "Appliances"
-  },
-  "IAB10-5": {
-    "id": "434",
-    "name": "Home Furnishings"
-  },
-  "IAB10-6": {
-    "id": "434",
-    "name": "Home Furnishings"
-  },
-  "IAB10-7": {
-    "id": "434",
-    "name": "Home Furnishings"
-  },
-  "IAB10-8": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB10-9": {
-    "id": "434",
-    "name": "Home Furnishings"
-  },
-  "IAB11-1": {
-    "id": "398",
-    "name": "Government/Municipal"
-  },
-  "IAB11-2": {
-    "id": "398",
-    "name": "Government/Municipal"
-  },
-  "IAB11-3": {
-    "id": "398",
-    "name": "Government/Municipal"
-  },
-  "IAB11-4": {
-    "id": "398",
-    "name": "Government/Municipal"
-  },
-  "IAB11-5": {
-    "id": "398",
-    "name": "Government/Municipal"
-  },
-  "IAB12-1": {
-    "id": "438",
-    "name": "News"
-  },
-  "IAB12-2": {
-    "id": "438",
-    "name": "News"
-  },
-  "IAB12-3": {
-    "id": "438",
-    "name": "News"
-  },
-  "IAB13-1": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB13-2": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB13-3": {
-    "id": "438",
-    "name": "News"
-  },
-  "IAB13-4": {
-    "id": "391",
-    "name": "Financial Services"
-  },
-  "IAB13-5": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB13-6": {
-    "id": "436",
-    "name": "Insurance"
-  },
-  "IAB13-7": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB13-8": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB13-9": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB13-10": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB13-11": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB13-12": {
-    "id": "393",
-    "name": "Business Services"
-  },
-  "IAB16-1": {
-    "id": "423",
-    "name": "Pet Food/Supplies"
-  },
-  "IAB16-2": {
-    "id": "423",
-    "name": "Pet Food/Supplies"
-  },
-  "IAB16-3": {
-    "id": "423",
-    "name": "Pet Food/Supplies"
-  },
-  "IAB16-4": {
-    "id": "423",
-    "name": "Pet Food/Supplies"
-  },
-  "IAB16-5": {
-    "id": "423",
-    "name": "Pet Food/Supplies"
-  },
-  "IAB16-6": {
-    "id": "423",
-    "name": "Pet Food/Supplies"
-  },
-  "IAB16-7": {
-    "id": "423",
-    "name": "Pet Food/Supplies"
-  },
-  "IAB17-1": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-2": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-3": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-4": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-5": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-6": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-7": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-8": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-9": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-10": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-11": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-12": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-13": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-14": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-15": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-16": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-17": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-18": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-19": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-20": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-21": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-22": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-23": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-24": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-25": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-26": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-27": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-28": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-29": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-30": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-31": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-32": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-33": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-34": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-35": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-36": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-37": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-38": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-39": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-40": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-41": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-42": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-43": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB17-44": {
-    "id": "425",
-    "name": "Professional Sports"
-  },
-  "IAB18-1": {
-    "id": "411",
-    "name": "Cosmetics/Toiletries"
-  },
-  "IAB18-2": {
-    "id": "397",
-    "name": "Apparel"
-  },
-  "IAB18-3": {
-    "id": "397",
-    "name": "Apparel"
-  },
-  "IAB18-4": {
-    "id": "418",
-    "name": "Jewelry"
-  },
-  "IAB18-5": {
-    "id": "397",
-    "name": "Apparel"
-  },
-  "IAB18-6": {
-    "id": "397",
-    "name": "Apparel"
-  },
-  "IAB19-2": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-3": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-4": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-5": {
-    "id": "424",
-    "name": "Photographic Equipment"
-  },
-  "IAB19-6": {
-    "id": "417",
-    "name": "Telecommunications"
-  },
-  "IAB19-7": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-8": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-9": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-10": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-11": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-12": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-13": {
-    "id": "404",
-    "name": "Publishing"
-  },
-  "IAB19-14": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-15": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-16": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-17": {
-    "id": "419",
-    "name": "Filmed Entertainment"
-  },
-  "IAB19-18": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-19": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-20": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-21": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-22": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-23": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-24": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-25": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-26": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-27": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-28": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-29": {
-    "id": "392",
-    "name": "Entertainment"
-  },
-  "IAB19-30": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-31": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-32": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-33": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-34": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-35": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB19-36": {
-    "id": "409",
-    "name": "Computing Product"
-  },
-  "IAB20-1": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-2": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-3": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-4": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-5": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-6": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-7": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-8": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-9": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-10": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-11": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-12": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-13": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-14": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-15": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-16": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-17": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-18": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-19": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-20": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-21": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-22": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-23": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-24": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-25": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-26": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB20-27": {
-    "id": "395",
-    "name": "Travel/Hotels/Airlines"
-  },
-  "IAB21-1": {
-    "id": "416",
-    "name": "Real Estate"
-  },
-  "IAB21-2": {
-    "id": "416",
-    "name": "Real Estate"
-  },
-  "IAB21-3": {
-    "id": "416",
-    "name": "Real Estate"
-  },
-  "IAB22-1": {
-    "id": "416",
-    "name": "Real Estate"
-  },
-  "IAB22-2": {
-    "id": "416",
-    "name": "Real Estate"
-  },
-  "IAB22-3": {
-    "id": "416",
-    "name": "Real Estate"
-  }
+	"IAB1-2": {
+		"id": "392",
+		"name": "Entertainment"
+	},
+	"IAB1-5": {
+		"id": "419",
+		"name": "Filmed Entertainment"
+	},
+	"IAB1-6": {
+		"id": "392",
+		"name": "Entertainment"
+	},
+	"IAB1-7": {
+		"id": "392",
+		"name": "Entertainment"
+	},
+	"IAB2-1": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-2": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-3": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-4": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-5": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-6": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-7": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-8": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-9": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-10": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-11": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-12": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-13": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-14": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-15": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-16": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-17": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-18": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-19": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-20": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-21": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-22": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB2-23": {
+		"id": "399",
+		"name": "Automotive"
+	},
+	"IAB3-1": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB3-2": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB3-3": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB3-4": {
+		"id": "408",
+		"name": "Office Equipment/Supplies"
+	},
+	"IAB3-5": {
+		"id": "390",
+		"name": "Manufacturing"
+	},
+	"IAB3-6": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB3-7": {
+		"id": "398",
+		"name": "Government/Municipal"
+	},
+	"IAB3-8": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB3-9": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB3-10": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB3-11": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB3-12": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB4-1": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB4-2": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB4-3": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB4-4": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB4-5": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB4-6": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB4-7": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB4-8": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB4-9": {
+		"id": "417",
+		"name": "Telecommunications"
+	},
+	"IAB4-10": {
+		"id": "429",
+		"name": "Military"
+	},
+	"IAB4-11": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB5-1": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-2": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-3": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-4": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-5": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-6": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-7": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-8": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-9": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-10": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-11": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-12": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-13": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-14": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB5-15": {
+		"id": "405",
+		"name": "Educational Services"
+	},
+	"IAB7-1": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-2": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-3": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-4": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-5": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-6": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-7": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-8": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-9": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-10": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-11": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-12": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-13": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-14": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-15": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-16": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-17": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-18": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-19": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-20": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-21": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-22": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-23": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-24": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-25": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-26": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-27": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-28": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-29": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-30": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-31": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-32": {
+		"id": "402",
+		"name": "Pharmaceuticals"
+	},
+	"IAB7-33": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-34": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-35": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-36": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-37": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-38": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-39": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-40": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-41": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-42": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-43": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB7-44": {
+		"id": "433",
+		"name": "Drug Stores"
+	},
+	"IAB7-45": {
+		"id": "406",
+		"name": "Health Care Services"
+	},
+	"IAB8-1": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-2": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-3": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-4": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-5": {
+		"id": "400",
+		"name": "Beer/Wine/Liquor"
+	},
+	"IAB8-6": {
+		"id": "401",
+		"name": "Beverages"
+	},
+	"IAB8-7": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-8": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-9": {
+		"id": "407",
+		"name": "Restaurant/Fast Food"
+	},
+	"IAB8-10": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-11": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-12": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-13": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-14": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-15": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-16": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-17": {
+		"id": "394",
+		"name": "Food"
+	},
+	"IAB8-18": {
+		"id": "400",
+		"name": "Beer/Wine/Liquor"
+	},
+	"IAB9-1": {
+		"id": "392",
+		"name": "Entertainment"
+	},
+	"IAB9-3": {
+		"id": "418",
+		"name": "Jewelry"
+	},
+	"IAB9-5": {
+		"id": "414",
+		"name": "Gambling"
+	},
+	"IAB9-6": {
+		"id": "412",
+		"name": "Household Products"
+	},
+	"IAB9-7": {
+		"id": "413",
+		"name": "Gaming"
+	},
+	"IAB9-9": {
+		"id": "426",
+		"name": "Tobacco"
+	},
+	"IAB9-11": {
+		"id": "404",
+		"name": "Publishing"
+	},
+	"IAB9-15": {
+		"id": "404",
+		"name": "Publishing"
+	},
+	"IAB9-16": {
+		"id": "392",
+		"name": "Entertainment"
+	},
+	"IAB9-18": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB9-19": {
+		"id": "418",
+		"name": "Jewelry"
+	},
+	"IAB9-23": {
+		"id": "424",
+		"name": "Photographic Equipment"
+	},
+	"IAB9-24": {
+		"id": "392",
+		"name": "Entertainment"
+	},
+	"IAB9-25": {
+		"id": "392",
+		"name": "Entertainment"
+	},
+	"IAB9-30": {
+		"id": "427",
+		"name": "Toys/Games"
+	},
+	"IAB10-1": {
+		"id": "415",
+		"name": "Appliances"
+	},
+	"IAB10-5": {
+		"id": "434",
+		"name": "Home Furnishings"
+	},
+	"IAB10-6": {
+		"id": "434",
+		"name": "Home Furnishings"
+	},
+	"IAB10-7": {
+		"id": "434",
+		"name": "Home Furnishings"
+	},
+	"IAB10-8": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB10-9": {
+		"id": "434",
+		"name": "Home Furnishings"
+	},
+	"IAB11-1": {
+		"id": "398",
+		"name": "Government/Municipal"
+	},
+	"IAB11-2": {
+		"id": "398",
+		"name": "Government/Municipal"
+	},
+	"IAB11-3": {
+		"id": "398",
+		"name": "Government/Municipal"
+	},
+	"IAB11-4": {
+		"id": "398",
+		"name": "Government/Municipal"
+	},
+	"IAB11-5": {
+		"id": "421",
+		"name": "Associations"
+	},
+	"IAB12-1": {
+		"id": "438",
+		"name": "News"
+	},
+	"IAB12-2": {
+		"id": "438",
+		"name": "News"
+	},
+	"IAB12-3": {
+		"id": "438",
+		"name": "News"
+	},
+	"IAB13-1": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB13-2": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB13-3": {
+		"id": "438",
+		"name": "News"
+	},
+	"IAB13-4": {
+		"id": "391",
+		"name": "Financial Services"
+	},
+	"IAB13-5": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB13-6": {
+		"id": "436",
+		"name": "Insurance"
+	},
+	"IAB13-7": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB13-8": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB13-9": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB13-10": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB13-11": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB13-12": {
+		"id": "393",
+		"name": "Business Services"
+	},
+	"IAB16-1": {
+		"id": "423",
+		"name": "Pet Food/Supplies"
+	},
+	"IAB16-2": {
+		"id": "423",
+		"name": "Pet Food/Supplies"
+	},
+	"IAB16-3": {
+		"id": "423",
+		"name": "Pet Food/Supplies"
+	},
+	"IAB16-4": {
+		"id": "423",
+		"name": "Pet Food/Supplies"
+	},
+	"IAB16-5": {
+		"id": "423",
+		"name": "Pet Food/Supplies"
+	},
+	"IAB16-6": {
+		"id": "423",
+		"name": "Pet Food/Supplies"
+	},
+	"IAB16-7": {
+		"id": "423",
+		"name": "Pet Food/Supplies"
+	},
+	"IAB17-1": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-2": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-3": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-4": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-5": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-6": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-7": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-8": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-9": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-10": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-11": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-12": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-13": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-14": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-15": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-16": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-17": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-18": {
+		"id": "412",
+		"name": "Household Products"
+	},
+	"IAB17-19": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-20": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-21": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-22": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-23": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-24": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-25": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-26": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-27": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-28": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-29": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-30": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-31": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-32": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-33": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-34": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-35": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-36": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-37": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-38": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-39": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-40": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-41": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-42": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-43": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB17-44": {
+		"id": "425",
+		"name": "Professional Sports"
+	},
+	"IAB18-1": {
+		"id": "411",
+		"name": "Cosmetics/Toiletries"
+	},
+	"IAB18-2": {
+		"id": "397",
+		"name": "Apparel"
+	},
+	"IAB18-3": {
+		"id": "397",
+		"name": "Apparel"
+	},
+	"IAB18-4": {
+		"id": "418",
+		"name": "Jewelry"
+	},
+	"IAB18-5": {
+		"id": "397",
+		"name": "Apparel"
+	},
+	"IAB18-6": {
+		"id": "397",
+		"name": "Apparel"
+	},
+	"IAB19-2": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-3": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-4": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-5": {
+		"id": "424",
+		"name": "Photographic Equipment"
+	},
+	"IAB19-6": {
+		"id": "417",
+		"name": "Telecommunications"
+	},
+	"IAB19-7": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-8": {
+		"id": "432",
+		"name": "Audio and Video Equipment"
+	},
+	"IAB19-9": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-10": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-11": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-12": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-13": {
+		"id": "404",
+		"name": "Publishing"
+	},
+	"IAB19-14": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-15": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-16": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-17": {
+		"id": "419",
+		"name": "Filmed Entertainment"
+	},
+	"IAB19-18": {
+		"id": "431",
+		"name": "Computing"
+	},
+	"IAB19-19": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-20": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-21": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-22": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-23": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-24": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-25": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-26": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-27": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-28": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-29": {
+		"id": "392",
+		"name": "Entertainment"
+	},
+	"IAB19-30": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-31": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-32": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-33": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-34": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-35": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB19-36": {
+		"id": "409",
+		"name": "Computing Product"
+	},
+	"IAB20-1": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-2": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-3": {
+		"id": "428",
+		"name": "Aerospace"
+	},
+	"IAB20-4": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-5": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-6": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-7": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-8": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-9": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-10": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-11": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-12": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-13": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-14": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-15": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-16": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-17": {
+		"id": "396",
+		"name": "Amusement and Recreation"
+	},
+	"IAB20-18": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-19": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-20": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-21": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-22": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-23": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-24": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-25": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-26": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB20-27": {
+		"id": "395",
+		"name": "Travel/Hotels/Airlines"
+	},
+	"IAB21-1": {
+		"id": "416",
+		"name": "Real Estate"
+	},
+	"IAB21-2": {
+		"id": "416",
+		"name": "Real Estate"
+	},
+	"IAB21-3": {
+		"id": "416",
+		"name": "Real Estate"
+	},
+	"IAB22-1": {
+		"id": "403",
+		"name": "Retail Stores/Chains"
+	},
+	"IAB22-2": {
+		"id": "403",
+		"name": "Retail Stores/Chains"
+	},
+	"IAB22-3": {
+		"id": "410",
+		"name": "Product"
+	}
 }
\ No newline at end of file
diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go
index 751d2aab..5657c8b7 100755
--- a/usersync/usersyncers/syncer.go
+++ b/usersync/usersyncers/syncer.go
@@ -18,6 +18,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/aja"
 	"github.com/prebid/prebid-server/adapters/appnexus"
 	"github.com/prebid/prebid-server/adapters/audienceNetwork"
+	"github.com/prebid/prebid-server/adapters/avocet"
 	"github.com/prebid/prebid-server/adapters/beachfront"
 	"github.com/prebid/prebid-server/adapters/beintoo"
 	"github.com/prebid/prebid-server/adapters/brightroll"
@@ -49,6 +50,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/smartadserver"
 	"github.com/prebid/prebid-server/adapters/smartrtb"
 	"github.com/prebid/prebid-server/adapters/somoaudience"
 	"github.com/prebid/prebid-server/adapters/sonobi"
@@ -90,6 +92,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderAdvangelists, advangelists.NewAdvangelistsSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderAJA, aja.NewAJASyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderAppnexus, appnexus.NewAppnexusSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderAvocet, avocet.NewAvocetSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderBeachfront, beachfront.NewBeachfrontSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderBeintoo, beintoo.NewBeintooSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderBrightroll, brightroll.NewBrightrollSyncer)
@@ -125,6 +128,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSomoaudience, somoaudience.NewSomoaudienceSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSonobi, sonobi.NewSonobiSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSovrn, sovrn.NewSovrnSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderSmartadserver, smartadserver.NewSmartadserverSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSmartRTB, smartrtb.NewSmartRTBSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSynacormedia, synacormedia.NewSynacorMediaSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderTelaria, telaria.NewTelariaSyncer)


Test patch:
diff --git a/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json b/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json
index 007a5306..9e4ce06e 100644
--- a/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json
+++ b/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json
@@ -18,6 +18,9 @@
         "format": [{
           "w": 300,
           "h": 250
+        }, {
+          "w": 320,
+          "h": 600
         }]
       }
     }, {
@@ -68,7 +71,7 @@
   },
   "httpCalls": [{
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Asecod-twelve&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.0.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Asecod-twelve&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250_320x600&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
     },
     "mockResponse": {
       "status": 200,
diff --git a/adapters/adocean/adoceantest/exemplary/single-banner-impression.json b/adapters/adocean/adoceantest/exemplary/single-banner-impression.json
index b938a042..e6d70f84 100644
--- a/adapters/adocean/adoceantest/exemplary/single-banner-impression.json
+++ b/adapters/adocean/adoceantest/exemplary/single-banner-impression.json
@@ -59,7 +59,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.0.0"
+        "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
       },
       "mockResponse": {
         "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/bad-response.json b/adapters/adocean/adoceantest/supplemental/bad-response.json
index 514262d5..e7b871f9 100644
--- a/adapters/adocean/adoceantest/supplemental/bad-response.json
+++ b/adapters/adocean/adoceantest/supplemental/bad-response.json
@@ -49,7 +49,7 @@
   "httpCalls": [
     {
         "expectedRequest": {
-          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.0.0"
+          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
         },
       "mockResponse": {
         "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/encode-error.json b/adapters/adocean/adoceantest/supplemental/encode-error.json
index 2f775f98..8dfd0f83 100644
--- a/adapters/adocean/adoceantest/supplemental/encode-error.json
+++ b/adapters/adocean/adoceantest/supplemental/encode-error.json
@@ -49,7 +49,7 @@
   "httpCalls": [
     {
         "expectedRequest": {
-          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.0.0"
+          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
         },
       "mockResponse": {
         "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/network-error.json b/adapters/adocean/adoceantest/supplemental/network-error.json
index 7a5fa8fd..54e528af 100644
--- a/adapters/adocean/adoceantest/supplemental/network-error.json
+++ b/adapters/adocean/adoceantest/supplemental/network-error.json
@@ -49,7 +49,7 @@
   "httpCalls": [
     {
         "expectedRequest": {
-          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.0.0"
+          "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
         },
       "mockResponse": {
         "status": 500,
diff --git a/adapters/adocean/adoceantest/supplemental/no-bid.json b/adapters/adocean/adoceantest/supplemental/no-bid.json
index ed81bb35..625fb78f 100644
--- a/adapters/adocean/adoceantest/supplemental/no-bid.json
+++ b/adapters/adocean/adoceantest/supplemental/no-bid.json
@@ -83,7 +83,7 @@
   },
   "httpCalls": [{
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.0.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
     },
     "mockResponse": {
       "status": 200,
@@ -108,7 +108,7 @@
     }
   }, {
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.0.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
     },
     "mockResponse": {
       "status": 200,
diff --git a/adapters/adocean/adoceantest/supplemental/no-sizes.json b/adapters/adocean/adoceantest/supplemental/no-sizes.json
new file mode 100644
index 00000000..6286d805
--- /dev/null
+++ b/adapters/adocean/adoceantest/supplemental/no-sizes.json
@@ -0,0 +1,168 @@
+{
+  "mockBidRequest": {
+    "id": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b",
+    "source": {
+      "tid": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b"
+    },
+    "tmax": 1000,
+    "imp": [{
+      "id": "ao-test",
+      "ext": {
+        "bidder": {
+          "emiter": "myao.adocean.pl",
+          "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
+          "slaveId": "adoceanmyaozpniqismex"
+        }
+      }
+    }, {
+      "id": "ao-test-two",
+      "ext": {
+        "bidder": {
+          "emiter": "myao.adocean.pl",
+          "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
+          "slaveId": "adoceanmyaowafpdwlrks"
+        }
+      },
+      "banner": {
+        "format": []
+      }
+    }, {
+      "id": "ao-test-three",
+      "ext": {
+        "bidder": {
+          "emiter": "myao.adocean.pl",
+          "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
+          "slaveId": "adoceanmyaowafpdwlrks"
+        }
+      },
+      "banner": {
+        "w": 300,
+        "h": 250
+      }
+    }],
+    "test": 1,
+    "ext": {
+      "prebid": {
+        "targeting": {
+          "includewinners": true,
+          "includebidderkeys": false
+        }
+      }
+    },
+    "site": {
+      "publisher": {
+        "id": "1"
+      },
+      "page": "http://localhost/prebid_server/test.html"
+    },
+    "device": {
+      "w": 418,
+      "h": 961
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 1
+      }
+    },
+    "user": {
+      "ext": {
+        "consent": "COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw"
+      }
+    }
+  },
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": [{
+          "id": "adoceanmyaozpniqismex",
+          "price": "1",
+          "winurl": "https://win-url.com",
+          "statsUrl": "https://stats-url.com",
+          "code": " <!-- code 1 --> ",
+          "currency": "EUR",
+          "minFloorPrice": "0.01",
+          "width": "300",
+          "height": "250",
+          "crid": "0af345b42983cc4bc0",
+          "ttl": "300"
+        },
+        {
+          "id": "adoceanmyaowafpdwlrks",
+          "price": "1",
+          "winurl": "https://win-url2.com",
+          "statsUrl": "https://stats-url2.com",
+          "code": " <!-- code 2 --> ",
+          "currency": "EUR",
+          "minFloorPrice": "0.01",
+          "width": "300",
+          "height": "250",
+          "crid": "0af345b42983cc4bc0",
+          "ttl": "300"
+        }
+      ]
+    }
+  }, {
+    "expectedRequest": {
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": [{
+        "id": "adoceanmyaowafpdwlrks",
+        "price": "1",
+        "winurl": "https://win-url3.com",
+        "statsUrl": "https://stats-url3.com",
+        "code": " <!-- code 3 --> ",
+        "currency": "EUR",
+        "minFloorPrice": "0.01",
+        "width": "300",
+        "height": "250",
+        "crid": "0af345b42983cc4bc0",
+        "ttl": "300"
+      }]
+    }
+  }],
+  "expectedBidResponses": [{
+    "currency": "EUR",
+    "bids": [{
+      "bid": {
+        "id": "adoceanmyaozpniqismex",
+        "impid": "ao-test",
+        "price": 1,
+        "adm": " <script> +function() { var wu = \"https://win-url.com\"; var su = \"https://stats-url.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script>  <!-- code 1 --> ",
+        "crid": "0af345b42983cc4bc0",
+        "w": 300,
+        "h": 250
+      },
+      "type": "banner"
+    }, {
+      "bid": {
+        "id": "adoceanmyaowafpdwlrks",
+        "impid": "ao-test-two",
+        "price": 1,
+        "adm": " <script> +function() { var wu = \"https://win-url2.com\"; var su = \"https://stats-url2.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script>  <!-- code 2 --> ",
+        "crid": "0af345b42983cc4bc0",
+        "w": 300,
+        "h": 250
+      },
+      "type": "banner"
+    }]
+  }, {
+    "currency": "EUR",
+    "bids": [{
+      "bid": {
+        "id": "adoceanmyaowafpdwlrks",
+        "impid": "ao-test-three",
+        "price": 1,
+        "adm": " <script> +function() { var wu = \"https://win-url3.com\"; var su = \"https://stats-url3.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script>  <!-- code 3 --> ",
+        "crid": "0af345b42983cc4bc0",
+        "w": 300,
+        "h": 250
+      },
+      "type": "banner"
+    }]
+  }]
+}
diff --git a/adapters/adocean/adoceantest/supplemental/requests-merge.json b/adapters/adocean/adoceantest/supplemental/requests-merge.json
index 9b5eb39a..e0736ec9 100644
--- a/adapters/adocean/adoceantest/supplemental/requests-merge.json
+++ b/adapters/adocean/adoceantest/supplemental/requests-merge.json
@@ -83,7 +83,7 @@
   },
   "httpCalls": [{
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.0.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
     },
     "mockResponse": {
       "status": 200,
@@ -117,7 +117,7 @@
     }
   }, {
     "expectedRequest": {
-      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.0.0"
+      "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.1.0"
     },
     "mockResponse": {
       "status": 200,
diff --git a/adapters/avocet/avocet_test.go b/adapters/avocet/avocet_test.go
new file mode 100644
index 00000000..ff2159bf
--- /dev/null
+++ b/adapters/avocet/avocet_test.go
@@ -0,0 +1,301 @@
+package avocet
+
+import (
+	"encoding/json"
+	"net/http"
+	"reflect"
+	"testing"
+
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+	adapterstest.RunJSONBidderTest(t, "avocet", NewAvocetAdapter("https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013"))
+}
+
+func TestAvocetAdapter_MakeRequests(t *testing.T) {
+	type fields struct {
+		Endpoint string
+	}
+	type args struct {
+		request *openrtb.BidRequest
+		reqInfo *adapters.ExtraRequestInfo
+	}
+	type reqData []*adapters.RequestData
+	tests := []struct {
+		name     string
+		fields   fields
+		args     args
+		want     []*adapters.RequestData
+		wantErrs []error
+	}{
+		{
+			name:   "return nil if zero imps",
+			fields: fields{Endpoint: "https://bid.avct.cloud"},
+			args: args{
+				&openrtb.BidRequest{},
+				nil,
+			},
+			want:     nil,
+			wantErrs: nil,
+		},
+		{
+			name:   "makes POST request with JSON content",
+			fields: fields{Endpoint: "https://bid.avct.cloud"},
+			args: args{
+				&openrtb.BidRequest{Imp: []openrtb.Imp{{}}},
+				nil,
+			},
+			want: reqData{
+				&adapters.RequestData{
+					Method: http.MethodPost,
+					Uri:    "https://bid.avct.cloud",
+					Body:   []byte(`{"id":"","imp":[{"id":""}]}`),
+					Headers: map[string][]string{
+						"Accept":       {"application/json"},
+						"Content-Type": {"application/json;charset=utf-8"},
+					},
+				},
+			},
+			wantErrs: nil,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			a := &AvocetAdapter{
+				Endpoint: tt.fields.Endpoint,
+			}
+			got, got1 := a.MakeRequests(tt.args.request, tt.args.reqInfo)
+			if len(got) != len(tt.want) {
+				t.Errorf("AvocetAdapter.MakeRequests() got %v requests, wanted %v requests", len(got), len(tt.want))
+			}
+			if len(got) == len(tt.want) {
+				for i := range tt.want {
+					if !reflect.DeepEqual(got[i], tt.want[i]) {
+						t.Errorf("AvocetAdapter.MakeRequests() got = %v, want %v", got[i], tt.want[i])
+					}
+				}
+			}
+			if !reflect.DeepEqual(got1, tt.wantErrs) {
+				t.Errorf("AvocetAdapter.MakeRequests() got1 = %v, want %v", got1, tt.wantErrs)
+			}
+		})
+	}
+}
+
+func TestAvocetAdapter_MakeBids(t *testing.T) {
+	type fields struct {
+		Endpoint string
+	}
+	type args struct {
+		internalRequest *openrtb.BidRequest
+		externalRequest *adapters.RequestData
+		response        *adapters.ResponseData
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   *adapters.BidderResponse
+		errs   []error
+	}{
+		{
+			name:   "204 No Content indicates no bids",
+			fields: fields{Endpoint: "https://bid.avct.cloud"},
+			args: args{
+				nil,
+				nil,
+				&adapters.ResponseData{StatusCode: http.StatusNoContent},
+			},
+			want: nil,
+			errs: nil,
+		},
+		{
+			name:   "Non-200 return error",
+			fields: fields{Endpoint: "https://bid.avct.cloud"},
+			args: args{
+				nil,
+				nil,
+				&adapters.ResponseData{StatusCode: http.StatusBadRequest, Body: []byte("message")},
+			},
+			want: nil,
+			errs: []error{&errortypes.BadServerResponse{Message: "received status code: 400 error: message"}},
+		},
+		{
+			name:   "200 response containing banner bids",
+			fields: fields{Endpoint: "https://bid.avct.cloud"},
+			args: args{
+				nil,
+				nil,
+				&adapters.ResponseData{StatusCode: http.StatusOK, Body: validBannerBidResponseBody},
+			},
+			want: &adapters.BidderResponse{
+				Currency: "USD",
+				Bids: []*adapters.TypedBid{
+					{
+						Bid:     &validBannerBid,
+						BidType: openrtb_ext.BidTypeBanner,
+					},
+				},
+			},
+			errs: nil,
+		},
+		{
+			name:   "200 response containing video bids",
+			fields: fields{Endpoint: "https://bid.avct.cloud"},
+			args: args{
+				nil,
+				nil,
+				&adapters.ResponseData{StatusCode: http.StatusOK, Body: validVideoBidResponseBody},
+			},
+			want: &adapters.BidderResponse{
+				Currency: "USD",
+				Bids: []*adapters.TypedBid{
+					{
+						Bid:     &validVideoBid,
+						BidType: openrtb_ext.BidTypeVideo,
+						BidVideo: &openrtb_ext.ExtBidPrebidVideo{
+							Duration: 30,
+						},
+					},
+				},
+			},
+			errs: nil,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			a := &AvocetAdapter{
+				Endpoint: tt.fields.Endpoint,
+			}
+			got, got1 := a.MakeBids(tt.args.internalRequest, tt.args.externalRequest, tt.args.response)
+			if !reflect.DeepEqual(got, tt.want) {
+				gotb, _ := json.Marshal(got)
+				wantb, _ := json.Marshal(tt.want)
+				t.Errorf("AvocetAdapter.MakeBids() got = %s, want %s", string(gotb), string(wantb))
+			}
+			if !reflect.DeepEqual(got1, tt.errs) {
+				t.Errorf("AvocetAdapter.MakeBids() got1 = %v, want %v", got1, tt.errs)
+			}
+		})
+	}
+}
+
+func Test_getBidType(t *testing.T) {
+	type args struct {
+		bid openrtb.Bid
+		ext avocetBidExt
+	}
+	tests := []struct {
+		name string
+		args args
+		want openrtb_ext.BidType
+	}{
+		{
+			name: "VPAID 1.0",
+			args: args{openrtb.Bid{API: openrtb.APIFrameworkVPAID10}, avocetBidExt{}},
+			want: openrtb_ext.BidTypeVideo,
+		},
+		{
+			name: "VPAID 2.0",
+			args: args{openrtb.Bid{API: openrtb.APIFrameworkVPAID20}, avocetBidExt{}},
+			want: openrtb_ext.BidTypeVideo,
+		},
+		{
+			name: "other",
+			args: args{openrtb.Bid{}, avocetBidExt{}},
+			want: openrtb_ext.BidTypeBanner,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := getBidType(tt.args.bid, tt.args.ext); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("getBidType() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+var validBannerBid = openrtb.Bid{
+	AdM:      "<iframe src=\"http://ads.staging.avct.cloud/sv?pp=${AUCTION_PRICE}&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5b51e49634f2021f127ff7c9&tacid=5b51e4ed89654741306813a8&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=1&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591874537316649768&h=250&w=300&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&ck=1_5d99a849\" height=\"250\" width=\"300\" marginwidth=0 marginheight=0 hspace=0 vspace=0 frameborder=0 scrolling=\"no\"></iframe>",
+	ADomain:  []string{"avocet.io"},
+	CID:      "5b51e2d689654741306813a4",
+	CrID:     "5b51e49634f2021f127ff7c9",
+	H:        250,
+	ID:       "bc708396-9202-437b-b726-08b9864cb8b8",
+	ImpID:    "test-imp-id",
+	IURL:     "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg",
+	Language: "en",
+	Price:    15.64434783,
+	W:        300,
+}
+
+var validBannerBidResponseBody = []byte(`{
+	"bidid": "dd87f80c-16a0-43c8-a673-b94b3ea4d417",
+	"id": "test-request-id",
+	"seatbid": [
+		{
+			"bid": [
+				{
+					"adm": "<iframe src=\"http://ads.staging.avct.cloud/sv?pp=${AUCTION_PRICE}&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5b51e49634f2021f127ff7c9&tacid=5b51e4ed89654741306813a8&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=1&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591874537316649768&h=250&w=300&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&ck=1_5d99a849\" height=\"250\" width=\"300\" marginwidth=0 marginheight=0 hspace=0 vspace=0 frameborder=0 scrolling=\"no\"></iframe>",
+					"adomain": ["avocet.io"],
+					"cid": "5b51e2d689654741306813a4",
+					"crid": "5b51e49634f2021f127ff7c9",
+					"h": 250,
+					"id": "bc708396-9202-437b-b726-08b9864cb8b8",
+					"impid": "test-imp-id",
+					"iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg",
+					"language": "en",
+					"price": 15.64434783,
+					"w": 300
+				}
+			],
+			"seat": "TEST_SEAT_ID"
+		}
+	]
+}`)
+
+var validVideoBid = openrtb.Bid{
+	AdM:      "<VAST version=\"3.0\"><Ad id=\"5ec530e32d57fe1100f17d87\"><Wrapper><AdSystem>Avocet</AdSystem><VASTAdTagURI><![CDATA[http://ads.staging.avct.cloud/vast?x=1&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5ec530e32d57fe1100f17d87&tacid=5ec531d32d57fe1100f17d89&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=2&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591875033134290518&h=396&w=600&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&pixel=1&ck=1_c343bf14]]></VASTAdTagURI><Impression><![CDATA[http://ads.staging.avct.cloud/sv?pp=${AUCTION_PRICE}&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5ec530e32d57fe1100f17d87&tacid=5ec531d32d57fe1100f17d89&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=2&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591875033134290518&h=396&w=600&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&pixel=1&ck=1_c343bf14]]></Impression><Creatives><Creative AdId=\"5ec530e32d57fe1100f17d87\"><Linear><TrackingEvents></TrackingEvents><VideoClicks></VideoClicks></Linear></Creative></Creatives></Wrapper></Ad></VAST>",
+	ADomain:  []string{"avocet.io"},
+	CID:      "5b51e2d689654741306813a4",
+	CrID:     "5ec530e32d57fe1100f17d87",
+	H:        396,
+	ID:       "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f",
+	ImpID:    "dfp-ad--top-above-nav",
+	IURL:     "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg",
+	Language: "en",
+	Price:    15.64434783,
+	W:        600,
+	Ext:      []byte(`{"avocet":{"duration":30}}`),
+}
+
+var validVideoBidResponseBody = []byte(`{
+	"bidid": "dd87f80c-16a0-43c8-a673-b94b3ea4d417",
+	"id": "test-request-id",
+	"seatbid": [
+		{
+			"bid": [
+				{
+					"adm": "<VAST version=\"3.0\"><Ad id=\"5ec530e32d57fe1100f17d87\"><Wrapper><AdSystem>Avocet</AdSystem><VASTAdTagURI><![CDATA[http://ads.staging.avct.cloud/vast?x=1&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5ec530e32d57fe1100f17d87&tacid=5ec531d32d57fe1100f17d89&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=2&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591875033134290518&h=396&w=600&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&pixel=1&ck=1_c343bf14]]></VASTAdTagURI><Impression><![CDATA[http://ads.staging.avct.cloud/sv?pp=${AUCTION_PRICE}&uuid=0df2c449-6d85-4179-b5d5-37f2f91caa24&ty=h&crid=5ec530e32d57fe1100f17d87&tacid=5ec531d32d57fe1100f17d89&aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&accid=5b51dd1634f2021f127ff7c0&brid=5b51e20f34f2021f127ff7c4&ioid=5b51e22089654741306813a1&caid=5b51e2d689654741306813a4&it=2&iobsid=496e8cff35b2c0110029534d&ext_aid=749d36d7-c993-455f-aefd-ffd8a7e3ccf_0&bp=15.64434783&bt=1591875033134290518&h=396&w=600&vpr=0&vdp=0&domain=example.com&gco=54510b3b816269000061a0f7&stid=542d2c1615e3c013de53a6e2&glat=0&glong=0&bip4=3232238090&ext_siid=5ea89200c865f911007f1b0e&ext_pid=1&ext_sid=5ea84df8c865f911007f1ade&ext_plid=5ea9601ac865f911007f1b6a&optv=latest:latest&invsrc=5e722ee9bd6df11d063a8013&ug=0d&ca=0&biid=requestd-54644474bf-l7gx4|eu-central-1-staging&reg=eu-central-1&pixel=1&ck=1_c343bf14]]></Impression><Creatives><Creative AdId=\"5ec530e32d57fe1100f17d87\"><Linear><TrackingEvents></TrackingEvents><VideoClicks></VideoClicks></Linear></Creative></Creatives></Wrapper></Ad></VAST>",
+					"adomain": ["avocet.io"],
+					"cid": "5b51e2d689654741306813a4",
+					"crid": "5ec530e32d57fe1100f17d87",
+					"h": 396,
+					"id": "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f",
+					"impid": "dfp-ad--top-above-nav",
+					"iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg",
+					"language": "en",
+					"price": 15.64434783,
+					"w": 600,
+					"ext": {"avocet":{"duration":30}}
+				}
+			],
+			"seat": "TEST_SEAT_ID"
+		}
+	]
+}`)
diff --git a/adapters/avocet/usersync_test.go b/adapters/avocet/usersync_test.go
new file mode 100644
index 00000000..8fba403f
--- /dev/null
+++ b/adapters/avocet/usersync_test.go
@@ -0,0 +1,35 @@
+package avocet
+
+import (
+	"testing"
+	"text/template"
+
+	"github.com/prebid/prebid-server/privacy"
+	"github.com/prebid/prebid-server/privacy/ccpa"
+	"github.com/prebid/prebid-server/privacy/gdpr"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAvocetSyncer(t *testing.T) {
+	syncURL := "https://ads.avct.cloud/getuid?&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url=%2Fsetuid%3Fbidder%3Davocet%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7B%7BUUID%7D%7D"
+	syncURLTemplate := template.Must(
+		template.New("sync-template").Parse(syncURL),
+	)
+
+	syncer := NewAvocetSyncer(syncURLTemplate)
+	syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+		GDPR: gdpr.Policy{
+			Signal:  "1",
+			Consent: "ConsentString",
+		},
+		CCPA: ccpa.Policy{
+			Value: "PrivacyString",
+		},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, "https://ads.avct.cloud/getuid?&gdpr=1&gdpr_consent=ConsentString&us_privacy=PrivacyString&url=%2Fsetuid%3Fbidder%3Davocet%26gdpr%3D1%26gdpr_consent%3DConsentString%26uid%3D%7B%7BUUID%7D%7D", syncInfo.URL)
+	assert.Equal(t, "redirect", syncInfo.Type)
+	assert.EqualValues(t, 63, syncer.GDPRVendorID())
+	assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/adapters/smartadserver/params_test.go b/adapters/smartadserver/params_test.go
new file mode 100644
index 00000000..6e45bb1d
--- /dev/null
+++ b/adapters/smartadserver/params_test.go
@@ -0,0 +1,61 @@
+package smartadserver
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// This file actually intends to test static/bidder-params/smartadserver.json
+//
+// These also validate the format of the external API: request.imp[i].ext.smartadserver
+
+// TestValidParams makes sure that the smartadserver 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.BidderSmartadserver, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected smartadserver params: %s \n Error: %s", validParam, err)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the smartadserver 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.BidderSmartadserver, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"networkId":73}`,
+	`{"networkId":73,"siteId":1,"pageId":2,"formatId":3}`,
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`4.2`,
+	`[]`,
+	`{}`,
+	`{"networkId":"73"}`,
+	`{"networkId":"73","siteId":"1","pageId":"2","formatId":"3"}`,
+	`{"siteId":1,"pageId":2,"formatId":3}`,
+	`{"networkId":73,"pageId":2,"formatId":3}`,
+	`{"networkId":73,"siteId":1,"formatId":3}`,
+	`{"networkId":73,"siteId":1,"pageId":2}`,
+}
diff --git a/adapters/smartadserver/smartadserver_test.go b/adapters/smartadserver/smartadserver_test.go
new file mode 100644
index 00000000..7e4cff67
--- /dev/null
+++ b/adapters/smartadserver/smartadserver_test.go
@@ -0,0 +1,11 @@
+package smartadserver
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+)
+
+func TestJsonSamples(t *testing.T) {
+	adapterstest.RunJSONBidderTest(t, "smartadservertest", NewSmartadserverBidder("https://ssb.smartadserver.com"))
+}
diff --git a/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json b/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json
new file mode 100644
index 00000000..b7cf27c3
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json
@@ -0,0 +1,175 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-multi-id",
+    "imp": [
+      {
+        "id": "test-imp-id-1",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "siteId": 1,
+            "pageId": 2,
+            "formatId": 3,
+            "networkId": 73
+          }
+        }
+      },
+      {
+        "id": "test-imp-id-2",
+        "banner": {
+          "format": [{"w": 300, "h": 150}]
+        },
+        "ext": {
+          "bidder": {
+            "siteId": 1,
+            "pageId": 2,
+            "formatId": 4,
+            "networkId": 73
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://ssb.smartadserver.com/api/bid?callerId=5",
+        "body": {
+          "id": "test-request-multi-id",
+          "imp": [
+            {
+              "id": "test-imp-id-1",
+              "banner": {
+                "format": [{"w": 728, "h": 90}]
+              },
+              "ext": {
+                "bidder": {
+                  "siteId": 1,
+                  "pageId": 2,
+                  "formatId": 3,
+                  "networkId": 73
+                }
+              }
+            }
+          ],
+          "site": {
+            "publisher": {
+              "id": "73"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-multi-id",
+          "seatbid": [
+            {
+              "seat": "smartadserver",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id-1",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 90,
+                "w": 728
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "https://ssb.smartadserver.com/api/bid?callerId=5",
+        "body": {
+          "id": "test-request-multi-id",
+          "imp": [
+            {
+              "id": "test-imp-id-2",
+              "banner": {
+                "format": [{"w": 300, "h": 150}]
+              },
+              "ext": {
+                "bidder": {
+                  "siteId": 1,
+                  "pageId": 2,
+                  "formatId": 4,
+                  "networkId": 73
+                }
+              }
+            }
+          ],
+          "site": {
+            "publisher": {
+              "id": "73"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-multi-id",
+          "seatbid": [
+            {
+              "seat": "smartadserver",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801",
+                "impid": "test-imp-id-2",
+                "price": 0.800000,
+                "adm": "some-test-ad",
+                "crid": "crid_11",
+                "h": 150,
+                "w": 300
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id-1",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 728,
+            "h": 90
+          },
+          "type": "banner"
+        }
+      ]
+    },
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801",
+            "impid": "test-imp-id-2",
+            "price": 0.8,
+            "adm": "some-test-ad",
+            "crid": "crid_11",
+            "w": 300,
+            "h": 150
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/exemplary/simple-banner.json b/adapters/smartadserver/smartadservertest/exemplary/simple-banner.json
new file mode 100644
index 00000000..e8faab14
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/exemplary/simple-banner.json
@@ -0,0 +1,94 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "siteId": 1,
+            "pageId": 2,
+            "formatId": 3,
+            "networkId": 73
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://ssb.smartadserver.com/api/bid?callerId=5",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}]
+              },
+              "ext": {
+                "bidder": {
+                  "siteId": 1,
+                  "pageId": 2,
+                  "formatId": 3,
+                  "networkId": 73
+                }
+              }
+            }
+          ],
+          "site": {
+            "publisher": {
+              "id": "73"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "smartadserver",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 90,
+                "w": 728
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 728,
+            "h": 90
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/exemplary/simple-video.json b/adapters/smartadserver/smartadservertest/exemplary/simple-video.json
new file mode 100644
index 00000000..86f9361a
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/exemplary/simple-video.json
@@ -0,0 +1,100 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id-video",
+    "imp": [
+      {
+        "id": "test-imp-id-video",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [1],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "siteId": 1,
+            "pageId": 2,
+            "formatId": 3,
+            "networkId": 73
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://ssb.smartadserver.com/api/bid?callerId=5",
+        "body": {
+          "id": "test-request-id-video",
+          "imp": [
+            {
+              "id": "test-imp-id-video",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [1],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "siteId": 1,
+                  "pageId": 2,
+                  "formatId": 3,
+                  "networkId": 73
+                }
+              }
+            }
+          ],
+          "site": {
+            "publisher": {
+              "id": "73"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id-video",
+          "seatbid": [
+            {
+              "seat": "smartadserver",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id-video",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 576,
+                "w": 1024
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id-video",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 1024,
+            "h": 576
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/params/race/banner.json b/adapters/smartadserver/smartadservertest/params/race/banner.json
new file mode 100644
index 00000000..b3408830
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/params/race/banner.json
@@ -0,0 +1,7 @@
+{
+    "siteId": 1,
+    "pageId": 2,
+    "formatId": 3,
+    "networkId": 73
+  }
+  
\ No newline at end of file
diff --git a/adapters/smartadserver/smartadservertest/params/race/video.json b/adapters/smartadserver/smartadservertest/params/race/video.json
new file mode 100644
index 00000000..b3408830
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/params/race/video.json
@@ -0,0 +1,7 @@
+{
+    "siteId": 1,
+    "pageId": 2,
+    "formatId": 3,
+    "networkId": 73
+  }
+  
\ No newline at end of file
diff --git a/adapters/smartadserver/smartadservertest/supplemental/request-no-bidder-object.json b/adapters/smartadserver/smartadservertest/supplemental/request-no-bidder-object.json
new file mode 100644
index 00000000..48664a66
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/supplemental/request-no-bidder-object.json
@@ -0,0 +1,21 @@
+{
+  "mockBidRequest": {
+    "id": "test-no-bidder",
+    "imp": [
+      {
+        "id": "test-imp-id-no-bidder",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+        }
+      }
+    ]
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Error parsing smartadserverExt parameters",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/supplemental/request-no-ext-object.json b/adapters/smartadserver/smartadservertest/supplemental/request-no-ext-object.json
new file mode 100644
index 00000000..d6637d0e
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/supplemental/request-no-ext-object.json
@@ -0,0 +1,19 @@
+{
+  "mockBidRequest": {
+    "id": "test-no-ext",
+    "imp": [
+      {
+        "id": "test-imp-id-no-ext",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        }
+      }
+    ]
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Error parsing bidderExt object",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/supplemental/request-no-imp.json b/adapters/smartadserver/smartadservertest/supplemental/request-no-imp.json
new file mode 100644
index 00000000..50e00a8a
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/supplemental/request-no-imp.json
@@ -0,0 +1,13 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+    ]
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "No impression in the bid request",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/supplemental/request-site-recreated.json b/adapters/smartadserver/smartadservertest/supplemental/request-site-recreated.json
new file mode 100644
index 00000000..4a402674
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/supplemental/request-site-recreated.json
@@ -0,0 +1,99 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "siteId": 1,
+            "pageId": 2,
+            "formatId": 3,
+            "networkId": 73
+          }
+        }
+      }
+    ],
+    "site": {
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://ssb.smartadserver.com/api/bid?callerId=5",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}]
+              },
+              "ext": {
+                "bidder": {
+                  "siteId": 1,
+                  "pageId": 2,
+                  "formatId": 3,
+                  "networkId": 73
+                }
+              }
+            }
+          ],
+          "site": {
+            "publisher": {
+              "id": "73"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "smartadserver",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 90,
+                "w": 728
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 728,
+            "h": 90
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/supplemental/response-200-without-body.json b/adapters/smartadserver/smartadservertest/supplemental/response-200-without-body.json
new file mode 100644
index 00000000..3e275694
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/supplemental/response-200-without-body.json
@@ -0,0 +1,62 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "siteId": 1,
+            "pageId": 2,
+            "formatId": 3,
+            "networkId": 73
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://ssb.smartadserver.com/api/bid?callerId=5",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}]
+              },
+              "ext": {
+                "bidder": {
+                  "siteId": 1,
+                  "pageId": 2,
+                  "formatId": 3,
+                  "networkId": 73
+                }
+              }
+            }
+          ],
+          "site": {
+            "publisher": {
+              "id": "73"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "unexpected end of JSON input",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/supplemental/response-204.json b/adapters/smartadserver/smartadservertest/supplemental/response-204.json
new file mode 100644
index 00000000..32aa2642
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/supplemental/response-204.json
@@ -0,0 +1,56 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "siteId": 1,
+            "pageId": 2,
+            "formatId": 3,
+            "networkId": 73
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://ssb.smartadserver.com/api/bid?callerId=5",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}]
+              },
+              "ext": {
+                "bidder": {
+                  "siteId": 1,
+                  "pageId": 2,
+                  "formatId": 3,
+                  "networkId": 73
+                }
+              }
+            }
+          ],
+          "site": {
+            "publisher": {
+              "id": "73"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 204
+      }
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/supplemental/response-400.json b/adapters/smartadserver/smartadservertest/supplemental/response-400.json
new file mode 100644
index 00000000..b7d5a954
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/supplemental/response-400.json
@@ -0,0 +1,62 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "siteId": 1,
+            "pageId": 2,
+            "formatId": 3,
+            "networkId": 73
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://ssb.smartadserver.com/api/bid?callerId=5",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}]
+              },
+              "ext": {
+                "bidder": {
+                  "siteId": 1,
+                  "pageId": 2,
+                  "formatId": 3,
+                  "networkId": 73
+                }
+              }
+            }
+          ],
+          "site": {
+            "publisher": {
+              "id": "73"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 400
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/smartadserver/smartadservertest/supplemental/response-500.json b/adapters/smartadserver/smartadservertest/supplemental/response-500.json
new file mode 100644
index 00000000..727e8f08
--- /dev/null
+++ b/adapters/smartadserver/smartadservertest/supplemental/response-500.json
@@ -0,0 +1,62 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "siteId": 1,
+            "pageId": 2,
+            "formatId": 3,
+            "networkId": 73
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://ssb.smartadserver.com/api/bid?callerId=5",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}]
+              },
+              "ext": {
+                "bidder": {
+                  "siteId": 1,
+                  "pageId": 2,
+                  "formatId": 3,
+                  "networkId": 73
+                }
+              }
+            }
+          ],
+          "site": {
+            "publisher": {
+              "id": "73"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 500
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 500. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/smartadserver/usersync_test.go b/adapters/smartadserver/usersync_test.go
new file mode 100644
index 00000000..e279b49e
--- /dev/null
+++ b/adapters/smartadserver/usersync_test.go
@@ -0,0 +1,35 @@
+package smartadserver
+
+import (
+	"testing"
+	"text/template"
+
+	"github.com/prebid/prebid-server/privacy"
+	"github.com/prebid/prebid-server/privacy/ccpa"
+	"github.com/prebid/prebid-server/privacy/gdpr"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestSmartadserverSyncer(t *testing.T) {
+	syncURL := "//ssbsync.smartadserver.com/getuid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url=localhost%2Fsetuid%3Fbidder%3Dsmartadserver%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bsas_uid%5D%22"
+	syncURLTemplate := template.Must(
+		template.New("sync-template").Parse(syncURL),
+	)
+
+	syncer := NewSmartadserverSyncer(syncURLTemplate)
+	syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+		GDPR: gdpr.Policy{
+			Signal:  "1",
+			Consent: "COyASAoOyASAoAfAAAENAfCAAAAAAAAAAAAAAAAAAAAA",
+		},
+		CCPA: ccpa.Policy{
+			Value: "1YNN",
+		},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, "//ssbsync.smartadserver.com/getuid?gdpr=1&gdpr_consent=COyASAoOyASAoAfAAAENAfCAAAAAAAAAAAAAAAAAAAAA&us_privacy=1YNN&url=localhost%2Fsetuid%3Fbidder%3Dsmartadserver%26gdpr%3D1%26gdpr_consent%3DCOyASAoOyASAoAfAAAENAfCAAAAAAAAAAAAAAAAAAAAA%26uid%3D%5Bsas_uid%5D%22", syncInfo.URL)
+	assert.Equal(t, "redirect", syncInfo.Type)
+	assert.EqualValues(t, 45, syncer.GDPRVendorID())
+	assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/adapters/triplelift/triplelift_test.go b/adapters/triplelift/triplelift_test.go
index 2d7ed04f..6fd2b506 100644
--- a/adapters/triplelift/triplelift_test.go
+++ b/adapters/triplelift/triplelift_test.go
@@ -6,5 +6,5 @@ import (
 )
 
 func TestJsonSamples(t *testing.T) {
-	adapterstest.RunJSONBidderTest(t, "triplelifttest", NewTripleliftBidder(nil, "http://tlx.3lift.net/s2s/auction?supplier_id=20"))
+	adapterstest.RunJSONBidderTest(t, "triplelifttest", NewTripleliftBidder(nil, "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20"))
 }
diff --git a/adapters/triplelift/triplelifttest/exemplary/optional-params.json b/adapters/triplelift/triplelifttest/exemplary/optional-params.json
index 0851bc09..90c8da5b 100644
--- a/adapters/triplelift/triplelifttest/exemplary/optional-params.json
+++ b/adapters/triplelift/triplelifttest/exemplary/optional-params.json
@@ -28,7 +28,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "http://tlx.3lift.net/s2s/auction?supplier_id=20",
+        "uri": "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20",
         "body": {
           "id": "test-request-id",
           "imp": [
diff --git a/adapters/triplelift/triplelifttest/exemplary/simple-banner.json b/adapters/triplelift/triplelifttest/exemplary/simple-banner.json
index ff680037..156e07e3 100644
--- a/adapters/triplelift/triplelifttest/exemplary/simple-banner.json
+++ b/adapters/triplelift/triplelifttest/exemplary/simple-banner.json
@@ -27,7 +27,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "http://tlx.3lift.net/s2s/auction?supplier_id=20",
+        "uri": "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20",
         "body": {
           "id": "test-request-id",
           "imp": [
diff --git a/adapters/triplelift/triplelifttest/exemplary/simple-video.json b/adapters/triplelift/triplelifttest/exemplary/simple-video.json
index 185446bd..846c62b4 100644
--- a/adapters/triplelift/triplelifttest/exemplary/simple-video.json
+++ b/adapters/triplelift/triplelifttest/exemplary/simple-video.json
@@ -33,7 +33,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "http://tlx.3lift.net/s2s/auction?supplier_id=20",
+        "uri": "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20",
         "body": {
           "id": "test-request-id",
           "imp": [
@@ -85,7 +85,7 @@
                   "adomain": [
                     "foo.com"
                   ],
-                  "iurl": "http://tlx.3lift.net/s2s/auction?supplier_id=20",
+                  "iurl": "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20",
                   "cid": "958",
                   "crid": "29681110",
                   "h": 250,
@@ -122,7 +122,7 @@
             "adomain": [
               "foo.com"
             ],
-            "iurl": "http://tlx.3lift.net/s2s/auction?supplier_id=20",
+            "iurl": "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20",
             "cid": "958",
             "crid": "29681110",
             "w": 300,
diff --git a/adapters/triplelift/triplelifttest/supplemental/badresponseext.json b/adapters/triplelift/triplelifttest/supplemental/badresponseext.json
index 324c0582..6c09448f 100644
--- a/adapters/triplelift/triplelifttest/supplemental/badresponseext.json
+++ b/adapters/triplelift/triplelifttest/supplemental/badresponseext.json
@@ -27,7 +27,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "http://tlx.3lift.net/s2s/auction?supplier_id=20",
+        "uri": "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20",
         "body": {
           "id": "test-request-id",
           "imp": [
diff --git a/adapters/triplelift/triplelifttest/supplemental/badstatuscode.json b/adapters/triplelift/triplelifttest/supplemental/badstatuscode.json
index 15799616..f24eb799 100644
--- a/adapters/triplelift/triplelifttest/supplemental/badstatuscode.json
+++ b/adapters/triplelift/triplelifttest/supplemental/badstatuscode.json
@@ -27,7 +27,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "http://tlx.3lift.net/s2s/auction?supplier_id=20",
+        "uri": "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20",
         "body": {
           "id": "test-request-id",
           "imp": [
diff --git a/adapters/triplelift/triplelifttest/supplemental/notgoodstatuscode.json b/adapters/triplelift/triplelifttest/supplemental/notgoodstatuscode.json
index 963db593..bdcc0e3a 100644
--- a/adapters/triplelift/triplelifttest/supplemental/notgoodstatuscode.json
+++ b/adapters/triplelift/triplelifttest/supplemental/notgoodstatuscode.json
@@ -27,7 +27,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "http://tlx.3lift.net/s2s/auction?supplier_id=20",
+        "uri": "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20",
         "body": {
           "id": "test-request-id",
           "imp": [
diff --git a/config/config_test.go b/config/config_test.go
index ee8e68e7..2b291fe9 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -43,6 +43,8 @@ gdpr:
   non_standard_publishers: ["siteID","fake-site-id","appID","agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA"]
 ccpa:
   enforce: true
+lmt:
+  enforce: true
 host_cookie:
   cookie_name: userid
   family: prebid
@@ -240,6 +242,7 @@ func TestFullConfig(t *testing.T) {
 	cmpBools(t, "cfg.GDPR.NonStandardPublisherMap", found, false)
 
 	cmpBools(t, "ccpa.enforce", cfg.CCPA.Enforce, true)
+	cmpBools(t, "lmt.enforce", cfg.LMT.Enforce, true)
 
 	//Assert the NonStandardPublishers was correctly unmarshalled
 	cmpStrings(t, "blacklisted_apps", cfg.BlacklistedApps[0], "spamAppID")
diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go
index 289db3f4..731fd55e 100644
--- a/endpoints/openrtb2/amp_auction_test.go
+++ b/endpoints/openrtb2/amp_auction_test.go
@@ -832,6 +832,24 @@ func TestMultisize(t *testing.T) {
 	}.execute(t)
 }
 
+func TestSizeWithMultisize(t *testing.T) {
+	formatOverrideSpec{
+		width:     20,
+		height:    40,
+		multisize: "200x50,100x60",
+		expect: []openrtb.Format{{
+			W: 20,
+			H: 40,
+		}, {
+			W: 200,
+			H: 50,
+		}, {
+			W: 100,
+			H: 60,
+		}},
+	}.execute(t)
+}
+
 func TestHeightOnly(t *testing.T) {
 	formatOverrideSpec{
 		height: 200,
diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go
index fa04e6a4..fff397f0 100644
--- a/exchange/bidder_test.go
+++ b/exchange/bidder_test.go
@@ -1229,6 +1229,64 @@ func TestSetAssetTypes(t *testing.T) {
 	}
 }
 
+func TestTimeoutNotificationOff(t *testing.T) {
+	respBody := "{\"bid\":false}"
+	respStatus := 200
+	server := httptest.NewServer(mockHandler(respStatus, "getBody", respBody))
+	defer server.Close()
+
+	bidderImpl := &notifingBidder{
+		notiRequest: adapters.RequestData{
+			Method:  "GET",
+			Uri:     server.URL + "/notify/me",
+			Body:    nil,
+			Headers: http.Header{},
+		},
+	}
+	bidder := &bidderAdapter{
+		Bidder:      bidderImpl,
+		Client:      server.Client(),
+		DebugConfig: config.Debug{},
+		me:          &metricsConfig.DummyMetricsEngine{},
+	}
+	if tb, ok := bidder.Bidder.(adapters.TimeoutBidder); !ok {
+		t.Error("Failed to cast bidder to a TimeoutBidder")
+	} else {
+		bidder.doTimeoutNotification(tb, &adapters.RequestData{})
+	}
+}
+
+func TestTimeoutNotificationOn(t *testing.T) {
+	respBody := "{\"bid\":false}"
+	respStatus := 200
+	server := httptest.NewServer(mockHandler(respStatus, "getBody", respBody))
+	defer server.Close()
+
+	bidderImpl := &notifingBidder{
+		notiRequest: adapters.RequestData{
+			Method:  "GET",
+			Uri:     server.URL + "/notify/me",
+			Body:    nil,
+			Headers: http.Header{},
+		},
+	}
+	bidder := &bidderAdapter{
+		Bidder: bidderImpl,
+		Client: server.Client(),
+		DebugConfig: config.Debug{
+			TimeoutNotification: config.TimeoutNotification{
+				Log: true,
+			},
+		},
+		me: &metricsConfig.DummyMetricsEngine{},
+	}
+	if tb, ok := bidder.Bidder.(adapters.TimeoutBidder); !ok {
+		t.Error("Failed to cast bidder to a TimeoutBidder")
+	} else {
+		bidder.doTimeoutNotification(tb, &adapters.RequestData{})
+	}
+}
+
 type goodSingleBidder struct {
 	bidRequest   *openrtb.BidRequest
 	httpRequest  *adapters.RequestData
@@ -1302,3 +1360,19 @@ func (bidder *bidRejector) MakeBids(internalRequest *openrtb.BidRequest, externa
 	bidder.httpResponse = response
 	return nil, []error{errors.New("Can't make a response.")}
 }
+
+type notifingBidder struct {
+	notiRequest adapters.RequestData
+}
+
+func (bidder *notifingBidder) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	return nil, nil
+}
+
+func (bidder *notifingBidder) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	return nil, nil
+}
+
+func (bidder *notifingBidder) MakeTimeoutNotification(req *adapters.RequestData) (*adapters.RequestData, []error) {
+	return &bidder.notiRequest, nil
+}
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index e9b2127e..93cb60fb 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -582,7 +582,15 @@ func TestPanicRecovery(t *testing.T) {
 	panicker := func(aName openrtb_ext.BidderName, coreBidder openrtb_ext.BidderName, request *openrtb.BidRequest, bidlabels *pbsmetrics.AdapterLabels, conversions currencies.Conversions) {
 		panic("panic!")
 	}
-	recovered := e.recoverSafely(panicker, chBids)
+	cleanReqs := map[openrtb_ext.BidderName]*openrtb.BidRequest{
+		"bidder1": {
+			ID: "b-1",
+		},
+		"bidder2": {
+			ID: "b-2",
+		},
+	}
+	recovered := e.recoverSafely(cleanReqs, panicker, chBids)
 	apnLabels := pbsmetrics.AdapterLabels{
 		Source:      pbsmetrics.DemandWeb,
 		RType:       pbsmetrics.ReqTypeORTB2Web,
@@ -731,7 +739,17 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) {
 	if len(errs) != 0 {
 		t.Fatalf("%s: Failed to parse aliases", filename)
 	}
-	ex := newExchangeForTests(t, filename, spec.OutgoingRequests, aliases, spec.EnforceCCPA)
+
+	privacyConfig := config.Privacy{
+		CCPA: config.CCPA{
+			Enforce: spec.EnforceCCPA,
+		},
+		LMT: config.LMT{
+			Enforce: spec.EnforceLMT,
+		},
+	}
+
+	ex := newExchangeForTests(t, filename, spec.OutgoingRequests, aliases, privacyConfig)
 	biddersInAuction := findBiddersInAuction(t, filename, &spec.IncomingRequest.OrtbRequest)
 	categoriesFetcher, error := newCategoryFetcher("./test/category-mapping")
 	if error != nil {
@@ -816,7 +834,7 @@ func extractResponseTimes(t *testing.T, context string, bid *openrtb.BidResponse
 	}
 }
 
-func newExchangeForTests(t *testing.T, filename string, expectations map[string]*bidderSpec, aliases map[string]string, enforceCCPA bool) Exchange {
+func newExchangeForTests(t *testing.T, filename string, expectations map[string]*bidderSpec, aliases map[string]string, privacyConfig config.Privacy) Exchange {
 	adapters := make(map[openrtb_ext.BidderName]adaptedBidder)
 	for _, bidderName := range openrtb_ext.BidderMap {
 		if spec, ok := expectations[string(bidderName)]; ok {
@@ -854,7 +872,7 @@ func newExchangeForTests(t *testing.T, filename string, expectations map[string]
 		gDPR:                gdpr.AlwaysAllow{},
 		currencyConverter:   currencies.NewRateConverterDefault(),
 		UsersyncIfAmbiguous: false,
-		enforceCCPA:         enforceCCPA,
+		privacyConfig:       privacyConfig,
 	}
 }
 
@@ -1620,6 +1638,7 @@ type exchangeSpec struct {
 	OutgoingRequests map[string]*bidderSpec `json:"outgoingRequests"`
 	Response         exchangeResponse       `json:"response,omitempty"`
 	EnforceCCPA      bool                   `json:"enforceCcpa"`
+	EnforceLMT       bool                   `json:"enforceLmt"`
 	DebugLog         *DebugLog              `json:"debuglog,omitempty"`
 }
 
diff --git a/exchange/exchangetest/lmt-featureflag-off.json b/exchange/exchangetest/lmt-featureflag-off.json
new file mode 100644
index 00000000..9a15c879
--- /dev/null
+++ b/exchange/exchangetest/lmt-featureflag-off.json
@@ -0,0 +1,63 @@
+{
+    "enforceLmt": false,
+    "incomingRequest": {
+        "ortbRequest": {
+            "id": "some-request-id",
+            "site": {
+                "page": "test.somepage.com"
+            },
+            "imp": [{
+                "id": "my-imp-id",
+                "video": {
+                    "mimes": ["video/mp4"]
+                },
+                "ext": {
+                    "appnexus": {
+                        "placementId": 1
+                    }
+                }
+            }],
+            "device": {
+                "lmt": 1
+            },
+            "user": {
+                "id": "some-id",
+                "buyeruid": "some-buyer-id"
+            }
+        }
+    },
+    "outgoingRequests": {
+        "appnexus": {
+            "expectRequest": {
+                "ortbRequest": {
+                    "id": "some-request-id",
+                    "site": {
+                        "page": "test.somepage.com"
+                    },
+                    "imp": [{
+                        "id": "my-imp-id",
+                        "video": {
+                            "mimes": ["video/mp4"]
+                        },
+                        "ext": {
+                            "bidder": {
+                                "placementId": 1
+                            }
+                        }
+                    }],
+                    "device": {
+                        "lmt": 1
+                    },
+                    "user": {
+                        "id": "some-id",
+                        "buyeruid": "some-buyer-id"
+                    }
+                },
+                "bidAdjustment": 1.0
+            },
+            "mockResponse": {
+                "errors": ["appnexus-error"]
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/exchange/exchangetest/lmt-featureflag-on.json b/exchange/exchangetest/lmt-featureflag-on.json
new file mode 100644
index 00000000..440f8c76
--- /dev/null
+++ b/exchange/exchangetest/lmt-featureflag-on.json
@@ -0,0 +1,61 @@
+{
+    "enforceLmt": true,
+    "incomingRequest": {
+        "ortbRequest": {
+            "id": "some-request-id",
+            "site": {
+                "page": "test.somepage.com"
+            },
+            "imp": [{
+                "id": "my-imp-id",
+                "video": {
+                    "mimes": ["video/mp4"]
+                },
+                "ext": {
+                    "appnexus": {
+                        "placementId": 1
+                    }
+                }
+            }],
+            "device": {
+                "lmt": 1
+            },
+            "user": {
+                "id": "some-id",
+                "buyeruid": "some-buyer-id"
+            }
+        }
+    },
+    "outgoingRequests": {
+        "appnexus": {
+            "expectRequest": {
+                "ortbRequest": {
+                    "id": "some-request-id",
+                    "site": {
+                        "page": "test.somepage.com"
+                    },
+                    "imp": [{
+                        "id": "my-imp-id",
+                        "video": {
+                            "mimes": ["video/mp4"]
+                        },
+                        "ext": {
+                            "bidder": {
+                                "placementId": 1
+                            }
+                        }
+                    }],
+                    "device": {
+                        "lmt": 1
+                    },
+                    "user": {
+                    }
+                },
+                "bidAdjustment": 1.0
+            },
+            "mockResponse": {
+                "errors": ["appnexus-error"]
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index acbf25ff..4dad3f54 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/prebid/prebid-server/pbsmetrics"
 	"github.com/stretchr/testify/assert"
@@ -69,8 +70,17 @@ func TestCleanOpenRTBRequests(t *testing.T) {
 			applyCOPPA: false, consentedVendors: map[string]bool{"appnexus": true, "brightroll": true}},
 	}
 
+	privacyConfig := config.Privacy{
+		CCPA: config.CCPA{
+			Enforce: true,
+		},
+		LMT: config.LMT{
+			Enforce: true,
+		},
+	}
+
 	for _, test := range testCases {
-		reqByBidders, _, err := cleanOpenRTBRequests(context.Background(), test.req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{}, true, true)
+		reqByBidders, _, err := cleanOpenRTBRequests(context.Background(), test.req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{}, true, privacyConfig)
 		if test.hasError {
 			assert.NotNil(t, err, "Error shouldn't be nil")
 		} else {
@@ -99,9 +109,80 @@ func TestCleanOpenRTBRequestsCCPA(t *testing.T) {
 	}
 
 	for _, test := range testCases {
-		req := newCCPABidRequest(t)
+		req := newBidRequest(t)
+		req.Regs = &openrtb.Regs{
+			Ext: json.RawMessage(`{"us_privacy":"1-Y-"}`),
+		}
 
-		results, _, errs := cleanOpenRTBRequests(context.Background(), req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{}, true, test.enforceCCPA)
+		privacyConfig := config.Privacy{
+			CCPA: config.CCPA{
+				Enforce: test.enforceCCPA,
+			},
+		}
+
+		results, _, errs := cleanOpenRTBRequests(context.Background(), req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{}, true, privacyConfig)
+		result := results["appnexus"]
+
+		assert.Nil(t, errs)
+
+		if test.expectDataScrub {
+			assert.Equal(t, result.User.BuyerUID, "", test.description+":User.BuyerUID")
+			assert.Equal(t, result.Device.DIDMD5, "", test.description+":Device.DIDMD5")
+		} else {
+			assert.NotEqual(t, result.User.BuyerUID, "", test.description+":User.BuyerUID")
+			assert.NotEqual(t, result.Device.DIDMD5, "", test.description+":Device.DIDMD5")
+		}
+	}
+}
+
+func TestCleanOpenRTBRequestsLMT(t *testing.T) {
+	var (
+		enabled  int8 = 1
+		disabled int8 = 0
+	)
+	testCases := []struct {
+		description     string
+		lmt             *int8
+		enforceLMT      bool
+		expectDataScrub bool
+	}{
+		{
+			description:     "Feature Flag Enabled - OpenTRB Enabled",
+			lmt:             &enabled,
+			enforceLMT:      true,
+			expectDataScrub: true,
+		},
+		{
+			description:     "Feature Flag Disabled - OpenTRB Enabled",
+			lmt:             &enabled,
+			enforceLMT:      false,
+			expectDataScrub: false,
+		},
+		{
+			description:     "Feature Flag Enabled - OpenTRB Disabled",
+			lmt:             &disabled,
+			enforceLMT:      true,
+			expectDataScrub: false,
+		},
+		{
+			description:     "Feature Flag Disabled - OpenTRB Disabled",
+			lmt:             &disabled,
+			enforceLMT:      false,
+			expectDataScrub: false,
+		},
+	}
+
+	for _, test := range testCases {
+		req := newBidRequest(t)
+		req.Device.Lmt = test.lmt
+
+		privacyConfig := config.Privacy{
+			LMT: config.LMT{
+				Enforce: test.enforceLMT,
+			},
+		}
+
+		results, _, errs := cleanOpenRTBRequests(context.Background(), req, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{}, true, privacyConfig)
 		result := results["appnexus"]
 
 		assert.Nil(t, errs)
@@ -163,8 +244,7 @@ func newAdapterAliasBidRequest(t *testing.T) *openrtb.BidRequest {
 	}
 }
 
-func newCCPABidRequest(t *testing.T) *openrtb.BidRequest {
-	dnt := int8(1)
+func newBidRequest(t *testing.T) *openrtb.BidRequest {
 	return &openrtb.BidRequest{
 		Site: &openrtb.Site{
 			Page:   "www.some.domain.com",
@@ -178,7 +258,6 @@ func newCCPABidRequest(t *testing.T) *openrtb.BidRequest {
 			UA:       "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
 			IFA:      "ifa",
 			IP:       "132.173.230.74",
-			DNT:      &dnt,
 			Language: "EN",
 		},
 		Source: &openrtb.Source{
@@ -189,9 +268,6 @@ func newCCPABidRequest(t *testing.T) *openrtb.BidRequest {
 			BuyerUID: "their-id",
 			Ext:      json.RawMessage(`{"digitrust":{"id":"digi-id","keyv":1,"pref":1}}`),
 		},
-		Regs: &openrtb.Regs{
-			Ext: json.RawMessage(`{"us_privacy":"1-Y-"}`),
-		},
 		Imp: []openrtb.Imp{{
 			ID: "some-imp-id",
 			Banner: &openrtb.Banner{
diff --git a/privacy/enforcement_test.go b/privacy/enforcement_test.go
index 0e82648d..968c6354 100644
--- a/privacy/enforcement_test.go
+++ b/privacy/enforcement_test.go
@@ -21,6 +21,7 @@ func TestAny(t *testing.T) {
 				COPPA:   false,
 				GDPR:    false,
 				GDPRGeo: false,
+				LMT:     false,
 			},
 			expected: false,
 		},
@@ -31,6 +32,7 @@ func TestAny(t *testing.T) {
 				COPPA:   true,
 				GDPR:    true,
 				GDPRGeo: true,
+				LMT:     true,
 			},
 			expected: true,
 		},
@@ -41,16 +43,7 @@ func TestAny(t *testing.T) {
 				COPPA:   true,
 				GDPR:    false,
 				GDPRGeo: false,
-			},
-			expected: true,
-		},
-		{
-			description: "GDPRGeo only",
-			enforcement: Enforcement{
-				CCPA:    false,
-				COPPA:   false,
-				GDPR:    false,
-				GDPRGeo: true,
+				LMT:     true,
 			},
 			expected: true,
 		},
@@ -79,6 +72,7 @@ func TestApply(t *testing.T) {
 				COPPA:   true,
 				GDPR:    true,
 				GDPRGeo: true,
+				LMT:     true,
 			},
 			ampGDPRException:   false,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
@@ -93,6 +87,7 @@ func TestApply(t *testing.T) {
 				COPPA:   false,
 				GDPR:    false,
 				GDPRGeo: false,
+				LMT:     false,
 			},
 			ampGDPRException:   false,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
@@ -107,6 +102,7 @@ func TestApply(t *testing.T) {
 				COPPA:   true,
 				GDPR:    false,
 				GDPRGeo: false,
+				LMT:     false,
 			},
 			ampGDPRException:   false,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
@@ -121,6 +117,7 @@ func TestApply(t *testing.T) {
 				COPPA:   false,
 				GDPR:    true,
 				GDPRGeo: true,
+				LMT:     false,
 			},
 			ampGDPRException:   false,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
@@ -135,6 +132,7 @@ func TestApply(t *testing.T) {
 				COPPA:   false,
 				GDPR:    true,
 				GDPRGeo: true,
+				LMT:     false,
 			},
 			ampGDPRException:   true,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
@@ -149,6 +147,7 @@ func TestApply(t *testing.T) {
 				COPPA:   false,
 				GDPR:    false,
 				GDPRGeo: false,
+				LMT:     false,
 			},
 			ampGDPRException:   true,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
@@ -163,6 +162,7 @@ func TestApply(t *testing.T) {
 				COPPA:   true,
 				GDPR:    true,
 				GDPRGeo: true,
+				LMT:     false,
 			},
 			ampGDPRException:   true,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
@@ -177,6 +177,7 @@ func TestApply(t *testing.T) {
 				COPPA:   false,
 				GDPR:    true,
 				GDPRGeo: false,
+				LMT:     false,
 			},
 			ampGDPRException:   false,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
@@ -191,6 +192,7 @@ func TestApply(t *testing.T) {
 				COPPA:   false,
 				GDPR:    false,
 				GDPRGeo: true,
+				LMT:     false,
 			},
 			ampGDPRException:   false,
 			expectedDeviceIPv6: ScrubStrategyIPV6None,
@@ -198,6 +200,36 @@ func TestApply(t *testing.T) {
 			expectedUser:       ScrubStrategyUserNone,
 			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
 		},
+		{
+			description: "LMT Only",
+			enforcement: Enforcement{
+				CCPA:    false,
+				COPPA:   false,
+				GDPR:    false,
+				GDPRGeo: false,
+				LMT:     true,
+			},
+			ampGDPRException:   false,
+			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
+			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
+			expectedUser:       ScrubStrategyUserID,
+			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
+		},
+		{
+			description: "LMT Only, ampGDPRException",
+			enforcement: Enforcement{
+				CCPA:    false,
+				COPPA:   false,
+				GDPR:    false,
+				GDPRGeo: false,
+				LMT:     true,
+			},
+			ampGDPRException:   true,
+			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
+			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
+			expectedUser:       ScrubStrategyUserID,
+			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
+		},
 	}
 
 	for _, test := range testCases {
@@ -229,6 +261,7 @@ func TestApplyNoneApplicable(t *testing.T) {
 		CCPA:  false,
 		COPPA: false,
 		GDPR:  false,
+		LMT:   false,
 	}
 	enforcement.apply(req, false, m)
 
diff --git a/privacy/lmt/policy_test.go b/privacy/lmt/policy_test.go
new file mode 100644
index 00000000..45de219a
--- /dev/null
+++ b/privacy/lmt/policy_test.go
@@ -0,0 +1,128 @@
+package lmt
+
+import (
+	"testing"
+
+	"github.com/mxmCherry/openrtb"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestRead(t *testing.T) {
+	var one int8 = 1
+
+	testCases := []struct {
+		description    string
+		request        *openrtb.BidRequest
+		expectedPolicy Policy
+	}{
+		{
+			description: "Nil Request",
+			request:     nil,
+			expectedPolicy: Policy{
+				Signal:         0,
+				SignalProvided: false,
+			},
+		},
+		{
+			description: "Nil Device",
+			request: &openrtb.BidRequest{
+				Device: nil,
+			},
+			expectedPolicy: Policy{
+				Signal:         0,
+				SignalProvided: false,
+			},
+		},
+		{
+			description: "Nil Device.Lmt",
+			request: &openrtb.BidRequest{
+				Device: &openrtb.Device{
+					Lmt: nil,
+				},
+			},
+			expectedPolicy: Policy{
+				Signal:         0,
+				SignalProvided: false,
+			},
+		},
+		{
+			description: "Enabled",
+			request: &openrtb.BidRequest{
+				Device: &openrtb.Device{
+					Lmt: &one,
+				},
+			},
+			expectedPolicy: Policy{
+				Signal:         1,
+				SignalProvided: true,
+			},
+		},
+	}
+
+	for _, test := range testCases {
+		p := ReadPolicy(test.request)
+		assert.Equal(t, test.expectedPolicy, p, test.description)
+	}
+}
+
+func TestShouldEnforce(t *testing.T) {
+	testCases := []struct {
+		description string
+		policy      Policy
+		expected    bool
+	}{
+		{
+			description: "Signal Not Provided - Zero",
+			policy: Policy{
+				Signal:         0,
+				SignalProvided: false,
+			},
+			expected: false,
+		},
+		{
+			description: "Signal Not Provided - One",
+			policy: Policy{
+				Signal:         1,
+				SignalProvided: false,
+			},
+			expected: false,
+		},
+		{
+			description: "Signal Not Provided - Other",
+			policy: Policy{
+				Signal:         42,
+				SignalProvided: false,
+			},
+			expected: false,
+		},
+		{
+			description: "Signal Provided - Zero",
+			policy: Policy{
+				Signal:         0,
+				SignalProvided: true,
+			},
+			expected: false,
+		},
+		{
+			description: "Signal Provided - One",
+			policy: Policy{
+				Signal:         1,
+				SignalProvided: true,
+			},
+			expected: true,
+		},
+		{
+			description: "Signal Provided - Other",
+			policy: Policy{
+				Signal:         42,
+				SignalProvided: true,
+			},
+			expected: false,
+		},
+	}
+
+	for _, test := range testCases {
+		result := test.policy.ShouldEnforce()
+		assert.Equal(t, test.expected, result, test.description)
+	}
+}
diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go
index c9ef382f..363cd491 100755
--- a/usersync/usersyncers/syncer_test.go
+++ b/usersync/usersyncers/syncer_test.go
@@ -26,6 +26,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderAdvangelists):     syncConfig,
 			string(openrtb_ext.BidderAJA):              syncConfig,
 			string(openrtb_ext.BidderAppnexus):         syncConfig,
+			string(openrtb_ext.BidderAvocet):           syncConfig,
 			string(openrtb_ext.BidderBeachfront):       syncConfig,
 			string(openrtb_ext.BidderBeintoo):          syncConfig,
 			string(openrtb_ext.BidderBrightroll):       syncConfig,
@@ -61,6 +62,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderSomoaudience):     syncConfig,
 			string(openrtb_ext.BidderSonobi):           syncConfig,
 			string(openrtb_ext.BidderSovrn):            syncConfig,
+			string(openrtb_ext.BidderSmartadserver):    syncConfig,
 			string(openrtb_ext.BidderSmartRTB):         syncConfig,
 			string(openrtb_ext.BidderSynacormedia):     syncConfig,
 			string(openrtb_ext.BidderTelaria):          syncConfig,