Repository: prebid/prebid-server
Pull request #1238 (2020-03-31 23:41:31)

#615 Beachfront URLs from config
Added getting Beachfront URLs from config


Patch:
diff --git a/adapters/beachfront/beachfront.go b/adapters/beachfront/beachfront.go
index e2eb31b3..34a198e9 100644
--- a/adapters/beachfront/beachfront.go
+++ b/adapters/beachfront/beachfront.go
@@ -4,26 +4,27 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"github.com/mxmCherry/openrtb"
-	"github.com/prebid/prebid-server/adapters"
-	"github.com/prebid/prebid-server/errortypes"
-	"github.com/prebid/prebid-server/openrtb_ext"
 	"net/http"
 	"reflect"
 	"strconv"
 	"strings"
+
+	"github.com/golang/glog"
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
 const Seat = "beachfront"
 const BidCapacity = 5
 
-const bannerEndpoint = "https://display.bfmio.com/prebid_display"
-const videoEndpoint = "https://reachms.bfmio.com/bid.json?exchange_id"
+const defaultVideoEndpoint = "https://reachms.bfmio.com/bid.json?exchange_id"
 
 const nurlVideoEndpointSuffix = "&prebidserver"
 
 const beachfrontAdapterName = "BF_PREBID_S2S"
-const beachfrontAdapterVersion = "0.8.0"
+const beachfrontAdapterVersion = "0.9.0"
 
 const minBidFloor = 0.01
 
@@ -31,6 +32,12 @@ const DefaultVideoWidth = 300
 const DefaultVideoHeight = 250
 
 type BeachfrontAdapter struct {
+	bannerEndpoint string
+	extraInfo      ExtraInfo
+}
+
+type ExtraInfo struct {
+	VideoEndpoint string `json:"video_endpoint,omitempty"`
 }
 
 type beachfrontRequests struct {
@@ -138,7 +145,7 @@ func (a *BeachfrontAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *a
 		if err == nil {
 			reqs[0] = &adapters.RequestData{
 				Method:  "POST",
-				Uri:     bannerEndpoint,
+				Uri:     a.bannerEndpoint,
 				Body:    bytes,
 				Headers: headers,
 			}
@@ -159,7 +166,7 @@ func (a *BeachfrontAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *a
 		if err == nil {
 			reqs[j+nurlBump] = &adapters.RequestData{
 				Method:  "POST",
-				Uri:     videoEndpoint + "=" + beachfrontRequests.ADMVideo[j].AppId,
+				Uri:     a.extraInfo.VideoEndpoint + "=" + beachfrontRequests.ADMVideo[j].AppId,
 				Body:    bytes,
 				Headers: headers,
 			}
@@ -178,7 +185,7 @@ func (a *BeachfrontAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *a
 			bytes = append([]byte(`{"isPrebid":true,`), bytes[1:]...)
 			reqs[j+admBump] = &adapters.RequestData{
 				Method:  "POST",
-				Uri:     videoEndpoint + "=" + beachfrontRequests.NurlVideo[j].AppId + nurlVideoEndpointSuffix,
+				Uri:     a.extraInfo.VideoEndpoint + "=" + beachfrontRequests.NurlVideo[j].AppId + nurlVideoEndpointSuffix,
 				Body:    bytes,
 				Headers: headers,
 			}
@@ -518,13 +525,13 @@ func (a *BeachfrontAdapter) MakeBids(internalRequest *openrtb.BidRequest, extern
 
 			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
 				Bid:      &bids[i],
-				BidType:  getBidType(externalRequest),
+				BidType:  a.getBidType(externalRequest),
 				BidVideo: &impVideo,
 			})
 		} else {
 			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
 				Bid:     &bids[i],
-				BidType: getBidType(externalRequest),
+				BidType: a.getBidType(externalRequest),
 			})
 		}
 	}
@@ -532,6 +539,15 @@ func (a *BeachfrontAdapter) MakeBids(internalRequest *openrtb.BidRequest, extern
 	return bidResponse, errs
 }
 
+func (a *BeachfrontAdapter) getBidType(externalRequest *adapters.RequestData) openrtb_ext.BidType {
+	t := strings.Split(externalRequest.Uri, "=")[0]
+	if t == a.extraInfo.VideoEndpoint {
+		return openrtb_ext.BidTypeVideo
+	}
+
+	return openrtb_ext.BidTypeBanner
+}
+
 func postprocess(response *adapters.ResponseData, xtrnal openrtb.BidRequest, uri string, id string) ([]openrtb.Bid, []error) {
 	var beachfrontResp []beachfrontResponseSlot
 	var errs = make([]error, 0)
@@ -629,13 +645,13 @@ func getBeachfrontExtension(imp openrtb.Imp) (openrtb_ext.ExtImpBeachfront, erro
 }
 
 func getDomain(page string) string {
-	protoUrl := strings.Split(page, "//")
+	protoURL := strings.Split(page, "//")
 	var domainPage string
 
-	if len(protoUrl) > 1 {
-		domainPage = protoUrl[1]
+	if len(protoURL) > 1 {
+		domainPage = protoURL[1]
 	} else {
-		domainPage = protoUrl[0]
+		domainPage = protoURL[0]
 	}
 
 	return strings.Split(domainPage, "/")[0]
@@ -643,9 +659,9 @@ func getDomain(page string) string {
 }
 
 func isSecure(page string) int8 {
-	protoUrl := strings.Split(page, "://")
+	protoURL := strings.Split(page, "://")
 
-	if len(protoUrl) > 1 && protoUrl[0] == "https" {
+	if len(protoURL) > 1 && protoURL[0] == "https" {
 		return 1
 	}
 
@@ -663,19 +679,25 @@ func getIP(ip string) string {
 	return ip
 }
 
-func getBidType(externalRequest *adapters.RequestData) openrtb_ext.BidType {
-	t := strings.Split(externalRequest.Uri, "=")[0]
-	if t == videoEndpoint {
-		return openrtb_ext.BidTypeVideo
-	}
-
-	return openrtb_ext.BidTypeBanner
-}
-
 func removeVideoElement(slice []beachfrontVideoRequest, s int) []beachfrontVideoRequest {
 	return append(slice[:s], slice[s+1:]...)
 }
 
-func NewBeachfrontBidder() *BeachfrontAdapter {
-	return &BeachfrontAdapter{}
+func NewBeachfrontBidder(bannerEndpoint string, extraAdapterInfo string) adapters.Bidder {
+	var extraInfo ExtraInfo
+
+	if len(extraAdapterInfo) == 0 {
+		extraAdapterInfo = "{\"video_endpoint\":\"" + defaultVideoEndpoint + "\"}"
+	}
+
+	if err := json.Unmarshal([]byte(extraAdapterInfo), &extraInfo); err != nil {
+		glog.Fatal("Invalid Beachfront extra adapter info: " + err.Error())
+		return nil
+	}
+
+	if extraInfo.VideoEndpoint == "" {
+		extraInfo.VideoEndpoint = defaultVideoEndpoint
+	}
+
+	return &BeachfrontAdapter{bannerEndpoint: bannerEndpoint, extraInfo: extraInfo}
 }
diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go
index 46caf262..dad85ee1 100644
--- a/adapters/rubicon/rubicon.go
+++ b/adapters/rubicon/rubicon.go
@@ -21,6 +21,8 @@ import (
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
+const badvLimitSize = 50
+
 type RubiconAdapter struct {
 	http         *adapters.HTTPAdapter
 	URI          string
@@ -740,6 +742,13 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adap
 			request.App = &appCopy
 		}
 
+		reqBadv := request.BAdv
+		if reqBadv != nil {
+			if len(reqBadv) > badvLimitSize {
+				request.BAdv = reqBadv[:badvLimitSize]
+			}
+		}
+
 		request.Imp = []openrtb.Imp{thisImp}
 		request.Cur = nil
 		request.Ext = nil
diff --git a/adapters/telaria/telaria.go b/adapters/telaria/telaria.go
new file mode 100644
index 00000000..9edafa86
--- /dev/null
+++ b/adapters/telaria/telaria.go
@@ -0,0 +1,330 @@
+package telaria
+
+import (
+	"bytes"
+	"compress/gzip"
+	"encoding/json"
+	"fmt"
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"net/http"
+	"strconv"
+)
+
+const Endpoint = "https://ads.tremorhub.com/ad/rtb/prebid"
+
+type TelariaAdapter struct {
+	URI string
+}
+
+// This will be part of Imp[i].Ext when this adapter calls out the Telaria Ad Server
+type ImpressionExtOut struct {
+	OriginalTagID       string `json:"originalTagid"`
+	OriginalPublisherID string `json:"originalPublisherid"`
+}
+
+// used for cookies and such
+func (a *TelariaAdapter) Name() string {
+	return "telaria"
+}
+
+func (a *TelariaAdapter) SkipNoCookies() bool {
+	return false
+}
+
+// Endpoint for Telaria Ad server
+func (a *TelariaAdapter) FetchEndpoint() string {
+	return a.URI
+}
+
+// Checker method to ensure len(request.Imp) > 0
+func (a *TelariaAdapter) CheckHasImps(request *openrtb.BidRequest) error {
+	if len(request.Imp) == 0 {
+		err := &errortypes.BadInput{
+			Message: "Telaria: Missing Imp Object",
+		}
+		return err
+	}
+	return nil
+}
+
+// Checking if Imp[i].Video exists and Imp[i].Banner doesn't exist
+func (a *TelariaAdapter) CheckHasVideoObject(request *openrtb.BidRequest) error {
+	hasVideoObject := false
+
+	for _, imp := range request.Imp {
+		if imp.Banner != nil {
+			return &errortypes.BadInput{
+				Message: "Telaria: Banner not supported",
+			}
+		}
+
+		hasVideoObject = hasVideoObject || imp.Video != nil
+	}
+
+	if !hasVideoObject {
+		return &errortypes.BadInput{
+			Message: "Telaria: Only Supports Video",
+		}
+	}
+
+	return nil
+}
+
+// Fetches the populated header object
+func GetHeaders(request *openrtb.BidRequest) *http.Header {
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	headers.Add("X-Openrtb-Version", "2.5")
+	headers.Add("Accept-Encoding", "gzip")
+
+	if request.Device != nil {
+		if len(request.Device.UA) > 0 {
+			headers.Add("User-Agent", request.Device.UA)
+		}
+
+		if len(request.Device.IP) > 0 {
+			headers.Add("X-Forwarded-For", request.Device.IP)
+		}
+
+		if len(request.Device.Language) > 0 {
+			headers.Add("Accept-Language", request.Device.Language)
+		}
+
+		if request.Device.DNT != nil {
+			headers.Add("Dnt", strconv.Itoa(int(*request.Device.DNT)))
+		}
+	}
+
+	return &headers
+}
+
+// Checks the imp[i].ext object and returns a imp.ext object as per ExtImpTelaria format
+func (a *TelariaAdapter) FetchTelariaExtImpParams(imp *openrtb.Imp) (*openrtb_ext.ExtImpTelaria, error) {
+	var bidderExt adapters.ExtImpBidder
+	err := json.Unmarshal(imp.Ext, &bidderExt)
+
+	if err != nil {
+		err = &errortypes.BadInput{
+			Message: "Telaria: ext.bidder not provided",
+		}
+
+		return nil, err
+	}
+
+	var telariaExt openrtb_ext.ExtImpTelaria
+	err = json.Unmarshal(bidderExt.Bidder, &telariaExt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	if telariaExt.SeatCode == "" {
+		return nil, &errortypes.BadInput{Message: "Telaria: Seat Code required"}
+	}
+
+	return &telariaExt, nil
+}
+
+// Method to fetch the original publisher ID. Note that this method must be called
+// before we replace publisher.ID with seatCode
+func (a *TelariaAdapter) FetchOriginalPublisherID(request *openrtb.BidRequest) string {
+
+	if request.Site != nil && request.Site.Publisher != nil {
+		return request.Site.Publisher.ID
+	} else if request.App != nil && request.App.Publisher != nil {
+		return request.App.Publisher.ID
+	}
+
+	return ""
+}
+
+// Method to do a deep copy of the publisher object. It also adds the seatCode as publisher.ID
+func (a *TelariaAdapter) MakePublisherObject(seatCode string, publisher *openrtb.Publisher) *openrtb.Publisher {
+	var pub = &openrtb.Publisher{ID: seatCode}
+
+	if publisher != nil {
+		pub.Domain = publisher.Domain
+		pub.Name = publisher.Name
+		pub.Cat = publisher.Cat
+		pub.Ext = publisher.Ext
+	}
+
+	return pub
+}
+
+// This method changes <site/app>.publisher.id to the seatCode
+func (a *TelariaAdapter) PopulatePublisherId(request *openrtb.BidRequest, seatCode string) (*openrtb.Site, *openrtb.App) {
+	if request.Site != nil {
+		siteCopy := *request.Site
+		siteCopy.Publisher = a.MakePublisherObject(seatCode, request.Site.Publisher)
+		return &siteCopy, nil
+	} else if request.App != nil {
+		appCopy := *request.App
+		appCopy.Publisher = a.MakePublisherObject(seatCode, request.App.Publisher)
+		return nil, &appCopy
+	}
+	return nil, nil
+}
+
+func (a *TelariaAdapter) MakeRequests(requestIn *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+
+	// make a copy of the incoming request
+	request := *requestIn
+
+	// ensure that the request has Impressions
+	if noImps := a.CheckHasImps(&request); noImps != nil {
+		return nil, []error{noImps}
+	}
+
+	// ensure that the request has a Video object
+	if noVideoObjectError := a.CheckHasVideoObject(&request); noVideoObjectError != nil {
+		return nil, []error{noVideoObjectError}
+	}
+
+	var seatCode string
+	originalPublisherID := a.FetchOriginalPublisherID(&request)
+
+	var errors []error
+	for i, imp := range request.Imp {
+		// fetch adCode & seatCode from Imp[i].Ext
+		telariaExt, err := a.FetchTelariaExtImpParams(&imp)
+		if err != nil {
+			errors = append(errors, err)
+			break
+		}
+
+		seatCode = telariaExt.SeatCode
+
+		// move the original tagId and the original publisher.id into the Imp[i].Ext object
+		request.Imp[i].Ext, err = json.Marshal(&ImpressionExtOut{request.Imp[i].TagID, originalPublisherID})
+		if err != nil {
+			errors = append(errors, err)
+			break
+		}
+
+		// Swap the tagID with adCode
+		request.Imp[i].TagID = telariaExt.AdCode
+	}
+
+	if len(errors) > 0 {
+		return nil, errors
+	}
+
+	// Add seatCode to <Site/App>.Publisher.ID
+	siteObject, appObject := a.PopulatePublisherId(&request, seatCode)
+
+	request.Site = siteObject
+	request.App = appObject
+
+	reqJSON, err := json.Marshal(request)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	return []*adapters.RequestData{{
+		Method:  "POST",
+		Uri:     a.FetchEndpoint(),
+		Body:    reqJSON,
+		Headers: *GetHeaders(&request),
+	}}, nil
+}
+
+// response isn't automatically decompressed. This method unzips the response if Content-Encoding is gzip
+func GetResponseBody(response *adapters.ResponseData) ([]byte, error) {
+
+	if "gzip" == response.Headers.Get("Content-Encoding") {
+		body := bytes.NewBuffer(response.Body)
+		r, readerErr := gzip.NewReader(body)
+		if readerErr != nil {
+			return nil, &errortypes.BadServerResponse{
+				Message: fmt.Sprintf("Error while trying to unzip data [ %d ]", response.StatusCode),
+			}
+		}
+		var resB bytes.Buffer
+		var err error
+		_, err = resB.ReadFrom(r)
+		if err != nil {
+			return nil, &errortypes.BadServerResponse{
+				Message: fmt.Sprintf("Error while trying to unzip data [ %d ]", response.StatusCode),
+			}
+		}
+
+		response.Headers.Del("Content-Encoding")
+
+		return resB.Bytes(), nil
+	} else {
+		return response.Body, nil
+	}
+}
+
+func (a *TelariaAdapter) CheckResponseStatusCodes(response *adapters.ResponseData) error {
+	if response.StatusCode == http.StatusNoContent {
+		return &errortypes.BadInput{Message: "Telaria: Invalid Bid Request received by the server"}
+	}
+
+	if response.StatusCode == http.StatusBadRequest {
+		return &errortypes.BadInput{
+			Message: fmt.Sprintf("Telaria: Unexpected status code: [ %d ] ", response.StatusCode),
+		}
+	}
+
+	if response.StatusCode == http.StatusServiceUnavailable {
+		return &errortypes.BadInput{
+			Message: fmt.Sprintf("Telaria: Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
+		}
+	}
+
+	if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusMultipleChoices {
+		return &errortypes.BadInput{
+			Message: fmt.Sprintf("Telaria: Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
+		}
+	}
+
+	return nil
+}
+
+func (a *TelariaAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+
+	httpStatusError := a.CheckResponseStatusCodes(response)
+	if httpStatusError != nil {
+		return nil, []error{httpStatusError}
+	}
+
+	responseBody, err := GetResponseBody(response)
+
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	var bidResp openrtb.BidResponse
+	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Telaria: Bad Server Response",
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
+	sb := bidResp.SeatBid[0]
+
+	for _, bid := range sb.Bid {
+		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+			Bid:     &bid,
+			BidType: openrtb_ext.BidTypeVideo,
+		})
+	}
+	return bidResponse, nil
+}
+
+func NewTelariaBidder(endpoint string) *TelariaAdapter {
+	if endpoint == "" {
+		endpoint = Endpoint
+	}
+
+	return &TelariaAdapter{
+		URI: endpoint,
+	}
+}
diff --git a/adapters/telaria/usersync.go b/adapters/telaria/usersync.go
new file mode 100644
index 00000000..e3f76f6e
--- /dev/null
+++ b/adapters/telaria/usersync.go
@@ -0,0 +1,12 @@
+package telaria
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewTelariaSyncer(temp *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("telaria", 202, temp, adapters.SyncTypeRedirect)
+}
diff --git a/config/config.go b/config/config.go
index 999b1870..1c686591 100644
--- a/config/config.go
+++ b/config/config.go
@@ -221,7 +221,7 @@ const (
 type Adapter struct {
 	Endpoint string `mapstructure:"endpoint"` // Required
 	// UserSyncURL is the URL returned by /cookie_sync for this Bidder. It is _usually_ optional.
-	// If not defined, sensible defaults will be derved based on the config.external_url.
+	// If not defined, sensible defaults will be derived based on the config.external_url.
 	// Note that some Bidders don't have sensible defaults, because their APIs require an ID that will vary
 	// from one PBS host to another.
 	//
@@ -535,6 +535,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSovrn, "https://ap.lijit.com/pixel?redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsovrn%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSynacormedia, "https://sync.technoratimedia.com/services?srv=cs&pid=70&cb="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsynacormedia%26uid%3D%5BUSER_ID%5D")
 	// openrtb_ext.BidderTappx doesn't have a good default.
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderTelaria, "https://pbs.publishers.tremorhub.com/pubsync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dtelaria%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Btvid%5D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderTriplelift, "https://eb2.3lift.com/getuid?gdpr={{.GDPR}}&cmp_cs={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dtriplelift%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderTripleliftNative, "https://eb2.3lift.com/getuid?gdpr={{.GDPR}}&cmp_cs={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dtriplelift_native%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderUcfunnel, "https://sync.aralego.com/idsync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&usprivacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Ducfunnel%26uid%3DSspCookieUserId")
@@ -694,6 +695,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	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.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.brightroll.endpoint", "http://east-bid.ybp.yahoo.com/bid/appnexuspbs")
 	v.SetDefault("adapters.consumable.endpoint", "https://e.serverbid.com/api/v2")
 	v.SetDefault("adapters.conversant.endpoint", "http://api.hb.ad.cpe.dotomi.com/s2s/header/24")
@@ -729,6 +731,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.sovrn.endpoint", "http://ap.lijit.com/rtb/bid?src=prebid_server")
 	v.SetDefault("adapters.synacormedia.endpoint", "http://{{.Host}}.technoratimedia.com/openrtb/bids/{{.Host}}")
 	v.SetDefault("adapters.tappx.endpoint", "https://{{.Host}}")
+	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")
diff --git a/config/stored_requests.go b/config/stored_requests.go
index 0d9e7732..04e400f9 100644
--- a/config/stored_requests.go
+++ b/config/stored_requests.go
@@ -402,7 +402,7 @@ func (cfg *PostgresUpdatePolling) validate(errs configErrors) configErrors {
 	return errs
 }
 
-// MakeQuery builds a query which can fetch numReqs Stored Requetss and numImps Stored Imps.
+// MakeQuery builds a query which can fetch numReqs Stored Requests and numImps Stored Imps.
 // See the docs on PostgresConfig.QueryTemplate for a description of how it works.
 func (cfg *PostgresFetcherQueriesSlim) MakeQuery(numReqs int, numImps int) (query string) {
 	return resolve(cfg.QueryTemplate, numReqs, numImps)
diff --git a/docs/bidders/appnexus.md b/docs/bidders/appnexus.md
index 8b706adc..e4032313 100644
--- a/docs/bidders/appnexus.md
+++ b/docs/bidders/appnexus.md
@@ -15,7 +15,7 @@ The AppNexus endpoint expects `imp.displaymanagerver` to be populated for mobile
 requests, however not all SDKs will populate this field. If the `imp.displaymanagerver` field
 is not supplied for an `imp`, but `request.app.ext.prebid.source`
 and `request.app.ext.prebid.version` are supplied, the adapter will fill in a value for
-`diplaymanagerver`. It will concatonate the two `app` fields as `<source>-<version>` fo fill in
+`diplaymanagerver`. It will concatenate the two `app` fields as `<source>-<version>` fo fill in
 the empty `displaymanagerver` before sending the request to AppNexus.
 
 ## Test Request
diff --git a/docs/bidders/audienceNetwork.md b/docs/bidders/audienceNetwork.md
index 04357d61..d55e8218 100644
--- a/docs/bidders/audienceNetwork.md
+++ b/docs/bidders/audienceNetwork.md
@@ -3,6 +3,6 @@
 ## Mobile Bids
 
 Audience Network will not bid on requests made from device simulators.
-When testingfor Mobile bids, you must make bid requests using a real device.
+When testing for Mobile bids, you must make bid requests using a real device.
 
 **Note:** Audience Network is disabled by default. Please enable it in the app config if you wish to use it. Make sure you provide the partnerID for the auctions to run correctly.
\ No newline at end of file
diff --git a/docs/bidders/kidoz.md b/docs/bidders/kidoz.md
new file mode 100644
index 00000000..433dd71c
--- /dev/null
+++ b/docs/bidders/kidoz.md
@@ -0,0 +1,9 @@
+# Kidoz Bidder
+
+Kidoz is exclusively for Mobile app COPPA compatible ads, 100% kid relevant and appropriate.
+
+In order for a company to receive bids from Kidoz, they must first open a publisher account at Kidoz.net
+(https://accounts.kidoz.net/publishers/register) and accept the Kidoz Terms and Conditions and Privacy Policy. 
+Kidoz publishers must confirm that all of their content properties are COPPA and GDPR compliant and perform no monitoring
+or tracking of U13 users in their operations.  New publishers are provided a Publisher ID and AccessToken, this can also
+be used to login to their dashboard at the Kidoz.net portal to monitor their account activity. 
diff --git a/docs/bidders/sovrn.md b/docs/bidders/sovrn.md
index 544cb8a6..bc6d4233 100644
--- a/docs/bidders/sovrn.md
+++ b/docs/bidders/sovrn.md
@@ -1,3 +1,3 @@
 Sovrn supports 2 parameters to be present in the `ext` object of impressions sent to it:
 - tagid: a string containing the sovrn-specific id(s) for the publisher's ad tag(s) they would like to bid with. This is a required field
-- bidfloor: The minimium acceptable bid, in CPM, using US Dollars. This is an optional field.
\ No newline at end of file
+- bidfloor: The minimum acceptable bid, in CPM, using US Dollars. This is an optional field.
\ No newline at end of file
diff --git a/docs/developers/cookie-syncs.md b/docs/developers/cookie-syncs.md
index 36c6b85b..75a3e3b0 100644
--- a/docs/developers/cookie-syncs.md
+++ b/docs/developers/cookie-syncs.md
@@ -1,6 +1,6 @@
 # Cookie Sync Technical Details
 
-This document describes the mechancis of a Prebid Server cookie sync.
+This document describes the mechanics of a Prebid Server cookie sync.
 
 ## Motivation
 
diff --git a/docs/developers/default-request.md b/docs/developers/default-request.md
index 2337ccd8..f071d91b 100644
--- a/docs/developers/default-request.md
+++ b/docs/developers/default-request.md
@@ -1,6 +1,6 @@
 # Server Based Global Default Request
 
-This allows a defaut stored request to be defined that allows the server to set up some defaults for all incoming requests. A request specified stored request will override these defaults, and of course any options specified directly in the stored request override both. The default stored request is only read on server startup, it is meant as an installation static default rather than a dynamic tuning option.
+This allows a default stored request to be defined that allows the server to set up some defaults for all incoming requests. A request specified stored request will override these defaults, and of course any options specified directly in the stored request override both. The default stored request is only read on server startup, it is meant as an installation static default rather than a dynamic tuning option.
 
 A common use case is to "hard code" aliases into the server. This saves having to specify them on all incoming requests, and/or on all stored requests. To help support automation and alias discovery we can flag that any aliases found in the file be added to the bidder info endpoints.
 
@@ -35,8 +35,8 @@ The `filename` option is the path/filename of a JSON file containing the default
 ```
 This will be JSON merged into the incoming requests at the top level. These will be used as fallbacks which can be overridden by both Stored Requests _and_ the incoming HTTP request payload.
 
-The `info` option determines if the alised bidders will be exposed on the `/info` endpoints. If true the alias name will be added to the list returned by
-`/info/bidders` and the info JSON for the core bidder will be coppied into `/info/bidder/{biddername}` with the addition of the field 
+The `info` option determines if the aliased bidders will be exposed on the `/info` endpoints. If true the alias name will be added to the list returned by
+`/info/bidders` and the info JSON for the core bidder will be copied into `/info/bidder/{biddername}` with the addition of the field 
 `"alias_of": "{coreBidder}"` to indicate that it is an aliases, and of which core bidder. Turning the info support on may be useful for hosts
 that want to support automation around the `/info` endpoints that will include the predefined aliases.  This config option may be deprecated in a future
 version to promote a consistency in the endpoint functionality, depending on the perceived need for the option.
diff --git a/docs/endpoints/openrtb2/amp.md b/docs/endpoints/openrtb2/amp.md
index b792ae6e..16fa451e 100644
--- a/docs/endpoints/openrtb2/amp.md
+++ b/docs/endpoints/openrtb2/amp.md
@@ -100,7 +100,7 @@ This endpoint supports the following query parameters:
 6. `curl` - the canonical URL of the page
 7. `timeout` - the publisher-specified timeout for the RTC callout
    - A configuration option `amp_timeout_adjustment_ms` may be set to account for estimated latency so that Prebid Server can handle timeouts from adapters and respond to the AMP RTC request before it times out.
-8. `debug` - When set to `1`, the respones will contain extra info for debugging.
+8. `debug` - When set to `1`, the response will contain extra info for debugging.
 
 For information on how these get from AMP into this endpoint, see [this pull request adding the query params to the Prebid callout](https://github.com/ampproject/amphtml/pull/14155) and [this issue adding support for network-level RTC macros](https://github.com/ampproject/amphtml/issues/12374).
 
diff --git a/docs/endpoints/openrtb2/auction.md b/docs/endpoints/openrtb2/auction.md
index bd421850..67430e51 100644
--- a/docs/endpoints/openrtb2/auction.md
+++ b/docs/endpoints/openrtb2/auction.md
@@ -228,7 +228,7 @@ for each Bidder by using the `/cookie_sync` endpoint, and calling the URLs that
 
 #### Native Request
 
-For each native request, the `assets` objects's `id` field must not be defined. Prebid Server will set this automatically, using the index of the asset in the array as the ID.
+For each native request, the `assets` object's `id` field must not be defined. Prebid Server will set this automatically, using the index of the asset in the array as the ID.
 
 
 #### Bidder Aliases
@@ -265,7 +265,7 @@ This can be used to request bids from the same Bidder with different params. For
 ```
 
 For all intents and purposes, the alias will be treated as another Bidder. This new Bidder will behave exactly
-like the original, except that the Response will contain seprate SeatBids, and any Targeting keys
+like the original, except that the Response will contain separate SeatBids, and any Targeting keys
 will be formed using the alias' name.
 
 If an alias overlaps with a core Bidder's name, then the alias will take precedence.
@@ -280,7 +280,7 @@ For example, if the Request defines an alias like this:
 ```
 
 then any `imp.ext.appnexus` params will actually go to the **rubicon** adapter.
-It will become impossible to fetch bids from Appnexus within that Request.
+It will become impossible to fetch bids from AppNexus within that Request.
 
 #### Bidder Response Times
 
@@ -495,7 +495,7 @@ client can declare a given adunit as eligible for rewards by declaring `imp.ext.
 While testing SDK and video integrations, it's important, but often difficult, to get consistent responses back from bidders that cover a range of scenarios like different CPM values, deals, etc. Prebid Server supports a debugging workflow in two ways:
 
 - a stored-auction-response that covers multiple bidder responses
-- multiple stored-bid-reponses at the bidder adapter level
+- multiple stored-bid-responses at the bidder adapter level
 
 **Single Stored Auction Response ID**
 
diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go
index f7b970c5..20805fb7 100644
--- a/exchange/adapter_map.go
+++ b/exchange/adapter_map.go
@@ -54,6 +54,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/sovrn"
 	"github.com/prebid/prebid-server/adapters/synacormedia"
 	"github.com/prebid/prebid-server/adapters/tappx"
+	"github.com/prebid/prebid-server/adapters/telaria"
 	"github.com/prebid/prebid-server/adapters/triplelift"
 	"github.com/prebid/prebid-server/adapters/triplelift_native"
 	"github.com/prebid/prebid-server/adapters/ucfunnel"
@@ -84,15 +85,14 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter
 		openrtb_ext.BidderAdvangelists: advangelists.NewAdvangelistsBidder(cfg.Adapters[string(openrtb_ext.BidderAdvangelists)].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),
-		// TODO #615: Update the config setup so that the Beachfront URLs can be configured, and use those in TestRaceIntegration in exchange_test.go
-		openrtb_ext.BidderBeachfront: beachfront.NewBeachfrontBidder(),
-		openrtb_ext.BidderBrightroll: brightroll.NewBrightrollBidder(cfg.Adapters[string(openrtb_ext.BidderBrightroll)].Endpoint),
-		openrtb_ext.BidderConsumable: consumable.NewConsumableBidder(cfg.Adapters[string(openrtb_ext.BidderConsumable)].Endpoint),
-		openrtb_ext.BidderCpmstar:    cpmstar.NewCpmstarBidder(cfg.Adapters[string(openrtb_ext.BidderCpmstar)].Endpoint),
-		openrtb_ext.BidderDatablocks: datablocks.NewDatablocksBidder(cfg.Adapters[string(openrtb_ext.BidderDatablocks)].Endpoint),
-		openrtb_ext.BidderEmxDigital: emx_digital.NewEmxDigitalBidder(cfg.Adapters[string(openrtb_ext.BidderEmxDigital)].Endpoint),
-		openrtb_ext.BidderEngageBDR:  engagebdr.NewEngageBDRBidder(client, cfg.Adapters[string(openrtb_ext.BidderEngageBDR)].Endpoint),
-		openrtb_ext.BidderEPlanning:  eplanning.NewEPlanningBidder(client, cfg.Adapters[string(openrtb_ext.BidderEPlanning)].Endpoint),
+		openrtb_ext.BidderBeachfront:   beachfront.NewBeachfrontBidder(cfg.Adapters[string(openrtb_ext.BidderBeachfront)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderBeachfront)].ExtraAdapterInfo),
+		openrtb_ext.BidderBrightroll:   brightroll.NewBrightrollBidder(cfg.Adapters[string(openrtb_ext.BidderBrightroll)].Endpoint),
+		openrtb_ext.BidderConsumable:   consumable.NewConsumableBidder(cfg.Adapters[string(openrtb_ext.BidderConsumable)].Endpoint),
+		openrtb_ext.BidderCpmstar:      cpmstar.NewCpmstarBidder(cfg.Adapters[string(openrtb_ext.BidderCpmstar)].Endpoint),
+		openrtb_ext.BidderDatablocks:   datablocks.NewDatablocksBidder(cfg.Adapters[string(openrtb_ext.BidderDatablocks)].Endpoint),
+		openrtb_ext.BidderEmxDigital:   emx_digital.NewEmxDigitalBidder(cfg.Adapters[string(openrtb_ext.BidderEmxDigital)].Endpoint),
+		openrtb_ext.BidderEngageBDR:    engagebdr.NewEngageBDRBidder(client, cfg.Adapters[string(openrtb_ext.BidderEngageBDR)].Endpoint),
+		openrtb_ext.BidderEPlanning:    eplanning.NewEPlanningBidder(client, cfg.Adapters[string(openrtb_ext.BidderEPlanning)].Endpoint),
 		openrtb_ext.BidderFacebook: audienceNetwork.NewFacebookBidder(
 			client,
 			cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderFacebook))].PlatformID,
@@ -127,6 +127,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter
 		openrtb_ext.BidderSovrn:            sovrn.NewSovrnBidder(client, cfg.Adapters[string(openrtb_ext.BidderSovrn)].Endpoint),
 		openrtb_ext.BidderSynacormedia:     synacormedia.NewSynacorMediaBidder(cfg.Adapters[string(openrtb_ext.BidderSynacormedia)].Endpoint),
 		openrtb_ext.BidderTappx:            tappx.NewTappxBidder(client, cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderTappx))].Endpoint),
+		openrtb_ext.BidderTelaria:          telaria.NewTelariaBidder(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderTelaria))].Endpoint),
 		openrtb_ext.BidderTriplelift:       triplelift.NewTripleliftBidder(client, cfg.Adapters[string(openrtb_ext.BidderTriplelift)].Endpoint),
 		openrtb_ext.BidderTripleliftNative: triplelift_native.NewTripleliftNativeBidder(client, cfg.Adapters[string(openrtb_ext.BidderTripleliftNative)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderTripleliftNative)].ExtraAdapterInfo),
 		openrtb_ext.BidderUcfunnel:         ucfunnel.NewUcfunnelBidder(cfg.Adapters[string(openrtb_ext.BidderUcfunnel)].Endpoint),
diff --git a/exchange/bidder.go b/exchange/bidder.go
index 97f64e74..8e95835f 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -208,7 +208,7 @@ func addNativeTypes(bid *openrtb.Bid, request *openrtb.BidRequest) (*nativeRespo
 	var errs []error
 	var nativeMarkup *nativeResponse.Response
 	if err := json.Unmarshal(json.RawMessage(bid.AdM), &nativeMarkup); err != nil || len(nativeMarkup.Assets) == 0 {
-		// Some bidders are returning non-IAB complaiant native markup. In this case Prebid server will not be able to add types. E.g Facebook
+		// Some bidders are returning non-IAB compliant native markup. In this case Prebid server will not be able to add types. E.g Facebook
 		return nil, errs
 	}
 
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 3cab1880..e625e5ca 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -179,6 +179,12 @@ func (e *exchange) HoldAuction(ctx context.Context, bidRequest *openrtb.BidReque
 					errs = append(errs, errors.New("Unable to marshal response ext for debugging"))
 				}
 			}
+
+			if requestExt.Prebid.SupportDeals {
+				dealErrs := applyDealSupport(bidRequest, auc, bidCategory)
+				errs = append(errs, dealErrs...)
+			}
+
 			cacheErrs := auc.doCache(ctx, e.cache, targData, bidRequest, 60, &e.defaultTTLs, bidCategory, debugLog)
 			if len(cacheErrs) > 0 {
 				errs = append(errs, cacheErrs...)
@@ -186,10 +192,6 @@ func (e *exchange) HoldAuction(ctx context.Context, bidRequest *openrtb.BidReque
 			targData.setTargeting(auc, bidRequest.App != nil, bidCategory)
 		}
 
-		if requestExt.Prebid.SupportDeals {
-			dealErrs := applyDealSupport(bidRequest, auc)
-			errs = append(errs, dealErrs...)
-		}
 	}
 
 	// Build the response
@@ -210,7 +212,7 @@ type BidderDealTier struct {
 }
 
 // applyDealSupport updates targeting keys with deal prefixes if minimum deal tier exceeded
-func applyDealSupport(bidRequest *openrtb.BidRequest, auc *auction) []error {
+func applyDealSupport(bidRequest *openrtb.BidRequest, auc *auction, bidCategory map[string]string) []error {
 	errs := []error{}
 	impDealMap := getDealTiers(bidRequest)
 
@@ -221,7 +223,7 @@ func applyDealSupport(bidRequest *openrtb.BidRequest, auc *auction) []error {
 
 			if topBidPerBidder.dealPriority > 0 {
 				if validateAndNormalizeDealTier(impDeal[bidderString]) {
-					updateHbPbCatDur(topBidPerBidder, impDeal[bidderString].Info)
+					updateHbPbCatDur(topBidPerBidder, impDeal[bidderString].Info, bidCategory)
 				} else {
 					errs = append(errs, fmt.Errorf("dealTier configuration invalid for bidder '%s', imp ID '%s'", bidderString, impID))
 				}
@@ -258,16 +260,16 @@ func validateAndNormalizeDealTier(impDeal *DealTier) bool {
 	return len(impDeal.Info.Prefix) > 0 && impDeal.Info.MinDealTier > 0
 }
 
-func updateHbPbCatDur(bid *pbsOrtbBid, dealTierInfo *DealTierInfo) {
+func updateHbPbCatDur(bid *pbsOrtbBid, dealTierInfo *DealTierInfo, bidCategory map[string]string) {
 	if bid.dealPriority >= dealTierInfo.MinDealTier {
 		prefixTier := fmt.Sprintf("%s%d_", dealTierInfo.Prefix, bid.dealPriority)
 
-		if oldCatDur, ok := bid.bidTargets["hb_pb_cat_dur"]; ok {
+		if oldCatDur, ok := bidCategory[bid.bid.ID]; ok {
 			oldCatDurSplit := strings.SplitAfterN(oldCatDur, "_", 2)
 			oldCatDurSplit[0] = prefixTier
 
 			newCatDur := strings.Join(oldCatDurSplit, "")
-			bid.bidTargets["hb_pb_cat_dur"] = newCatDur
+			bidCategory[bid.bid.ID] = newCatDur
 		}
 	}
 }
diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go
index a6b64203..4e36e22f 100644
--- a/gdpr/gdpr.go
+++ b/gdpr/gdpr.go
@@ -12,17 +12,17 @@ import (
 type Permissions interface {
 	// Determines whether or not the host company is allowed to read/write cookies.
 	//
-	// If the consent string was nonsenical, the returned error will be an ErrorMalformedConsent.
+	// If the consent string was nonsensical, the returned error will be an ErrorMalformedConsent.
 	HostCookiesAllowed(ctx context.Context, consent string) (bool, error)
 
 	// Determines whether or not the given bidder is allowed to user personal info for ad targeting.
 	//
-	// If the consent string was nonsenical, the returned error will be an ErrorMalformedConsent.
+	// If the consent string was nonsensical, the returned error will be an ErrorMalformedConsent.
 	BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.BidderName, consent string) (bool, error)
 
 	// Determines whether or not to send PI information to a bidder, or mask it out.
 	//
-	// If the consent string was nonsenical, the returned error will be an ErrorMalformedConsent.
+	// If the consent string was nonsensical, the returned error will be an ErrorMalformedConsent.
 	PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, error)
 }
 
diff --git a/main.go b/main.go
index ae3b7fd5..d6ba430f 100644
--- a/main.go
+++ b/main.go
@@ -42,9 +42,11 @@ func main() {
 	}
 }
 
+const configFileName = "pbs"
+
 func loadConfig() (*config.Configuration, error) {
 	v := viper.New()
-	config.SetupViper(v, "pbs") // filke = filename
+	config.SetupViper(v, configFileName)
 	return config.New(v)
 }
 
diff --git a/openrtb_ext/bid.go b/openrtb_ext/bid.go
index 768128c9..3b297c7a 100644
--- a/openrtb_ext/bid.go
+++ b/openrtb_ext/bid.go
@@ -87,7 +87,7 @@ const (
 	HbpbConstantKey TargetingKey = "hb_pb"
 
 	// HbEnvKey exists to support the Prebid Universal Creative. If it exists, the only legal value is mobile-app.
-	// It will exist only if the incoming bidRequest defiend request.app instead of request.site.
+	// It will exist only if the incoming bidRequest defined request.app instead of request.site.
 	HbEnvKey TargetingKey = "hb_env"
 
 	// HbCacheHost and HbCachePath exist to supply cache host and path as targeting parameters
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index ec974556..43d9b894 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -72,6 +72,7 @@ const (
 	BidderSovrn            BidderName = "sovrn"
 	BidderSynacormedia     BidderName = "synacormedia"
 	BidderTappx            BidderName = "tappx"
+	BidderTelaria          BidderName = "telaria"
 	BidderTriplelift       BidderName = "triplelift"
 	BidderTripleliftNative BidderName = "triplelift_native"
 	BidderUcfunnel         BidderName = "ucfunnel"
@@ -135,6 +136,7 @@ var BidderMap = map[string]BidderName{
 	"sovrn":             BidderSovrn,
 	"synacormedia":      BidderSynacormedia,
 	"tappx":             BidderTappx,
+	"telaria":           BidderTelaria,
 	"triplelift":        BidderTriplelift,
 	"triplelift_native": BidderTripleliftNative,
 	"ucfunnel":          BidderUcfunnel,
diff --git a/openrtb_ext/imp_telaria.go b/openrtb_ext/imp_telaria.go
new file mode 100644
index 00000000..8ea371a8
--- /dev/null
+++ b/openrtb_ext/imp_telaria.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ExtImpTelaria struct {
+	AdCode   string `json:"adCode,omitempty"`
+	SeatCode string `json:"seatCode"`
+}
diff --git a/openrtb_ext/request.go b/openrtb_ext/request.go
index 9d1456c9..25b5c881 100644
--- a/openrtb_ext/request.go
+++ b/openrtb_ext/request.go
@@ -160,7 +160,7 @@ func (pg *PriceGranularity) UnmarshalJSON(b []byte) error {
 func PriceGranularityFromString(gran string) PriceGranularity {
 	switch gran {
 	case "low":
-		return priceGranulrityLow
+		return priceGranularityLow
 	case "med", "medium":
 		// Seems that PBS was written with medium = "med", so hacking that in
 		return priceGranularityMed
@@ -175,7 +175,7 @@ func PriceGranularityFromString(gran string) PriceGranularity {
 	return PriceGranularity{}
 }
 
-var priceGranulrityLow = PriceGranularity{
+var priceGranularityLow = PriceGranularity{
 	Precision: 2,
 	Ranges: []GranularityRange{{
 		Min:       0,
diff --git a/pbsmetrics/config/metrics.go b/pbsmetrics/config/metrics.go
index 81cfbfd0..e1cdaceb 100644
--- a/pbsmetrics/config/metrics.go
+++ b/pbsmetrics/config/metrics.go
@@ -181,6 +181,13 @@ func (me *MultiMetricsEngine) RecordPrebidCacheRequestTime(success bool, length
 	}
 }
 
+// RecordRequestQueueTime across all engines
+func (me *MultiMetricsEngine) RecordRequestQueueTime(success bool, requestType pbsmetrics.RequestType, length time.Duration) {
+	for _, thisME := range *me {
+		thisME.RecordRequestQueueTime(success, requestType, length)
+	}
+}
+
 // DummyMetricsEngine is a Noop metrics engine in case no metrics are configured. (may also be useful for tests)
 type DummyMetricsEngine struct{}
 
@@ -251,3 +258,7 @@ func (me *DummyMetricsEngine) RecordStoredImpCacheResult(cacheResult pbsmetrics.
 // RecordPrebidCacheRequestTime as a noop
 func (me *DummyMetricsEngine) RecordPrebidCacheRequestTime(success bool, length time.Duration) {
 }
+
+// RecordRequestQueueTime as a noop
+func (me *DummyMetricsEngine) RecordRequestQueueTime(success bool, requestType pbsmetrics.RequestType, length time.Duration) {
+}
diff --git a/pbsmetrics/go_metrics.go b/pbsmetrics/go_metrics.go
index 9b3dd65f..ff3d9681 100644
--- a/pbsmetrics/go_metrics.go
+++ b/pbsmetrics/go_metrics.go
@@ -24,6 +24,7 @@ type Metrics struct {
 	SafariRequestMeter             metrics.Meter
 	SafariNoCookieMeter            metrics.Meter
 	RequestTimer                   metrics.Timer
+	RequestsQueueTimer             map[RequestType]map[bool]metrics.Timer
 	PrebidCacheRequestTimerSuccess metrics.Timer
 	PrebidCacheRequestTimerError   metrics.Timer
 	StoredReqCacheMeter            map[CacheResult]metrics.Meter
@@ -111,6 +112,7 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderNa
 		SafariRequestMeter:             blankMeter,
 		SafariNoCookieMeter:            blankMeter,
 		RequestTimer:                   blankTimer,
+		RequestsQueueTimer:             make(map[RequestType]map[bool]metrics.Timer),
 		PrebidCacheRequestTimerSuccess: blankTimer,
 		PrebidCacheRequestTimerError:   blankTimer,
 		StoredReqCacheMeter:            make(map[CacheResult]metrics.Meter),
@@ -146,6 +148,11 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderNa
 		}
 	}
 
+	//to minimize memory usage, queuedTimeout metric is now supported for video endpoint only
+	//boolean value represents 2 general request statuses: accepted and rejected
+	newMetrics.RequestsQueueTimer["video"] = make(map[bool]metrics.Timer)
+	newMetrics.RequestsQueueTimer["video"][true] = blankTimer
+	newMetrics.RequestsQueueTimer["video"][false] = blankTimer
 	return newMetrics
 }
 
@@ -191,11 +198,15 @@ func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, d
 			statusMap[stat] = metrics.GetOrRegisterMeter("requests."+string(stat)+"."+string(typ), registry)
 		}
 	}
+
 	for _, cacheRes := range CacheResults() {
 		newMetrics.StoredReqCacheMeter[cacheRes] = metrics.GetOrRegisterMeter(fmt.Sprintf("stored_request_cache_%s", string(cacheRes)), registry)
 		newMetrics.StoredImpCacheMeter[cacheRes] = metrics.GetOrRegisterMeter(fmt.Sprintf("stored_imp_cache_%s", string(cacheRes)), registry)
 	}
 
+	newMetrics.RequestsQueueTimer["video"][true] = metrics.GetOrRegisterTimer("queued_requests.video.accepted", registry)
+	newMetrics.RequestsQueueTimer["video"][false] = metrics.GetOrRegisterTimer("queued_requests.video.rejected", registry)
+
 	newMetrics.userSyncSet[unknownBidder] = metrics.GetOrRegisterMeter("usersync.unknown.sets", registry)
 	newMetrics.userSyncGDPRPrevent[unknownBidder] = metrics.GetOrRegisterMeter("usersync.unknown.gdpr_prevent", registry)
 	return newMetrics
@@ -526,6 +537,13 @@ func (me *Metrics) RecordPrebidCacheRequestTime(success bool, length time.Durati
 	}
 }
 
+func (me *Metrics) RecordRequestQueueTime(success bool, requestType RequestType, length time.Duration) {
+	if requestType == ReqTypeVideo { //remove this check when other request types are supported
+		me.RequestsQueueTimer[requestType][success].Update(length)
+	}
+
+}
+
 func doMark(bidder openrtb_ext.BidderName, meters map[openrtb_ext.BidderName]metrics.Meter) {
 	met, ok := meters[bidder]
 	if ok {
diff --git a/pbsmetrics/metrics.go b/pbsmetrics/metrics.go
index aea9735c..611692c9 100644
--- a/pbsmetrics/metrics.go
+++ b/pbsmetrics/metrics.go
@@ -154,11 +154,12 @@ func CookieTypes() []CookieFlag {
 
 // Request/return status
 const (
-	RequestStatusOK          RequestStatus = "ok"
-	RequestStatusBadInput    RequestStatus = "badinput"
-	RequestStatusErr         RequestStatus = "err"
-	RequestStatusNetworkErr  RequestStatus = "networkerr"
-	RequestStatusBlacklisted RequestStatus = "blacklistedacctorapp"
+	RequestStatusOK           RequestStatus = "ok"
+	RequestStatusBadInput     RequestStatus = "badinput"
+	RequestStatusErr          RequestStatus = "err"
+	RequestStatusNetworkErr   RequestStatus = "networkerr"
+	RequestStatusBlacklisted  RequestStatus = "blacklistedacctorapp"
+	RequestStatusQueueTimeout RequestStatus = "queuetimeout"
 )
 
 func RequestStatuses() []RequestStatus {
@@ -168,6 +169,7 @@ func RequestStatuses() []RequestStatus {
 		RequestStatusErr,
 		RequestStatusNetworkErr,
 		RequestStatusBlacklisted,
+		RequestStatusQueueTimeout,
 	}
 }
 
@@ -248,7 +250,7 @@ func RequestActions() []RequestAction {
 
 // MetricsEngine is a generic interface to record PBS metrics into the desired backend
 // The first three metrics function fire off once per incoming request, so total metrics
-// will equal the total numer of incoming requests. The remaining 5 fire off per outgoing
+// will equal the total number of incoming requests. The remaining 5 fire off per outgoing
 // request to a bidder adapter, so will record a number of hits per incoming request. The
 // two groups should be consistent within themselves, but comparing numbers between groups
 // is generally not useful.
@@ -272,4 +274,5 @@ type MetricsEngine interface {
 	RecordStoredReqCacheResult(cacheResult CacheResult, inc int)
 	RecordStoredImpCacheResult(cacheResult CacheResult, inc int)
 	RecordPrebidCacheRequestTime(success bool, length time.Duration)
+	RecordRequestQueueTime(success bool, requestType RequestType, length time.Duration)
 }
diff --git a/pbsmetrics/metrics_mock.go b/pbsmetrics/metrics_mock.go
index 6d57f9fc..1f5b84b1 100644
--- a/pbsmetrics/metrics_mock.go
+++ b/pbsmetrics/metrics_mock.go
@@ -96,3 +96,8 @@ func (me *MetricsEngineMock) RecordStoredImpCacheResult(cacheResult CacheResult,
 func (me *MetricsEngineMock) RecordPrebidCacheRequestTime(success bool, length time.Duration) {
 	me.Called(success, length)
 }
+
+// RecordRequestQueueTime mock
+func (me *MetricsEngineMock) RecordRequestQueueTime(success bool, requestType RequestType, length time.Duration) {
+	me.Called(success, requestType, length)
+}
diff --git a/pbsmetrics/prometheus/preload.go b/pbsmetrics/prometheus/preload.go
index 7654dd54..11e6bdc1 100644
--- a/pbsmetrics/prometheus/preload.go
+++ b/pbsmetrics/prometheus/preload.go
@@ -1,6 +1,7 @@
 package prometheusmetrics
 
 import (
+	"github.com/prebid/prebid-server/pbsmetrics"
 	"github.com/prometheus/client_golang/prometheus"
 )
 
@@ -91,6 +92,13 @@ func preloadLabelValues(m *Metrics) {
 		adapterLabel: adapterValues,
 		actionLabel:  actionValues,
 	})
+
+	//to minimize memory usage, queuedTimeout metric is now supported for video endpoint only
+	//boolean value represents 2 general request statuses: accepted and rejected
+	preloadLabelValuesForHistogram(m.requestsQueueTimer, map[string][]string{
+		requestTypeLabel:   {string(pbsmetrics.ReqTypeVideo)},
+		requestStatusLabel: {requestSuccessLabel, requestRejectLabel},
+	})
 }
 
 func preloadLabelValuesForCounter(counter *prometheus.CounterVec, labelsWithValues map[string][]string) {
diff --git a/pbsmetrics/prometheus/prometheus.go b/pbsmetrics/prometheus/prometheus.go
index 7cb80643..d66defea 100644
--- a/pbsmetrics/prometheus/prometheus.go
+++ b/pbsmetrics/prometheus/prometheus.go
@@ -24,6 +24,7 @@ type Metrics struct {
 	prebidCacheWriteTimer        *prometheus.HistogramVec
 	requests                     *prometheus.CounterVec
 	requestsTimer                *prometheus.HistogramVec
+	requestsQueueTimer           *prometheus.HistogramVec
 	requestsWithoutCookie        *prometheus.CounterVec
 	storedImpressionsCacheResult *prometheus.CounterVec
 	storedRequestCacheResult     *prometheus.CounterVec
@@ -73,11 +74,17 @@ const (
 	markupDeliveryNurl = "nurl"
 )
 
+const (
+	requestSuccessLabel = "requestAcceptedLabel"
+	requestRejectLabel  = "requestRejectedLabel"
+)
+
 // NewMetrics initializes a new Prometheus metrics instance with preloaded label values.
 func NewMetrics(cfg config.PrometheusMetrics) *Metrics {
 	requestTimeBuckets := []float64{0.05, 0.1, 0.15, 0.20, 0.25, 0.3, 0.4, 0.5, 0.75, 1}
-	cacheWriteTimeBuckts := []float64{0.001, 0.002, 0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 1}
+	cacheWriteTimeBuckets := []float64{0.001, 0.002, 0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 1}
 	priceBuckets := []float64{250, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000}
+	queuedRequestTimeBuckets := []float64{0, 1, 5, 30, 60, 120, 180, 240, 300}
 
 	metrics := Metrics{}
 	metrics.Registry = prometheus.NewRegistry()
@@ -112,7 +119,7 @@ func NewMetrics(cfg config.PrometheusMetrics) *Metrics {
 		"prebidcache_write_time_seconds",
 		"Seconds to write to Prebid Cache labeled by success or failure. Failure timing is limited by Prebid Server enforced timeouts.",
 		[]string{successLabel},
-		cacheWriteTimeBuckts)
+		cacheWriteTimeBuckets)
 
 	metrics.requests = newCounter(cfg, metrics.Registry,
 		"requests",
@@ -187,6 +194,12 @@ func NewMetrics(cfg config.PrometheusMetrics) *Metrics {
 		"Count of total requests to Prebid Server labeled by account.",
 		[]string{accountLabel})
 
+	metrics.requestsQueueTimer = newHistogram(cfg, metrics.Registry,
+		"request_queue_time",
+		"Seconds request was waiting in queue",
+		[]string{requestTypeLabel, requestStatusLabel},
+		queuedRequestTimeBuckets)
+
 	preloadLabelValues(&metrics)
 
 	return &metrics
@@ -374,3 +387,14 @@ func (m *Metrics) RecordPrebidCacheRequestTime(success bool, length time.Duratio
 		successLabel: strconv.FormatBool(success),
 	}).Observe(length.Seconds())
 }
+
+func (m *Metrics) RecordRequestQueueTime(success bool, requestType pbsmetrics.RequestType, length time.Duration) {
+	successLabelFormatted := requestRejectLabel
+	if success {
+		successLabelFormatted = requestSuccessLabel
+	}
+	m.requestsQueueTimer.With(prometheus.Labels{
+		requestTypeLabel:   string(requestType),
+		requestStatusLabel: successLabelFormatted,
+	}).Observe(length.Seconds())
+}
diff --git a/router/aspects/request_timeout_handler.go b/router/aspects/request_timeout_handler.go
index ae11f8c5..23d6cef9 100644
--- a/router/aspects/request_timeout_handler.go
+++ b/router/aspects/request_timeout_handler.go
@@ -3,11 +3,13 @@ package aspects
 import (
 	"github.com/julienschmidt/httprouter"
 	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/pbsmetrics"
 	"net/http"
 	"strconv"
+	"time"
 )
 
-func QueuedRequestTimeout(f httprouter.Handle, reqTimeoutHeaders config.RequestTimeoutHeaders) httprouter.Handle {
+func QueuedRequestTimeout(f httprouter.Handle, reqTimeoutHeaders config.RequestTimeoutHeaders, metricsEngine pbsmetrics.MetricsEngine, requestType pbsmetrics.RequestType) httprouter.Handle {
 
 	return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
 
@@ -30,13 +32,17 @@ func QueuedRequestTimeout(f httprouter.Handle, reqTimeoutHeaders config.RequestT
 			return
 		}
 
+		reqTimeDuration := time.Duration(reqTimeFloat * float64(time.Second))
+
 		//Return HTTP 408 if requests stays too long in queue
 		if reqTimeFloat >= reqTimeoutFloat {
 			w.WriteHeader(http.StatusRequestTimeout)
 			w.Write([]byte("Queued request processing time exceeded maximum"))
+			metricsEngine.RecordRequestQueueTime(false, requestType, reqTimeDuration)
 			return
 		}
 
+		metricsEngine.RecordRequestQueueTime(true, requestType, reqTimeDuration)
 		f(w, r, params)
 	}
 
diff --git a/router/router.go b/router/router.go
index 8ac463b8..68627f93 100644
--- a/router/router.go
+++ b/router/router.go
@@ -6,6 +6,7 @@ import (
 	"database/sql"
 	"encoding/json"
 	"fmt"
+	"github.com/prebid/prebid-server/pbsmetrics"
 	"io/ioutil"
 	"net/http"
 	"path/filepath"
@@ -258,7 +259,7 @@ func New(cfg *config.Configuration, rateConvertor *currencies.RateConverter) (r
 
 	requestTimeoutHeaders := config.RequestTimeoutHeaders{}
 	if cfg.RequestTimeoutHeaders != requestTimeoutHeaders {
-		videoEndpoint = aspects.QueuedRequestTimeout(videoEndpoint, cfg.RequestTimeoutHeaders)
+		videoEndpoint = aspects.QueuedRequestTimeout(videoEndpoint, cfg.RequestTimeoutHeaders, r.MetricsEngine, pbsmetrics.ReqTypeVideo)
 	}
 
 	r.POST("/auction", endpoints.Auction(cfg, syncers, gdprPerms, r.MetricsEngine, dataCache, exchanges))
diff --git a/static/bidder-info/33across.yaml b/static/bidder-info/33across.yaml
index f0a44470..84ba6d68 100644
--- a/static/bidder-info/33across.yaml
+++ b/static/bidder-info/33across.yaml
@@ -1,9 +1,9 @@
 maintainer:
-  email: "dev@33across.com"
+  email: "headerbidding@33across.com"
 capabilities:
   app:
     mediaTypes:
     - banner
   site:
     mediaTypes:
-    - banner
\ No newline at end of file
+    - banner
diff --git a/static/bidder-info/adoppler.yaml b/static/bidder-info/adoppler.yaml
index 7fa79eda..1b101039 100644
--- a/static/bidder-info/adoppler.yaml
+++ b/static/bidder-info/adoppler.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: info@adoppler.com
+  email: pbs@adoppler.com
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-info/advangelists.yaml b/static/bidder-info/advangelists.yaml
index e1bc6c0a..aed9900d 100644
--- a/static/bidder-info/advangelists.yaml
+++ b/static/bidder-info/advangelists.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "lokesh@advangelists.com"
+  email: "prebid@advangelists.com"
 capabilities:
   site:
     mediaTypes:
diff --git a/static/bidder-info/appnexus.yaml b/static/bidder-info/appnexus.yaml
index 585c59b9..f1e7ca23 100644
--- a/static/bidder-info/appnexus.yaml
+++ b/static/bidder-info/appnexus.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "info@prebid.org"
+  email: "prebid-server@xandr.com"
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-info/audienceNetwork.yaml b/static/bidder-info/audienceNetwork.yaml
index 34700f2f..56230bf3 100644
--- a/static/bidder-info/audienceNetwork.yaml
+++ b/static/bidder-info/audienceNetwork.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "info@prebid.org"
+  email: "none"
 capabilities:
   site:
     mediaTypes:
diff --git a/static/bidder-info/brightroll.yaml b/static/bidder-info/brightroll.yaml
index 14d9a45f..f913be6d 100644
--- a/static/bidder-info/brightroll.yaml
+++ b/static/bidder-info/brightroll.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "smithaa@oath.com"
+  email: "dsp-supply-prebid@verizonmedia.com"
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-info/conversant.yaml b/static/bidder-info/conversant.yaml
index ce67700e..017f0e0c 100644
--- a/static/bidder-info/conversant.yaml
+++ b/static/bidder-info/conversant.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "mediapsr@conversantmedia.com"
+  email: "CNVR_PublisherIntegration@conversantmedia.com"
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-info/datablocks.yaml b/static/bidder-info/datablocks.yaml
index 9bf7e780..43f00a63 100644
--- a/static/bidder-info/datablocks.yaml
+++ b/static/bidder-info/datablocks.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "henry@datablocks.net"
+  email: "prebid@datablocks.net"
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-info/engagebdr.yaml b/static/bidder-info/engagebdr.yaml
index d2f74762..57c359e4 100644
--- a/static/bidder-info/engagebdr.yaml
+++ b/static/bidder-info/engagebdr.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "admin@engagebdr.com"
+  email: "tech@engagebdr.com"
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-info/gamoshi.yaml b/static/bidder-info/gamoshi.yaml
index 71120ed0..c3ed3ff1 100644
--- a/static/bidder-info/gamoshi.yaml
+++ b/static/bidder-info/gamoshi.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "moses@gamoshi.com"
+  email: "dev@gamoshi.com"
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-info/gumgum.yaml b/static/bidder-info/gumgum.yaml
index b8a3981c..0feca7cd 100644
--- a/static/bidder-info/gumgum.yaml
+++ b/static/bidder-info/gumgum.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "pubtech@gumgum.com"
+  email: "prebid@gumgum.com"
 capabilities:
   site:
     mediaTypes:
diff --git a/static/bidder-info/ix.yaml b/static/bidder-info/ix.yaml
index ff29ec03..326989ae 100644
--- a/static/bidder-info/ix.yaml
+++ b/static/bidder-info/ix.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "info@prebid.org"
+  email: "pdu-supply-prebid@indexexchange.com"
 capabilities:
   site:
     mediaTypes:
diff --git a/static/bidder-info/openx.yaml b/static/bidder-info/openx.yaml
index ce2b67db..e3062b54 100644
--- a/static/bidder-info/openx.yaml
+++ b/static/bidder-info/openx.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "team-openx@openx.com"
+  email: "prebid@openx.com"
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-info/pulsepoint.yaml b/static/bidder-info/pulsepoint.yaml
index b9fd3242..716e4530 100644
--- a/static/bidder-info/pulsepoint.yaml
+++ b/static/bidder-info/pulsepoint.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "info@prebid.org"
+  email: "ExchangeTeam@pulsepoint.com"
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-info/rtbhouse.yaml b/static/bidder-info/rtbhouse.yaml
index 4b899eb3..f15af6ca 100644
--- a/static/bidder-info/rtbhouse.yaml
+++ b/static/bidder-info/rtbhouse.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "inventory.devel@rtbhouse.com"
+  email: "prebid@rtbhouse.com"
 capabilities:
   site:
     mediaTypes:
diff --git a/static/bidder-info/sonobi.yaml b/static/bidder-info/sonobi.yaml
index f49fa281..6d39319a 100644
--- a/static/bidder-info/sonobi.yaml
+++ b/static/bidder-info/sonobi.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "apex@sonobi.com"
+  email: "apex.prebid@sonobi.com"
 capabilities:
   site:
     mediaTypes:
diff --git a/static/bidder-info/telaria.yaml b/static/bidder-info/telaria.yaml
new file mode 100644
index 00000000..43e8707a
--- /dev/null
+++ b/static/bidder-info/telaria.yaml
@@ -0,0 +1,9 @@
+maintainer:
+  email: "github@telaria.com"
+capabilities:
+  app:
+    mediaTypes:
+      - video
+  site:
+    mediaTypes:
+      - video
diff --git a/static/bidder-info/verizonmedia.yaml b/static/bidder-info/verizonmedia.yaml
index da5725ee..024cafad 100644
--- a/static/bidder-info/verizonmedia.yaml
+++ b/static/bidder-info/verizonmedia.yaml
@@ -1,6 +1,6 @@
 maintainer:
-  email: "hb-fe-tech@verizonmedia.com"
+  email: "dsp-supply-prebid@verizonmedia.com"
 capabilities:
   site:
     mediaTypes:
-      - banner
\ No newline at end of file
+      - banner
diff --git a/static/bidder-info/visx.yaml b/static/bidder-info/visx.yaml
index f404a013..b6a16e4c 100644
--- a/static/bidder-info/visx.yaml
+++ b/static/bidder-info/visx.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "service@yoc.com"
+  email: "supply.partners@yoc.com"
 capabilities:
   site:
     mediaTypes:
diff --git a/static/bidder-info/yieldmo.yaml b/static/bidder-info/yieldmo.yaml
index 7d6c0af6..514f1745 100644
--- a/static/bidder-info/yieldmo.yaml
+++ b/static/bidder-info/yieldmo.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "progsupport@yieldmo.com"
+  email: "prebid@yieldmo.com"
 capabilities:
   site:
     mediaTypes:
diff --git a/static/bidder-info/zeroclickfraud.yaml b/static/bidder-info/zeroclickfraud.yaml
index 9bf7e780..527c0065 100644
--- a/static/bidder-info/zeroclickfraud.yaml
+++ b/static/bidder-info/zeroclickfraud.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "henry@datablocks.net"
+  email: "support@datablocks.net"
 capabilities:
   app:
     mediaTypes:
diff --git a/static/bidder-params/telaria.json b/static/bidder-params/telaria.json
new file mode 100644
index 00000000..b4121967
--- /dev/null
+++ b/static/bidder-params/telaria.json
@@ -0,0 +1,22 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Telaria Adapter Params",
+  "description": "A schema which validates params accepted by the Telaria adapter",
+
+  "type": "object",
+  "properties": {
+    "adCode": {
+      "type": "string",
+      "description": "The Ad Unit Code."
+    },
+    "seatCode": {
+      "type": "string",
+      "description": "Your Seat Code."
+    },
+    "originalPublisherid": {
+      "type": "string",
+      "description": "publisher ID from the original request"
+    }
+  },
+  "required": ["seatCode"]
+}
diff --git a/stored_requests/backends/db_fetcher/fetcher.go b/stored_requests/backends/db_fetcher/fetcher.go
index a8232fd5..223067c9 100644
--- a/stored_requests/backends/db_fetcher/fetcher.go
+++ b/stored_requests/backends/db_fetcher/fetcher.go
@@ -113,7 +113,7 @@ func appendErrors(dataType string, ids []string, data map[string]json.RawMessage
 //
 // These errors are documented here: https://www.postgresql.org/docs/9.3/static/errcodes-appendix.html
 func isBadInput(err error) bool {
-	// Unfortunately, Postgres queries will fail if a non-UUID is passedd into a query for a UUID column. For example:
+	// Unfortunately, Postgres queries will fail if a non-UUID is passed into a query for a UUID column. For example:
 	//
 	//    SELECT uuid, data, dataType FROM stored_requests WHERE uuid IN ('abc');
 	//
diff --git a/stored_requests/events/http/http.go b/stored_requests/events/http/http.go
index 4f141dac..a6a129ee 100644
--- a/stored_requests/events/http/http.go
+++ b/stored_requests/events/http/http.go
@@ -142,7 +142,7 @@ func (e *HTTPEvents) refresh(ticker <-chan time.Time) {
 	}
 }
 
-// proceess unpacks the HTTP response and sends the relevant events to the channels.
+// parse unpacks the HTTP response and sends the relevant events to the channels.
 // It returns true if everything was successful, and false if any errors occurred.
 func (e *HTTPEvents) parse(endpoint string, resp *httpCore.Response, err error) (*responseContract, bool) {
 	if err != nil {
diff --git a/stored_requests/fetcher.go b/stored_requests/fetcher.go
index 808495e4..23fdb6b4 100644
--- a/stored_requests/fetcher.go
+++ b/stored_requests/fetcher.go
@@ -30,7 +30,7 @@ type CategoryFetcher interface {
 	FetchCategories(ctx context.Context, primaryAdServer, publisherId, iabCategory string) (string, error)
 }
 
-// AllFetcher is an iterface that encapsulates both the original Fetcher and the CategoryFetcher
+// AllFetcher is an interface that encapsulates both the original Fetcher and the CategoryFetcher
 type AllFetcher interface {
 	FetchRequests(ctx context.Context, requestIDs []string, impIDs []string) (requestData map[string]json.RawMessage, impData map[string]json.RawMessage, errs []error)
 	FetchCategories(ctx context.Context, primaryAdServer, publisherId, iabCategory string) (string, error)
diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go
index be0392f2..da235402 100644
--- a/usersync/usersyncers/syncer.go
+++ b/usersync/usersyncers/syncer.go
@@ -47,6 +47,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/sonobi"
 	"github.com/prebid/prebid-server/adapters/sovrn"
 	"github.com/prebid/prebid-server/adapters/synacormedia"
+	"github.com/prebid/prebid-server/adapters/telaria"
 	"github.com/prebid/prebid-server/adapters/triplelift"
 	"github.com/prebid/prebid-server/adapters/triplelift_native"
 	"github.com/prebid/prebid-server/adapters/ucfunnel"
@@ -110,6 +111,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSovrn, sovrn.NewSovrnSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSmartRTB, smartrtb.NewSmartRTBSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSynacormedia, synacormedia.NewSynacorMediaSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderTelaria, telaria.NewTelariaSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderTriplelift, triplelift.NewTripleliftSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderTripleliftNative, triplelift_native.NewTripleliftSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderUcfunnel, ucfunnel.NewUcfunnelSyncer)


Test patch:
diff --git a/adapters/adapterstest/test_json.go b/adapters/adapterstest/test_json.go
index a0d19548..7602ab16 100644
--- a/adapters/adapterstest/test_json.go
+++ b/adapters/adapterstest/test_json.go
@@ -301,7 +301,7 @@ func diffJson(t *testing.T, description string, actual []byte, expected []byte)
 	if diff.Modified() {
 		var left interface{}
 		if err := json.Unmarshal(actual, &left); err != nil {
-			t.Fatalf("%s json did not match, but unmarhsalling failed. %v", description, err)
+			t.Fatalf("%s json did not match, but unmarshalling failed. %v", description, err)
 		}
 		printer := formatter.NewAsciiFormatter(left, formatter.AsciiFormatterConfig{
 			ShowArrayIndex: true,
diff --git a/adapters/beachfront/beachfront_test.go b/adapters/beachfront/beachfront_test.go
index 4e82deaf..c220cebf 100644
--- a/adapters/beachfront/beachfront_test.go
+++ b/adapters/beachfront/beachfront_test.go
@@ -7,5 +7,5 @@ import (
 )
 
 func TestJsonSamples(t *testing.T) {
-	adapterstest.RunJSONBidderTest(t, "beachfronttest", new(BeachfrontAdapter))
+	adapterstest.RunJSONBidderTest(t, "beachfronttest", NewBeachfrontBidder("https://display.bfmio.com/prebid_display", "{\"video_endpoint\":\"https://reachms.bfmio.com/bid.json?exchange_id\"}"))
 }
diff --git a/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json b/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json
index ffcea194..51ce4e92 100644
--- a/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json
+++ b/adapters/beachfront/beachfronttest/exemplary/minimal-banner.json
@@ -56,7 +56,7 @@
           "dnt": 0,
           "ua": "",
           "adapterName": "BF_PREBID_S2S",
-          "adapterVersion": "0.8.0",
+          "adapterVersion": "0.9.0",
           "user": {
           }
         }
diff --git a/adapters/beachfront/beachfronttest/exemplary/simple-mix.json b/adapters/beachfront/beachfronttest/exemplary/simple-mix.json
index 6d8e483e..eb5d9b07 100644
--- a/adapters/beachfront/beachfronttest/exemplary/simple-mix.json
+++ b/adapters/beachfront/beachfronttest/exemplary/simple-mix.json
@@ -85,7 +85,7 @@
             "buyeruid": "some-buyer"
           },
           "adapterName": "BF_PREBID_S2S",
-          "adapterVersion": "0.8.0",
+          "adapterVersion": "0.9.0",
           "ip": "192.168.255.255",
           "requestId": "61b87329-8790-47b7-90dd-c53ae7ce1723"
         }
diff --git a/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json b/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json
index f189b2c8..7bdbc73c 100644
--- a/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json
+++ b/adapters/beachfront/beachfronttest/supplemental/minimal-banner-empty_array-200.json
@@ -56,7 +56,7 @@
           "dnt": 0,
           "ua": "",
           "adapterName": "BF_PREBID_S2S",
-          "adapterVersion": "0.8.0",
+          "adapterVersion": "0.9.0",
           "user": {
           }
         }
diff --git a/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json b/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json
index b610c96f..27b24357 100644
--- a/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json
+++ b/adapters/beachfront/beachfronttest/supplemental/minimal-site-banner.json
@@ -56,7 +56,7 @@
             "dnt": 0,
             "ua": "",
             "adapterName": "BF_PREBID_S2S",
-            "adapterVersion": "0.8.0",
+            "adapterVersion": "0.9.0",
             "user": {
             }
           }
diff --git a/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json b/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json
index d47393b7..ea38d7ad 100644
--- a/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json
+++ b/adapters/beachfront/beachfronttest/supplemental/mobile-banner.json
@@ -87,7 +87,7 @@
 
           },
           "adapterName":"BF_PREBID_S2S",
-          "adapterVersion":"0.8.0",
+          "adapterVersion":"0.9.0",
           "ip":"192.168.255.255",
           "requestId":"763e3312-19d5-4b07-a61d-890147e863a1"
         }
diff --git a/adapters/beachfront/beachfronttest/supplemental/multi-banner.json b/adapters/beachfront/beachfronttest/supplemental/multi-banner.json
index c4120787..46699511 100644
--- a/adapters/beachfront/beachfronttest/supplemental/multi-banner.json
+++ b/adapters/beachfront/beachfronttest/supplemental/multi-banner.json
@@ -96,7 +96,7 @@
           "dnt": 1,
           "ua": "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
           "adapterName": "BF_PREBID_S2S",
-          "adapterVersion": "0.8.0",
+          "adapterVersion": "0.9.0",
           "user": {
             "buyeruid": "some-buyer",
             "id": "some-user"
diff --git a/adapters/rubicon/rubicon_test.go b/adapters/rubicon/rubicon_test.go
index d386daed..96623659 100644
--- a/adapters/rubicon/rubicon_test.go
+++ b/adapters/rubicon/rubicon_test.go
@@ -7,6 +7,7 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
+	"strconv"
 	"testing"
 	"time"
 
@@ -1133,6 +1134,48 @@ func TestOpenRTBRequestWithImpAndAdSlotIncluded(t *testing.T) {
 		"Unexpected dfp_ad_unit_code: %s", rubiconExtInventory["dfp_ad_unit_code"])
 }
 
+func TestOpenRTBRequestWithBadvOverflowed(t *testing.T) {
+	SIZE_ID := getTestSizes()
+	bidder := new(RubiconAdapter)
+
+	badvOverflowed := make([]string, 100)
+	for i := range badvOverflowed {
+		badvOverflowed[i] = strconv.Itoa(i)
+	}
+
+	request := &openrtb.BidRequest{
+		ID:   "test-request-id",
+		BAdv: badvOverflowed,
+		Imp: []openrtb.Imp{{
+			ID: "test-imp-id",
+			Banner: &openrtb.Banner{
+				Format: []openrtb.Format{
+					SIZE_ID[15],
+				},
+			},
+			Ext: json.RawMessage(`{
+				"bidder": {
+					"zoneId": 8394,
+					"siteId": 283282,
+					"accountId": 7891,
+					"inventory": {"key1" : "val1"},
+					"visitor": {"key2" : "val2"}
+				}
+			}`),
+		}},
+	}
+
+	reqs, _ := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
+
+	rubiconReq := &openrtb.BidRequest{}
+	if err := json.Unmarshal(reqs[0].Body, rubiconReq); err != nil {
+		t.Fatalf("Unexpected error while decoding request: %s", err)
+	}
+
+	badvRequest := rubiconReq.BAdv
+	assert.Equal(t, badvOverflowed[:50], badvRequest, "Unexpected dfp_ad_unit_code: %s")
+}
+
 func TestOpenRTBRequestWithSpecificExtUserEids(t *testing.T) {
 	SIZE_ID := getTestSizes()
 	bidder := new(RubiconAdapter)
diff --git a/adapters/telaria/params_test.go b/adapters/telaria/params_test.go
new file mode 100644
index 00000000..efa3fba1
--- /dev/null
+++ b/adapters/telaria/params_test.go
@@ -0,0 +1,50 @@
+package telaria
+
+import (
+	"encoding/json"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"testing"
+)
+
+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.BidderTelaria, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected Telaria params: %s", validParam)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the Telaria 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.BidderTelaria, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"adCode": "string", "seatCode": "string", "originalPublisherid": "string"}`,
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`4.2`,
+	`[]`,
+	`{}`,
+	`{"adCode": "string", "originalPublisherid": "string"}`,
+	`{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`,
+}
diff --git a/adapters/telaria/telaria_test.go b/adapters/telaria/telaria_test.go
new file mode 100644
index 00000000..7ad96b93
--- /dev/null
+++ b/adapters/telaria/telaria_test.go
@@ -0,0 +1,34 @@
+package telaria
+
+import (
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"testing"
+)
+
+/**
+ * Verify adapter names are setup correctly.
+ */
+func TestTelariaAdapterNames(t *testing.T) {
+	adapter := NewTelariaBidder("")
+	adapterstest.VerifyStringValue(adapter.Name(), "telaria", t)
+}
+
+/**
+ * Verify adapter SkipNoCookie is correct.
+ */
+func TestTelariaAdapterSkipNoCookiesFlag(t *testing.T) {
+	adapter := NewTelariaBidder("")
+	adapterstest.VerifyBoolValue(adapter.SkipNoCookies(), false, t)
+}
+
+/**
+ * Verify bidder has the proper URL
+ */
+func TestTelariaAdapterEndpoint(t *testing.T) {
+	adapter := NewTelariaBidder("")
+	adapterstest.VerifyStringValue(adapter.URI, "https://ads.tremorhub.com/ad/rtb/prebid", t)
+}
+
+func TestJsonSamples(t *testing.T) {
+	adapterstest.RunJSONBidderTest(t, "telariatest", NewTelariaBidder(""))
+}
diff --git a/adapters/telaria/telariatest/exemplary/video-app.json b/adapters/telaria/telariatest/exemplary/video-app.json
new file mode 100644
index 00000000..09bcf998
--- /dev/null
+++ b/adapters/telaria/telariatest/exemplary/video-app.json
@@ -0,0 +1,157 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode",
+            "seatCode": "my-seatcode"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [{
+    "expectedRequest": {
+      "headers": {
+        "Content-Type": ["application/json;charset=utf-8"],
+        "Accept": ["application/json"],
+        "X-Openrtb-Version": ["2.5"],
+        "Accept-Encoding": ["gzip"],
+        "User-Agent": ["test-user-agent"],
+        "X-Forwarded-For": ["123.123.123.123"],
+        "Accept-Language": ["en"],
+        "Dnt": ["0"]
+      },
+      "uri": "https://ads.tremorhub.com/ad/rtb/prebid",
+      "body": {
+        "id": "some-request-id",
+        "device": {
+          "ua": "test-user-agent",
+          "ip": "123.123.123.123",
+          "language": "en",
+          "dnt": 0
+        },
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "tagid": "my-adcode",
+            "ext": {
+              "originalTagid": "ogTAGID",
+              "originalPublisherid": "123456789"
+            }
+          }
+        ],
+        "app": {
+          "id": "123456789",
+          "name": "Awesome App",
+          "bundle": "com.app.awesome",
+          "domain": "awesomeapp.com",
+          "cat": [
+            "IAB22-1"
+          ],
+          "publisher": {
+            "id": "my-seatcode"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": {
+        "id": "awesome-resp-id",
+        "seatbid": [{
+          "bid": [{
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "1",
+            "price": 3.5,
+            "adm": "asesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 1280,
+            "h": 720,
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          }],
+          "seat": "telaria"
+        }],
+        "cur": "USD",
+        "ext": {
+          "responsetimemillis": {
+            "telaria": 154
+          },
+          "tmaxrequest": 1000
+        }
+      }
+    }
+  }],
+  "expectedBids": [{
+    "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+    "impid": "1",
+    "price": 3.5,
+    "adm": "awesome-markup",
+    "adomain": [
+      "awesome.com"
+    ],
+    "crid": "20",
+    "w": 1280,
+    "h": 720,
+    "ext": {
+      "prebid": {
+        "type": "video"
+      }
+    }
+  }]
+}
diff --git a/adapters/telaria/telariatest/exemplary/video-web.json b/adapters/telaria/telariatest/exemplary/video-web.json
new file mode 100644
index 00000000..5dc26b0f
--- /dev/null
+++ b/adapters/telaria/telariatest/exemplary/video-web.json
@@ -0,0 +1,145 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode",
+            "seatCode": "my-seatcode"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "headers": {
+        "Content-Type": ["application/json;charset=utf-8"],
+        "Accept": ["application/json"],
+        "X-Openrtb-Version": ["2.5"],
+        "Accept-Encoding": ["gzip"],
+        "User-Agent": ["test-user-agent"],
+        "X-Forwarded-For": ["123.123.123.123"],
+        "Accept-Language": ["en"],
+        "Dnt": ["0"]
+      },
+      "uri": "https://ads.tremorhub.com/ad/rtb/prebid",
+      "body": {
+        "id": "some-request-id",
+        "device": {
+          "ua": "test-user-agent",
+          "ip": "123.123.123.123",
+          "language": "en",
+          "dnt": 0
+        },
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "my-adcode",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "ext": {
+              "originalTagid": "ogTAGID",
+              "originalPublisherid": "123456789"
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "my-seatcode"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": {
+        "id": "awesome-resp-id",
+        "seatbid": [{
+          "bid": [{
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "1",
+            "price": 3.5,
+            "adm": "asesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 1280,
+            "h": 720,
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          }],
+          "seat": "telaria"
+        }],
+        "cur": "USD",
+        "ext": {
+          "responsetimemillis": {
+            "telaria": 154
+          },
+          "tmaxrequest": 1000
+        }
+      }
+    }
+  }],
+  "expectedBids": [{
+    "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+    "impid": "1",
+    "price": 3.5,
+    "adm": "asesome-markup",
+    "adomain": [
+      "awesome.com"
+    ],
+    "crid": "20",
+    "w": 1280,
+    "h": 720,
+    "ext": {
+      "prebid": {
+        "type": "video"
+      }
+    }
+  }]
+}
diff --git a/adapters/telaria/telariatest/params/race/video.json b/adapters/telaria/telariatest/params/race/video.json
new file mode 100644
index 00000000..e3b67ec8
--- /dev/null
+++ b/adapters/telaria/telariatest/params/race/video.json
@@ -0,0 +1,4 @@
+{
+  "adCode": "my-adcode",
+  "seatCode": "my-seatcode"
+}
diff --git a/adapters/telaria/telariatest/supplemental/banner-unsupported.json b/adapters/telaria/telariatest/supplemental/banner-unsupported.json
new file mode 100644
index 00000000..1e75371d
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/banner-unsupported.json
@@ -0,0 +1,42 @@
+
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Telaria: Banner not supported",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "someother-publisher-id"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "my-adcode",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode",
+            "seatCode": "my-seatcode"
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/adapters/telaria/telariatest/supplemental/invalid-response.json b/adapters/telaria/telariatest/supplemental/invalid-response.json
new file mode 100644
index 00000000..8e4f1ee8
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/invalid-response.json
@@ -0,0 +1,105 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode",
+            "seatCode": "my-seatcode"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "headers": {
+        "Content-Type": ["application/json;charset=utf-8"],
+        "Accept": ["application/json"],
+        "X-Openrtb-Version": ["2.5"],
+        "Accept-Encoding": ["gzip"],
+        "User-Agent": ["test-user-agent"],
+        "X-Forwarded-For": ["123.123.123.123"],
+        "Accept-Language": ["en"],
+        "Dnt": ["0"]
+      },
+      "uri": "https://ads.tremorhub.com/ad/rtb/prebid",
+      "body": {
+        "id": "some-request-id",
+        "device": {
+          "ua": "test-user-agent",
+          "ip": "123.123.123.123",
+          "language": "en",
+          "dnt": 0
+        },
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "my-adcode",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "ext": {
+              "originalTagid": "ogTAGID",
+              "originalPublisherid": "123456789"
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "my-seatcode"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": "invalid response"
+    }
+  }],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Telaria: Bad Server Response",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/telaria/telariatest/supplemental/invalid-telaria-ext-object.json b/adapters/telaria/telariatest/supplemental/invalid-telaria-ext-object.json
new file mode 100644
index 00000000..efdec8ad
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/invalid-telaria-ext-object.json
@@ -0,0 +1,29 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Telaria: ext.bidder not provided",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "my-adcode",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": "Awesome"
+      }
+    ],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
diff --git a/adapters/telaria/telariatest/supplemental/requires-imp-object.json b/adapters/telaria/telariatest/supplemental/requires-imp-object.json
new file mode 100644
index 00000000..5933dc4e
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/requires-imp-object.json
@@ -0,0 +1,16 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Telaria: Missing Imp Object",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
diff --git a/adapters/telaria/telariatest/supplemental/requires-seat-code.json b/adapters/telaria/telariatest/supplemental/requires-seat-code.json
new file mode 100644
index 00000000..5c05e529
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/requires-seat-code.json
@@ -0,0 +1,30 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Telaria: Seat Code required",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-impression-1",
+        "video": {
+          "w": 640,
+          "h": 480,
+          "linearity": 1
+        },
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode"
+          }
+        }
+      }
+    ],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
diff --git a/adapters/telaria/telariatest/supplemental/requires-video-object.json b/adapters/telaria/telariatest/supplemental/requires-video-object.json
new file mode 100644
index 00000000..3f797c9e
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/requires-video-object.json
@@ -0,0 +1,26 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Telaria: Only Supports Video",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-impression-1",
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode",
+            "seatCode": "my-seatcode"
+          }
+        }
+      }
+    ],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
diff --git a/adapters/telaria/telariatest/supplemental/status-code-bad-request.json b/adapters/telaria/telariatest/supplemental/status-code-bad-request.json
new file mode 100644
index 00000000..0b5d8a85
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/status-code-bad-request.json
@@ -0,0 +1,80 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode",
+            "seatCode": "my-seatcode"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "https://ads.tremorhub.com/ad/rtb/prebid",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "my-adcode",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "ext": {
+              "originalTagid": "ogTAGID",
+              "originalPublisherid": ""
+            }
+          }
+        ],
+        "app": {
+          "id": "123456789",
+          "publisher": {
+            "id": "my-seatcode"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 400
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Telaria: Unexpected status code: [ 400 ] ",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/telaria/telariatest/supplemental/status-code-no-content.json b/adapters/telaria/telariatest/supplemental/status-code-no-content.json
new file mode 100644
index 00000000..ffb183f4
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/status-code-no-content.json
@@ -0,0 +1,83 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode",
+            "seatCode": "my-seatcode"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "https://ads.tremorhub.com/ad/rtb/prebid",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "my-adcode",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "ext": {
+              "originalTagid": "ogTAGID",
+              "originalPublisherid": "123456789"
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "my-seatcode"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 204
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Telaria: Invalid Bid Request received by the server",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/telaria/telariatest/supplemental/status-code-other-error.json b/adapters/telaria/telariatest/supplemental/status-code-other-error.json
new file mode 100644
index 00000000..15e4b7f8
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/status-code-other-error.json
@@ -0,0 +1,83 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode",
+            "seatCode": "my-seatcode"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "https://ads.tremorhub.com/ad/rtb/prebid",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "my-adcode",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "ext": {
+              "originalTagid": "ogTAGID",
+              "originalPublisherid": "123456789"
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "my-seatcode"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 306
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Telaria: Something went wrong, please contact your Account Manager. Status Code: [ 306 ] ",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/telaria/telariatest/supplemental/status-code-service-unavailable.json b/adapters/telaria/telariatest/supplemental/status-code-service-unavailable.json
new file mode 100644
index 00000000..b92d4ea8
--- /dev/null
+++ b/adapters/telaria/telariatest/supplemental/status-code-service-unavailable.json
@@ -0,0 +1,83 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "adCode": "my-adcode",
+            "seatCode": "my-seatcode"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "https://ads.tremorhub.com/ad/rtb/prebid",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "my-adcode",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "ext": {
+              "originalTagid": "ogTAGID",
+              "originalPublisherid": "123456789"
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "my-seatcode"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 503
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Telaria: Something went wrong, please contact your Account Manager. Status Code: [ 503 ] ",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/telaria/usersync_test.go b/adapters/telaria/usersync_test.go
new file mode 100644
index 00000000..4896b253
--- /dev/null
+++ b/adapters/telaria/usersync_test.go
@@ -0,0 +1,33 @@
+package telaria
+
+import (
+	"testing"
+	"text/template"
+
+	"github.com/prebid/prebid-server/privacy"
+	"github.com/prebid/prebid-server/privacy/gdpr"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestTelariaSyncer(t *testing.T) {
+
+	syncURL := "https://pbs.publishers.tremorhub.com/pubsync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}"
+	syncURLTemplate := template.Must(
+		template.New("sync-template").Parse(syncURL),
+	)
+
+	syncer := NewTelariaSyncer(syncURLTemplate)
+	syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+		GDPR: gdpr.Policy{
+			Signal: "0",
+		},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, "https://pbs.publishers.tremorhub.com/pubsync?gdpr=0&gdpr_consent=", syncInfo.URL)
+	assert.Equal(t, "redirect", syncInfo.Type)
+	assert.EqualValues(t, 202, syncer.GDPRVendorID())
+	assert.Equal(t, false, syncInfo.SupportCORS)
+	assert.Equal(t, "telaria", syncer.FamilyName())
+
+}
diff --git a/analytics/config/config_test.go b/analytics/config/config_test.go
index 0fd3ec20..7d97fb5f 100644
--- a/analytics/config/config_test.go
+++ b/analytics/config/config_test.go
@@ -22,7 +22,7 @@ func TestSampleModule(t *testing.T) {
 		Response: &openrtb.BidResponse{},
 	})
 	if count != 1 {
-		t.Errorf("PBSAnalyticsModule failed at LogAuctionObejct")
+		t.Errorf("PBSAnalyticsModule failed at LogAuctionObject")
 	}
 
 	am.LogSetUIDObject(&analytics.SetUIDObject{
@@ -33,12 +33,12 @@ func TestSampleModule(t *testing.T) {
 		Success: true,
 	})
 	if count != 2 {
-		t.Errorf("PBSAnalyticsModule failed at LogSetUIDObejct")
+		t.Errorf("PBSAnalyticsModule failed at LogSetUIDObject")
 	}
 
 	am.LogCookieSyncObject(&analytics.CookieSyncObject{})
 	if count != 3 {
-		t.Errorf("PBSAnalyticsModule failed at LogCookieSyncObejct")
+		t.Errorf("PBSAnalyticsModule failed at LogCookieSyncObject")
 	}
 
 	am.LogAmpObject(&analytics.AmpObject{})
diff --git a/config/config_test.go b/config/config_test.go
index 78630e07..92794d79 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -270,6 +270,8 @@ func TestFullConfig(t *testing.T) {
 	cmpStrings(t, "adapters.audiencenetwork.usersync_url", cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderFacebook))].UserSyncURL, "http://facebook.com/ortb/prebid-s2s")
 	cmpStrings(t, "adapters.audiencenetwork.platform_id", cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderFacebook))].PlatformID, "abcdefgh1234")
 	cmpStrings(t, "adapters.audiencenetwork.app_secret", cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderFacebook))].AppSecret, "987abc")
+	cmpStrings(t, "adapters.beachfront.endpoint", cfg.Adapters[string(openrtb_ext.BidderBeachfront)].Endpoint, "https://display.bfmio.com/prebid_display")
+	cmpStrings(t, "adapters.beachfront.extra_info", cfg.Adapters[string(openrtb_ext.BidderBeachfront)].ExtraAdapterInfo, "{\"video_endpoint\":\"https://reachms.bfmio.com/bid.json?exchange_id\"}")
 	cmpStrings(t, "adapters.ix.endpoint", cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderIx))].Endpoint, "http://ixtest.com/api")
 	cmpStrings(t, "adapters.rubicon.endpoint", cfg.Adapters[string(openrtb_ext.BidderRubicon)].Endpoint, "http://rubitest.com/api")
 	cmpStrings(t, "adapters.rubicon.usersync_url", cfg.Adapters[string(openrtb_ext.BidderRubicon)].UserSyncURL, "http://pixel.rubiconproject.com/sync.php?p=prebid")
@@ -417,9 +419,9 @@ func TestCookieSizeError(t *testing.T) {
 	}
 	for i := range testCases {
 		if testCases[i].expectError {
-			assert.Error(t, isValidCookieSize(testCases[i].cookieHost.MaxCookieSizeBytes), fmt.Sprintf("Configuration.HostCooki.MaxCookieSizeBytes less than MIN_COOKIE_SIZE_BYTES = %d and not equal to zero should return an error", MIN_COOKIE_SIZE_BYTES))
+			assert.Error(t, isValidCookieSize(testCases[i].cookieHost.MaxCookieSizeBytes), fmt.Sprintf("Configuration.HostCookie.MaxCookieSizeBytes less than MIN_COOKIE_SIZE_BYTES = %d and not equal to zero should return an error", MIN_COOKIE_SIZE_BYTES))
 		} else {
-			assert.NoError(t, isValidCookieSize(testCases[i].cookieHost.MaxCookieSizeBytes), fmt.Sprintf("Configuration.HostCooki.MaxCookieSizeBytes greater than MIN_COOKIE_SIZE_BYTES = %d or equal to zero should not return an error", MIN_COOKIE_SIZE_BYTES))
+			assert.NoError(t, isValidCookieSize(testCases[i].cookieHost.MaxCookieSizeBytes), fmt.Sprintf("Configuration.HostCookie.MaxCookieSizeBytes greater than MIN_COOKIE_SIZE_BYTES = %d or equal to zero should not return an error", MIN_COOKIE_SIZE_BYTES))
 		}
 	}
 }
diff --git a/docs/developers/automated-tests.md b/docs/developers/automated-tests.md
index 12532237..0dff9b04 100644
--- a/docs/developers/automated-tests.md
+++ b/docs/developers/automated-tests.md
@@ -9,7 +9,7 @@ To reproduce these tests locally, use:
 
 ## Writing Tests
 
-Tests for `some-file.go` should be placed in the file `some-file_test.go` in the same paackage.
+Tests for `some-file.go` should be placed in the file `some-file_test.go` in the same package.
 For more info on how to write tests in Go, see [the Go docs](https://golang.org/pkg/testing/).
 
 ## Adapter Tests
diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go
index b25d5b0c..9dc81eb1 100644
--- a/endpoints/openrtb2/amp_auction_test.go
+++ b/endpoints/openrtb2/amp_auction_test.go
@@ -219,7 +219,7 @@ func TestGDPRConsent(t *testing.T) {
 		responseRecorder := httptest.NewRecorder()
 		endpoint(responseRecorder, request, nil)
 
-		// Parse Resonse
+		// Parse Response
 		var response AmpResponse
 		if err := json.Unmarshal(responseRecorder.Body.Bytes(), &response); err != nil {
 			t.Fatalf("Error unmarshalling response: %s", err.Error())
@@ -372,7 +372,7 @@ func TestCCPAConsent(t *testing.T) {
 		responseRecorder := httptest.NewRecorder()
 		endpoint(responseRecorder, request, nil)
 
-		// Parse Resonse
+		// Parse Response
 		var response AmpResponse
 		if err := json.Unmarshal(responseRecorder.Body.Bytes(), &response); err != nil {
 			t.Fatalf("Error unmarshalling response: %s", err.Error())
@@ -431,7 +431,7 @@ func TestNoConsent(t *testing.T) {
 	responseRecorder := httptest.NewRecorder()
 	endpoint(responseRecorder, request, nil)
 
-	// Parse Resonse
+	// Parse Response
 	var response AmpResponse
 	if err := json.Unmarshal(responseRecorder.Body.Bytes(), &response); err != nil {
 		t.Fatalf("Error unmarshalling response: %s", err.Error())
@@ -478,7 +478,7 @@ func TestInvalidConsent(t *testing.T) {
 	responseRecorder := httptest.NewRecorder()
 	endpoint(responseRecorder, request, nil)
 
-	// Parse Resonse
+	// Parse Response
 	var response AmpResponse
 	if err := json.Unmarshal(responseRecorder.Body.Bytes(), &response); err != nil {
 		t.Fatalf("Error unmarshalling response: %s", err.Error())
@@ -561,7 +561,7 @@ func TestNewAndLegacyConsentBothProvided(t *testing.T) {
 		responseRecorder := httptest.NewRecorder()
 		endpoint(responseRecorder, request, nil)
 
-		// Parse Resonse
+		// Parse Response
 		var response AmpResponse
 		if err := json.Unmarshal(responseRecorder.Body.Bytes(), &response); err != nil {
 			t.Fatalf("Error unmarshalling response: %s", err.Error())
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index 74a70c69..98dfa66d 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -175,7 +175,7 @@ func TestBadNativeRequests(t *testing.T) {
 	tests.assert(t)
 }
 
-// TestAliasedRequests makes sure we handle (defuault) aliased bidders properly
+// TestAliasedRequests makes sure we handle (default) aliased bidders properly
 func TestAliasedRequests(t *testing.T) {
 	tests := &getResponseFromDirectory{
 		dir:           "sample-requests/aliased",
@@ -289,7 +289,7 @@ func (gr *getResponseFromDirectory) assert(t *testing.T) {
 			filesToAssert = append(filesToAssert, gr.dir+"/"+fileInfo.Name())
 		}
 	} else {
-		// Just test the single `gr.file`, and not the entiriety of files that may be found in `gr.dir`
+		// Just test the single `gr.file`, and not the entirety of files that may be found in `gr.dir`
 		filesToAssert = append(filesToAssert, gr.dir+"/"+gr.file)
 	}
 
@@ -805,7 +805,7 @@ func TestDisabledBidder(t *testing.T) {
 		},
 		pbsmetrics.NewMetrics(metrics.NewRegistry(), openrtb_ext.BidderList(), config.DisabledMetrics{}),
 		analyticsConf.NewPBSAnalytics(&config.Analytics{}),
-		map[string]string{"unknownbidder": "The biddder 'unknownbidder' has been disabled."},
+		map[string]string{"unknownbidder": "The bidder 'unknownbidder' has been disabled."},
 		false,
 		[]byte{},
 		openrtb_ext.BidderMap,
@@ -839,7 +839,7 @@ func TestValidateImpExtDisabledBidder(t *testing.T) {
 		&config.Configuration{MaxRequestSize: int64(8096)},
 		pbsmetrics.NewMetrics(metrics.NewRegistry(), openrtb_ext.BidderList(), config.DisabledMetrics{}),
 		analyticsConf.NewPBSAnalytics(&config.Analytics{}),
-		map[string]string{"unknownbidder": "The biddder 'unknownbidder' has been disabled."},
+		map[string]string{"unknownbidder": "The bidder 'unknownbidder' has been disabled."},
 		false,
 		[]byte{},
 		openrtb_ext.BidderMap,
@@ -847,7 +847,7 @@ func TestValidateImpExtDisabledBidder(t *testing.T) {
 	}
 	errs := deps.validateImpExt(imp, nil, 0)
 	assert.JSONEq(t, `{"appnexus":{"placement_id":555}}`, string(imp.Ext))
-	assert.Equal(t, []error{&errortypes.BidderTemporarilyDisabled{Message: "The biddder 'unknownbidder' has been disabled."}}, errs)
+	assert.Equal(t, []error{&errortypes.BidderTemporarilyDisabled{Message: "The bidder 'unknownbidder' has been disabled."}}, errs)
 }
 
 func TestEffectivePubID(t *testing.T) {
diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go
index 0199b43f..d0ce33de 100644
--- a/endpoints/openrtb2/video_auction_test.go
+++ b/endpoints/openrtb2/video_auction_test.go
@@ -44,7 +44,7 @@ func TestVideoEndpointImpressionsNumber(t *testing.T) {
 	respBytes := recorder.Body.Bytes()
 	resp := &openrtb_ext.BidResponseVideo{}
 	if err := json.Unmarshal(respBytes, resp); err != nil {
-		t.Fatalf("Unable to umarshal response.")
+		t.Fatalf("Unable to unmarshal response.")
 	}
 
 	assert.Len(t, ex.lastRequest.Imp, 11, "Incorrect number of impressions in request")
@@ -197,7 +197,7 @@ func TestVideoEndpointDebugQueryTrue(t *testing.T) {
 	respBytes := recorder.Body.Bytes()
 	resp := &openrtb_ext.BidResponseVideo{}
 	if err := json.Unmarshal(respBytes, resp); err != nil {
-		t.Fatalf("Unable to umarshal response.")
+		t.Fatalf("Unable to unmarshal response.")
 	}
 
 	assert.Len(t, ex.lastRequest.Imp, 11, "Incorrect number of impressions in request")
@@ -239,7 +239,7 @@ func TestVideoEndpointDebugQueryFalse(t *testing.T) {
 	respBytes := recorder.Body.Bytes()
 	resp := &openrtb_ext.BidResponseVideo{}
 	if err := json.Unmarshal(respBytes, resp); err != nil {
-		t.Fatalf("Unable to umarshal response.")
+		t.Fatalf("Unable to unmarshal response.")
 	}
 
 	assert.Len(t, ex.lastRequest.Imp, 11, "Incorrect number of impressions in request")
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 7217e609..e7df5e85 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -483,6 +483,11 @@ func TestRaceIntegration(t *testing.T) {
 		Endpoint:   server.URL,
 		PlatformID: "abc",
 	}
+	cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderBeachfront))] = config.Adapter{
+		Endpoint:         server.URL,
+		ExtraAdapterInfo: "{\"video_endpoint\":\"" + server.URL + "\"}",
+	}
+
 	categoriesFetcher, error := newCategoryFetcher("./test/category-mapping")
 	if error != nil {
 		t.Errorf("Failed to create a category Fetcher: %v", error)
@@ -1403,7 +1408,10 @@ func TestApplyDealSupport(t *testing.T) {
 			},
 		}
 
-		bid := pbsOrtbBid{&openrtb.Bid{}, "video", test.targ, &openrtb_ext.ExtBidPrebidVideo{}, test.dealPriority}
+		bid := pbsOrtbBid{&openrtb.Bid{ID: "123456"}, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, test.dealPriority}
+		bidCategory := map[string]string{
+			bid.bid.ID: test.targ["hb_pb_cat_dur"],
+		}
 
 		auc := &auction{
 			winningBidsByBidder: map[string]map[openrtb_ext.BidderName]*pbsOrtbBid{
@@ -1413,9 +1421,9 @@ func TestApplyDealSupport(t *testing.T) {
 			},
 		}
 
-		dealErrs := applyDealSupport(bidRequest, auc)
+		dealErrs := applyDealSupport(bidRequest, auc, bidCategory)
 
-		assert.Equal(t, test.expectedHbPbCatDur, auc.winningBidsByBidder["imp_id1"][bidderName].bidTargets["hb_pb_cat_dur"], test.description)
+		assert.Equal(t, test.expectedHbPbCatDur, bidCategory[auc.winningBidsByBidder["imp_id1"][bidderName].bid.ID], test.description)
 		if len(test.expectedDealErr) > 0 {
 			assert.Containsf(t, dealErrs, errors.New(test.expectedDealErr), "Expected error message not found in deal errors")
 		}
@@ -1590,11 +1598,14 @@ func TestUpdateHbPbCatDur(t *testing.T) {
 	}
 
 	for _, test := range testCases {
-		bid := pbsOrtbBid{&openrtb.Bid{}, "video", test.targ, &openrtb_ext.ExtBidPrebidVideo{}, test.dealPriority}
+		bid := pbsOrtbBid{&openrtb.Bid{ID: "123456"}, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, test.dealPriority}
+		bidCategory := map[string]string{
+			bid.bid.ID: test.targ["hb_pb_cat_dur"],
+		}
 
-		updateHbPbCatDur(&bid, test.dealTier)
+		updateHbPbCatDur(&bid, test.dealTier, bidCategory)
 
-		assert.Equal(t, test.expectedHbPbCatDur, bid.bidTargets["hb_pb_cat_dur"], test.description)
+		assert.Equal(t, test.expectedHbPbCatDur, bidCategory[bid.bid.ID], test.description)
 	}
 }
 
@@ -1762,7 +1773,7 @@ func diffJson(t *testing.T, description string, actual []byte, expected []byte)
 	if diff.Modified() {
 		var left interface{}
 		if err := json.Unmarshal(actual, &left); err != nil {
-			t.Fatalf("%s json did not match, but unmarhsalling failed. %v", description, err)
+			t.Fatalf("%s json did not match, but unmarshalling failed. %v", description, err)
 		}
 		printer := formatter.NewAsciiFormatter(left, formatter.AsciiFormatterConfig{
 			ShowArrayIndex: true,
diff --git a/openrtb_ext/request_test.go b/openrtb_ext/request_test.go
index 3291c4f9..e4046a62 100644
--- a/openrtb_ext/request_test.go
+++ b/openrtb_ext/request_test.go
@@ -8,12 +8,12 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-// Test the unmashalling of the prebid extensions and setting default Price Granularity
+// Test the unmarshalling of the prebid extensions and setting default Price Granularity
 func TestExtRequestTargeting(t *testing.T) {
 	extRequest := &ExtRequest{}
 	err := json.Unmarshal([]byte(ext1), extRequest)
 	if err != nil {
-		t.Errorf("ext1 Unmashall falure: %s", err.Error())
+		t.Errorf("ext1 Unmarshall failure: %s", err.Error())
 	}
 	if extRequest.Prebid.Targeting != nil {
 		t.Error("ext1 Targeting is not nil")
@@ -22,7 +22,7 @@ func TestExtRequestTargeting(t *testing.T) {
 	extRequest = &ExtRequest{}
 	err = json.Unmarshal([]byte(ext2), extRequest)
 	if err != nil {
-		t.Errorf("ext2 Unmashall falure: %s", err.Error())
+		t.Errorf("ext2 Unmarshall failure: %s", err.Error())
 	}
 	if extRequest.Prebid.Targeting == nil {
 		t.Error("ext2 Targeting is nil")
@@ -36,7 +36,7 @@ func TestExtRequestTargeting(t *testing.T) {
 	extRequest = &ExtRequest{}
 	err = json.Unmarshal([]byte(ext3), extRequest)
 	if err != nil {
-		t.Errorf("ext3 Unmashall falure: %s", err.Error())
+		t.Errorf("ext3 Unmarshall failure: %s", err.Error())
 	}
 	if extRequest.Prebid.Targeting == nil {
 		t.Error("ext3 Targeting is nil")
diff --git a/pbsmetrics/config/metrics_test.go b/pbsmetrics/config/metrics_test.go
index ad817ba7..d2374f95 100644
--- a/pbsmetrics/config/metrics_test.go
+++ b/pbsmetrics/config/metrics_test.go
@@ -115,6 +115,9 @@ func TestMultiMetricsEngine(t *testing.T) {
 	for i := 0; i < 3; i++ {
 		metricsEngine.RecordImps(impTypeLabels)
 	}
+
+	metricsEngine.RecordRequestQueueTime(false, pbsmetrics.ReqTypeVideo, time.Duration(1))
+
 	//Make the metrics engine, instantiated here with goEngine, fill its RequestStatuses[RequestType][pbsmetrics.RequestStatusXX] with the new boolean values added to pbsmetrics.Labels
 	VerifyMetrics(t, "RequestStatuses.OpenRTB2.OK", goEngine.RequestStatuses[pbsmetrics.ReqTypeORTB2Web][pbsmetrics.RequestStatusOK].Count(), 5)
 	VerifyMetrics(t, "RequestStatuses.Legacy.OK", goEngine.RequestStatuses[pbsmetrics.ReqTypeLegacy][pbsmetrics.RequestStatusOK].Count(), 0)
@@ -148,6 +151,9 @@ func TestMultiMetricsEngine(t *testing.T) {
 	}
 	VerifyMetrics(t, "AdapterMetrics.AppNexus.GotBidsMeter", goEngine.AdapterMetrics[openrtb_ext.BidderAppnexus].GotBidsMeter.Count(), 0)
 	VerifyMetrics(t, "AdapterMetrics.AppNexus.NoBidMeter", goEngine.AdapterMetrics[openrtb_ext.BidderAppnexus].NoBidMeter.Count(), 5)
+
+	VerifyMetrics(t, "RecordRequestQueueTime.Video.Rejected", goEngine.RequestsQueueTimer[pbsmetrics.ReqTypeVideo][false].Count(), 1)
+	VerifyMetrics(t, "RecordRequestQueueTime.Video.Accepted", goEngine.RequestsQueueTimer[pbsmetrics.ReqTypeVideo][true].Count(), 0)
 }
 
 func VerifyMetrics(t *testing.T, name string, actual int64, expected int64) {
diff --git a/pbsmetrics/go_metrics_test.go b/pbsmetrics/go_metrics_test.go
index b403733d..253ff69e 100644
--- a/pbsmetrics/go_metrics_test.go
+++ b/pbsmetrics/go_metrics_test.go
@@ -50,6 +50,9 @@ func TestNewMetrics(t *testing.T) {
 	ensureContains(t, registry, "requests.badinput.video", m.RequestStatuses[ReqTypeVideo][RequestStatusBadInput])
 	ensureContains(t, registry, "requests.err.video", m.RequestStatuses[ReqTypeVideo][RequestStatusErr])
 	ensureContains(t, registry, "requests.networkerr.video", m.RequestStatuses[ReqTypeVideo][RequestStatusNetworkErr])
+
+	ensureContains(t, registry, "queued_requests.video.rejected", m.RequestsQueueTimer[ReqTypeVideo][false])
+	ensureContains(t, registry, "queued_requests.video.accepted", m.RequestsQueueTimer[ReqTypeVideo][true])
 }
 
 func TestRecordBidType(t *testing.T) {
diff --git a/pbsmetrics/prometheus/prometheus_test.go b/pbsmetrics/prometheus/prometheus_test.go
index 4cf9676e..e4d6a4f7 100644
--- a/pbsmetrics/prometheus/prometheus_test.go
+++ b/pbsmetrics/prometheus/prometheus_test.go
@@ -571,7 +571,7 @@ func TestAdapterRequestMetrics(t *testing.T) {
 		var totalCount float64
 		var totalCookieNoCount float64
 		var totalCookieYesCount float64
-		var totalCookieUnknowmCount float64
+		var totalCookieUnknownCount float64
 		var totalHasBidsCount float64
 		processMetrics(m.adapterRequests, func(m dto.Metric) {
 			isMetricForAdapter := false
@@ -597,7 +597,7 @@ func TestAdapterRequestMetrics(t *testing.T) {
 						case string(pbsmetrics.CookieFlagYes):
 							totalCookieYesCount += value
 						case string(pbsmetrics.CookieFlagUnknown):
-							totalCookieUnknowmCount += value
+							totalCookieUnknownCount += value
 						}
 					}
 				}
@@ -606,7 +606,7 @@ func TestAdapterRequestMetrics(t *testing.T) {
 		assert.Equal(t, test.expectedCount, totalCount, test.description+":total")
 		assert.Equal(t, test.expectedCookieNoCount, totalCookieNoCount, test.description+":cookie=no")
 		assert.Equal(t, test.expectedCookieYesCount, totalCookieYesCount, test.description+":cookie=yes")
-		assert.Equal(t, test.expectedCookieUnknownCount, totalCookieUnknowmCount, test.description+":cookie=unknown")
+		assert.Equal(t, test.expectedCookieUnknownCount, totalCookieUnknownCount, test.description+":cookie=unknown")
 		assert.Equal(t, test.expectedHasBidsCount, totalHasBidsCount, test.description+":hasBids")
 	}
 }
@@ -881,6 +881,48 @@ func TestMetricAccumulationSpotCheck(t *testing.T) {
 		expectedValue)
 }
 
+func TestRecordRequestQueueTimeMetric(t *testing.T) {
+	performTest := func(m *Metrics, requestStatus bool, requestType pbsmetrics.RequestType, timeInSec float64) {
+		m.RecordRequestQueueTime(requestStatus, requestType, time.Duration(timeInSec*float64(time.Second)))
+	}
+
+	testCases := []struct {
+		description   string
+		status        string
+		testCase      func(m *Metrics)
+		expectedCount uint64
+		expectedSum   float64
+	}{
+		{
+			description: "Success",
+			status:      requestSuccessLabel,
+			testCase: func(m *Metrics) {
+				performTest(m, true, pbsmetrics.ReqTypeVideo, 2)
+			},
+			expectedCount: 1,
+			expectedSum:   2,
+		},
+		{
+			description: "TimeoutError",
+			status:      requestRejectLabel,
+			testCase: func(m *Metrics) {
+				performTest(m, false, pbsmetrics.ReqTypeVideo, 50)
+			},
+			expectedCount: 1,
+			expectedSum:   50,
+		},
+	}
+
+	m := createMetricsForTesting()
+	for _, test := range testCases {
+
+		test.testCase(m)
+
+		result := getHistogramFromHistogramVecByTwoKeys(m.requestsQueueTimer, requestTypeLabel, "video", requestStatusLabel, test.status)
+		assertHistogram(t, test.description, result, test.expectedCount, test.expectedSum)
+	}
+}
+
 func assertCounterValue(t *testing.T, description, name string, counter prometheus.Counter, expected float64) {
 	m := dto.Metric{}
 	counter.Write(&m)
@@ -906,6 +948,24 @@ func getHistogramFromHistogramVec(histogram *prometheus.HistogramVec, labelKey,
 	return result
 }
 
+func getHistogramFromHistogramVecByTwoKeys(histogram *prometheus.HistogramVec, label1Key, label1Value, label2Key, label2Value string) dto.Histogram {
+	var result dto.Histogram
+	processMetrics(histogram, func(m dto.Metric) {
+		for ind, label := range m.GetLabel() {
+			if label.GetName() == label1Key && label.GetValue() == label1Value {
+				valInd := ind
+				if ind == 1 {
+					valInd = 0
+				}
+				if m.Label[valInd].GetName() == label2Key && m.Label[valInd].GetValue() == label2Value {
+					result = *m.GetHistogram()
+				}
+			}
+		}
+	})
+	return result
+}
+
 func processMetrics(collector prometheus.Collector, handler func(m dto.Metric)) {
 	collectorChan := make(chan prometheus.Metric)
 	go func() {
diff --git a/router/aspects/request_timeout_handler_test.go b/router/aspects/request_timeout_handler_test.go
index b6e10fd6..cdc920c4 100644
--- a/router/aspects/request_timeout_handler_test.go
+++ b/router/aspects/request_timeout_handler_test.go
@@ -3,9 +3,12 @@ package aspects
 import (
 	"github.com/julienschmidt/httprouter"
 	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/pbsmetrics"
 	"net/http"
 	"net/http/httptest"
+	"strconv"
 	"testing"
+	"time"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -18,76 +21,62 @@ func TestAny(t *testing.T) {
 		reqTimeInQueue          string
 		reqTimeOut              string
 		setHeaders              bool
-		extectedRespCode        int
+		expectedRespCode        int
 		expectedRespCodeMessage string
 		expectedRespBody        string
 		expectedRespBodyMessage string
+		requestStatusMetrics    bool
 	}{
 		{
 			//TestQueuedRequestTimeoutWithTimeout
 			reqTimeInQueue:          "6",
 			reqTimeOut:              "5",
 			setHeaders:              true,
-			extectedRespCode:        http.StatusRequestTimeout,
+			expectedRespCode:        http.StatusRequestTimeout,
 			expectedRespCodeMessage: "Http response code is incorrect, should be 408",
 			expectedRespBody:        "Queued request processing time exceeded maximum",
 			expectedRespBodyMessage: "Body should have error message",
+			requestStatusMetrics:    false,
 		},
 		{
 			//TestQueuedRequestTimeoutNoTimeout
 			reqTimeInQueue:          "0.9",
 			reqTimeOut:              "5",
 			setHeaders:              true,
-			extectedRespCode:        http.StatusOK,
+			expectedRespCode:        http.StatusOK,
 			expectedRespCodeMessage: "Http response code is incorrect, should be 200",
 			expectedRespBody:        "Executed",
 			expectedRespBodyMessage: "Body should be present in response",
+			requestStatusMetrics:    true,
 		},
 		{
 			//TestQueuedRequestNoHeaders
 			reqTimeInQueue:          "",
 			reqTimeOut:              "",
 			setHeaders:              false,
-			extectedRespCode:        http.StatusOK,
+			expectedRespCode:        http.StatusOK,
 			expectedRespCodeMessage: "Http response code is incorrect, should be 200",
 			expectedRespBody:        "Executed",
 			expectedRespBodyMessage: "Body should be present in response",
+			requestStatusMetrics:    true,
 		},
 		{
 			//TestQueuedRequestSomeHeaders
 			reqTimeInQueue:          "2",
 			reqTimeOut:              "",
 			setHeaders:              true,
-			extectedRespCode:        http.StatusOK,
+			expectedRespCode:        http.StatusOK,
 			expectedRespCodeMessage: "Http response code is incorrect, should be 200",
 			expectedRespBody:        "Executed",
 			expectedRespBodyMessage: "Body should be present in response",
-		},
-		{
-			//TestQueuedRequestAllHeadersIncorrect
-			reqTimeInQueue:          "test1",
-			reqTimeOut:              "test2",
-			setHeaders:              true,
-			extectedRespCode:        http.StatusInternalServerError,
-			expectedRespCodeMessage: "Http response code is incorrect, should be 400",
-			expectedRespBody:        "Request timeout headers are incorrect (wrong format)",
-			expectedRespBodyMessage: "Body should have error message",
-		},
-		{
-			//TestQueuedRequestSomeHeadersIncorrect
-			reqTimeInQueue:          "test1",
-			reqTimeOut:              "123",
-			setHeaders:              true,
-			extectedRespCode:        http.StatusInternalServerError,
-			expectedRespCodeMessage: "Http response code is incorrect, should be 400",
-			expectedRespBody:        "Request timeout headers are incorrect (wrong format)",
-			expectedRespBodyMessage: "Body should have error message",
+			requestStatusMetrics:    true,
 		},
 	}
 
 	for _, test := range testCases {
-		result := ExecuteAspectRequest(t, test.reqTimeInQueue, test.reqTimeOut, test.setHeaders)
-		assert.Equal(t, test.extectedRespCode, result.Code, test.expectedRespCodeMessage)
+		reqTimeFloat, _ := strconv.ParseFloat(test.reqTimeInQueue, 64)
+		result := ExecuteAspectRequest(t, test.reqTimeInQueue, test.reqTimeOut, test.setHeaders, pbsmetrics.ReqTypeVideo, test.requestStatusMetrics, reqTimeFloat)
+		assert.Equal(t, test.expectedRespCode, result.Code, test.expectedRespCodeMessage)
 		assert.Equal(t, test.expectedRespBody, string(result.Body.Bytes()), test.expectedRespBodyMessage)
 	}
 }
@@ -100,7 +89,7 @@ func MockHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
 	w.Write([]byte("Executed"))
 }
 
-func ExecuteAspectRequest(t *testing.T, timeInQueue string, reqTimeout string, setHeaders bool) *httptest.ResponseRecorder {
+func ExecuteAspectRequest(t *testing.T, timeInQueue string, reqTimeout string, setHeaders bool, requestType pbsmetrics.RequestType, status bool, requestDuration float64) *httptest.ResponseRecorder {
 	rw := httptest.NewRecorder()
 	req, err := http.NewRequest("POST", "/test", nil)
 	if err != nil {
@@ -113,7 +102,11 @@ func ExecuteAspectRequest(t *testing.T, timeInQueue string, reqTimeout string, s
 
 	customHeaders := config.RequestTimeoutHeaders{reqTimeInQueueHeaderName, reqTimeoutHeaderName}
 
-	handler := QueuedRequestTimeout(MockEndpoint(), customHeaders)
+	metrics := &pbsmetrics.MetricsEngineMock{}
+
+	metrics.On("RecordRequestQueueTime", status, requestType, time.Duration(requestDuration*float64(time.Second))).Once()
+
+	handler := QueuedRequestTimeout(MockEndpoint(), customHeaders, metrics, requestType)
 
 	r := httprouter.New()
 	r.POST("/test", handler)
diff --git a/ssl/ssl_test.go b/ssl/ssl_test.go
index c4c29d14..b72fb7ae 100644
--- a/ssl/ssl_test.go
+++ b/ssl/ssl_test.go
@@ -38,7 +38,7 @@ func TestCertsFromFilePoolDontExist(t *testing.T) {
 	// Assert loaded certificates by looking at the length of the subjects array of strings
 	assert.NoError(t, err, "Error thrown by AppendPEMFileToRootCAPool while loading file %s: %v", certificatesFile, err)
 	subjects := certPool.Subjects()
-	assert.Equal(t, len(subjects), 1, "We only loaded one vertificate from the file, len(subjects) should equal 1")
+	assert.Equal(t, len(subjects), 1, "We only loaded one certificate from the file, len(subjects) should equal 1")
 }
 
 func TestAppendPEMFileToRootCAPoolFail(t *testing.T) {
diff --git a/stored_requests/events/events_test.go b/stored_requests/events/events_test.go
index aaece692..240a6975 100644
--- a/stored_requests/events/events_test.go
+++ b/stored_requests/events/events_test.go
@@ -23,7 +23,7 @@ func TestListen(t *testing.T) {
 		TTL:              -1,
 	})
 
-	// create channels to syncronize
+	// create channels to synchronize
 	saveOccurred := make(chan struct{})
 	invalidateOccurred := make(chan struct{})
 	listener := NewEventListener(
diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go
index 383e24d8..637f590e 100644
--- a/usersync/usersyncers/syncer_test.go
+++ b/usersync/usersyncers/syncer_test.go
@@ -56,6 +56,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderSovrn):            syncConfig,
 			string(openrtb_ext.BidderSmartRTB):         syncConfig,
 			string(openrtb_ext.BidderSynacormedia):     syncConfig,
+			string(openrtb_ext.BidderTelaria):          syncConfig,
 			string(openrtb_ext.BidderTriplelift):       syncConfig,
 			string(openrtb_ext.BidderTripleliftNative): syncConfig,
 			string(openrtb_ext.BidderUcfunnel):         syncConfig,