Repository: prebid/prebid-server
Pull request #3152 (2023-09-26 14:19:13)

Make user.ext.prebid.buyeruids bidder name case insensitive
We need to handle case insensitivity for user.ext.prebid.buyeruids biddernames. This PR updates the biddername look up to use the normalized names for buyeruids.BIDDER.

partially resolves https://github.com/prebid/prebid-server/issues/2400

Sonali-More-Xandr: @bsardo We need this PR to go out with PBS 2.0. Can you please help me understand me why this PR is marked blocked and if there is something pending from my side
bsardo: Hi @Sonali-More-Xandr. We originally blocked this because we thought it conflicted with #3107 and we wanted to see that merged first, but on second look it appears that was a mistake so I'll remove the label.
VeronikaSolovei9: Sonali, thank you for your updates! 
I want to apologize. At the moment I tested your PR at the first time, I misunderstood how this should work. 
(I did the same mistake for my StoredBidResponses PR and had to fix it... )

Here is a desired behavior.
Let's say we have a request with one imp. In the imp.ext we have this config: 
```json
"ext": {
                        "prebid": {
                            "bidder": {
                                "APPnexus": {
                                    "placementId": 1
                                },
                                "appNEXUS": {
                                    "placementId": 2
                                },
                                "amx": {}
                            }
                        }
                    }
```
We also have this config in user.ext.prebid.buyerids:
```json
"user": {
                "id": "userId",
                "ext": {
                    "prebid": {
                        "buyeruids": {
                            "APPnexUS": "12345"
                        }
                    }
                }
            }
```
in this case  "buyeruids": {"APPnexUS": "12345"} should be applied to both "APPnexus" and "appNEXUS", because we need to support case-insesitive comparisons, not case sensitive as it is now. 
My mistake was to check that   user.ext.prebid."buyeruids": { "APPnexus": "12345" } will be only applied to "APPnexus". This is not right, it should be applied to any "appnexus" in imp.ext. 

In order to fix this, add next change on top of existing ones in this PR: util.go -> func prepareUser should be changed to this:
```go
func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, explicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool {
	cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey)

	buyerIdSet := false
	for bidderName, id := range explicitBuyerUIDs {
		if strings.EqualFold(bidderName, givenBidder) {
			req.User = copyWithBuyerUID(req.User, id)
			buyerIdSet = true
		}
	}
	if !buyerIdSet && hadCookie {
		req.User = copyWithBuyerUID(req.User, cookieId)
	}

	return hadCookie
}
```

Also I would like you to add a test that explicitly tests what data goes to what bidder.  Put this test in `exchange/exchangetest/` directory. This test has 3 bidders in imp.ext. 2 of them are "apnexus" in different casing and one amx. It also has a req.user.ext.prebid.buyerids{"APPnexUS": "12345"}.
In `outgoingRequests` there are 3 requests we expect to be executed: APPnexus, appNEXUS and amx. Only APPnexus and appNEXUS will receive user.buyeruid: "12345" -> [test_buyerids.json](https://github.com/prebid/prebid-server/files/12886333/buyerids.json)

onkarvhanumante: master code:
>```go
> func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, explicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool {
>	cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey)
>
>	if id, ok := explicitBuyerUIDs[givenBidder]; ok {
>		req.User = copyWithBuyerUID(req.User, id)
>	} else if hadCookie {
>		req.User = copyWithBuyerUID(req.User, cookieId)
>	}
>
>	return hadCookie
>}


suggested code https://github.com/prebid/prebid-server/pull/3152#issuecomment-1760230797

> ```go
> func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, explicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool {
> 	cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey)
> 
> 	buyerIdSet := false
> 	for bidderName, id := range explicitBuyerUIDs {
> 		if strings.EqualFold(bidderName, givenBidder) {
> 			req.User = copyWithBuyerUID(req.User, id)
> 			buyerIdSet = true
>                          break 
> 		}
> 	}
> 	if !buyerIdSet && hadCookie {
> 		req.User = copyWithBuyerUID(req.User, cookieId)
> 	}
> 
> 	return hadCookie
> }
> ```
> 

Thanks @VeronikaSolovei9  for above change. But something to note is this will change complexity of prepareUser from 0(1) to 0(N). Also `prepareUser()` is called within the loop  then complexity goes 0(N^2)

https://github.com/prebid/prebid-server/blob/1944dbb8592872a712532abaf7a331b2a862b2ac/exchange/utils.go#L331-L364

How about preparing lowercase key map from `explicitBuyerUIDs` and in `prepareUser()`. we could lookup using `strings.ToLower()`. Preparing lowercase key map will incur less complexity  - `0(N) + 0(N) + 0(1)`  than looping inside `prepareUser()` 



```go
lowerCaseExplicitBuyerUIDs = ... code to have lower case bidder name keys from explicitBuyerUIDs map

 for bidder, imps := range impsByBidder { 
 	coreBidder := resolveBidder(bidder, aliases) 
  
 	reqCopy := *req.BidRequest 
 	reqCopy.Imp = imps 
  
 	sChainWriter.Write(&reqCopy, bidder) 
        ...
        if hadSync := prepareUser(&reqCopy, bidder, syncerKey, explicitBuyerUIDs, auctionRequest.UserSyncs); !hadSync && req.BidRequest.App == nil { 
...

func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, lowerCaseExplicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool {
	cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey)

	if id, ok := lowerCaseExplicitBuyerUIDs [strings.ToLower(givenBidder)]; ok {
		req.User = copyWithBuyerUID(req.User, id)
	} else if hadCookie {
		req.User = copyWithBuyerUID(req.User, cookieId)
	}

	return hadCookie
}
```



VeronikaSolovei9: Sure, if this gives the same result! As long as attached test passes and data is returned as expected. 


Patch:
diff --git a/adapters/sovrn/sovrn.go b/adapters/sovrn/sovrn.go
index 405e5ebf..15b07800 100644
--- a/adapters/sovrn/sovrn.go
+++ b/adapters/sovrn/sovrn.go
@@ -97,7 +97,6 @@ func (s *SovrnAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapt
 		video := imp.Video
 		if video != nil {
 			if video.MIMEs == nil ||
-				video.MinDuration == 0 ||
 				video.MaxDuration == 0 ||
 				video.Protocols == nil {
 				errs = append(errs, &errortypes.BadInput{
diff --git a/endpoints/events/vtrack.go b/endpoints/events/vtrack.go
index d320fdc6..e0bf3fd4 100644
--- a/endpoints/events/vtrack.go
+++ b/endpoints/events/vtrack.go
@@ -16,6 +16,7 @@ import (
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/errortypes"
 	"github.com/prebid/prebid-server/metrics"
+	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/prebid/prebid-server/prebid_cache_client"
 	"github.com/prebid/prebid-server/stored_requests"
 )
@@ -27,12 +28,15 @@ const (
 	ImpressionOpenTag    = "<Impression>"
 )
 
+type normalizeBidderName func(name string) (openrtb_ext.BidderName, bool)
+
 type vtrackEndpoint struct {
-	Cfg           *config.Configuration
-	Accounts      stored_requests.AccountFetcher
-	BidderInfos   config.BidderInfos
-	Cache         prebid_cache_client.Client
-	MetricsEngine metrics.MetricsEngine
+	Cfg                 *config.Configuration
+	Accounts            stored_requests.AccountFetcher
+	BidderInfos         config.BidderInfos
+	Cache               prebid_cache_client.Client
+	MetricsEngine       metrics.MetricsEngine
+	normalizeBidderName normalizeBidderName
 }
 
 type BidCacheRequest struct {
@@ -49,11 +53,12 @@ type CacheObject struct {
 
 func NewVTrackEndpoint(cfg *config.Configuration, accounts stored_requests.AccountFetcher, cache prebid_cache_client.Client, bidderInfos config.BidderInfos, me metrics.MetricsEngine) httprouter.Handle {
 	vte := &vtrackEndpoint{
-		Cfg:           cfg,
-		Accounts:      accounts,
-		BidderInfos:   bidderInfos,
-		Cache:         cache,
-		MetricsEngine: me,
+		Cfg:                 cfg,
+		Accounts:            accounts,
+		BidderInfos:         bidderInfos,
+		Cache:               cache,
+		MetricsEngine:       me,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	return vte.Handle
@@ -203,7 +208,7 @@ func ParseVTrackRequest(httpRequest *http.Request, maxRequestSize int64) (req *B
 
 // handleVTrackRequest handles a VTrack request
 func (v *vtrackEndpoint) handleVTrackRequest(ctx context.Context, req *BidCacheRequest, account *config.Account, integration string) (*BidCacheResponse, []error) {
-	biddersAllowingVastUpdate := getBiddersAllowingVastUpdate(req, &v.BidderInfos, v.Cfg.VTrack.AllowUnknownBidder)
+	biddersAllowingVastUpdate := getBiddersAllowingVastUpdate(req, &v.BidderInfos, v.Cfg.VTrack.AllowUnknownBidder, v.normalizeBidderName)
 	// cache data
 	r, errs := v.cachePutObjects(ctx, req, biddersAllowingVastUpdate, account.ID, integration)
 
@@ -251,11 +256,11 @@ func (v *vtrackEndpoint) cachePutObjects(ctx context.Context, req *BidCacheReque
 }
 
 // getBiddersAllowingVastUpdate returns a list of bidders that allow VAST XML modification
-func getBiddersAllowingVastUpdate(req *BidCacheRequest, bidderInfos *config.BidderInfos, allowUnknownBidder bool) map[string]struct{} {
+func getBiddersAllowingVastUpdate(req *BidCacheRequest, bidderInfos *config.BidderInfos, allowUnknownBidder bool, normalizeBidderName normalizeBidderName) map[string]struct{} {
 	bl := map[string]struct{}{}
 
 	for _, bcr := range req.Puts {
-		if _, ok := bl[bcr.Bidder]; isAllowVastForBidder(bcr.Bidder, bidderInfos, allowUnknownBidder) && !ok {
+		if _, ok := bl[bcr.Bidder]; isAllowVastForBidder(bcr.Bidder, bidderInfos, allowUnknownBidder, normalizeBidderName) && !ok {
 			bl[bcr.Bidder] = struct{}{}
 		}
 	}
@@ -264,12 +269,14 @@ func getBiddersAllowingVastUpdate(req *BidCacheRequest, bidderInfos *config.Bidd
 }
 
 // isAllowVastForBidder checks if a bidder is active and allowed to modify vast xml data
-func isAllowVastForBidder(bidder string, bidderInfos *config.BidderInfos, allowUnknownBidder bool) bool {
+func isAllowVastForBidder(bidder string, bidderInfos *config.BidderInfos, allowUnknownBidder bool, normalizeBidderName normalizeBidderName) bool {
 	//if bidder is active and isModifyingVastXmlAllowed is true
 	// check if bidder is configured
-	if b, ok := (*bidderInfos)[bidder]; bidderInfos != nil && ok {
-		// check if bidder is enabled
-		return b.IsEnabled() && b.ModifyingVastXmlAllowed
+	if normalizedBidder, ok := normalizeBidderName(bidder); ok {
+		if b, ok := (*bidderInfos)[normalizedBidder.String()]; bidderInfos != nil && ok {
+			// check if bidder is enabled
+			return b.IsEnabled() && b.ModifyingVastXmlAllowed
+		}
 	}
 
 	return allowUnknownBidder
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 3a929c43..fdb13549 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -1817,7 +1817,9 @@ func (deps *endpointDeps) validateUser(req *openrtb_ext.RequestWrapper, aliases
 			return append(errL, errors.New(`request.user.ext.prebid requires a "buyeruids" property with at least one ID defined. If none exist, then request.user.ext.prebid should not be defined.`))
 		}
 		for bidderName := range prebid.BuyerUIDs {
-			if _, ok := deps.bidderMap[bidderName]; !ok {
+			normalizedCoreBidder, _ := deps.normalizeBidderName(bidderName)
+			coreBidder := normalizedCoreBidder.String()
+			if _, ok := deps.bidderMap[coreBidder]; !ok {
 				if _, ok := aliases[bidderName]; !ok {
 					return append(errL, fmt.Errorf("request.user.ext.%s is neither a known bidder name nor an alias in request.ext.prebid.aliases", bidderName))
 				}
diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json
new file mode 100644
index 00000000..1d2462c9
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json
@@ -0,0 +1,84 @@
+{
+  "description": "Amp request where root.user.ext.prebid.buyeruids field makes use of alias defined in root.ext.prebid.aliases and request makes use of case sensitive bidder name",
+  "query": "tag_id=101",
+  "config": {
+    "mockBidders": [
+      {
+        "bidderName": "appnexus",
+        "currency": "USD",
+        "price": 2
+      }
+    ]
+  },
+  "mockBidRequest": {
+    "id": "request-with-user-ext-obj",
+    "site": {
+      "page": "test.somepage.com"
+    },
+    "imp": [
+      {
+        "id": "my-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "prebid": {
+            "bidder": {
+              "Appnexus": {
+                "placementId": 12883451
+              }
+            }
+          }
+        }
+      }
+    ],
+    "user": {
+      "ext": {
+        "prebid": {
+          "buyeruids": {
+            "unknown": "123"
+          }
+        }
+      }
+    },
+    "ext": {
+      "prebid": {
+        "aliases": {
+          "unknown": "Appnexus"
+        }
+      }
+    }
+  },
+  "expectedAmpResponse": {
+    "targeting": {
+      "hb_bidder": "Appnexus",
+      "hb_bidder_Appnexus": "Appnexus",
+      "hb_cache_host": "www.pbcserver.com",
+      "hb_cache_host_Appnex": "www.pbcserver.com",
+      "hb_cache_id": "0",
+      "hb_cache_id_Appnexus": "0",
+      "hb_cache_path": "/pbcache/endpoint",
+      "hb_cache_path_Appnex": "/pbcache/endpoint",
+      "hb_pb": "2.00",
+      "hb_pb_Appnexus": "2.00"
+    },
+    "ortb2": {
+      "ext": {
+        "warnings": {
+          "general": [
+            {
+              "code": 10002,
+              "message": "debug turned off for account"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "expectedReturnCode": 200
+}
\ No newline at end of file
diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json
new file mode 100644
index 00000000..4597fe77
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json
@@ -0,0 +1,77 @@
+{
+  "description": "Amp request where root.user.ext.prebid.buyeruids field has camel case bidder name",
+  "query": "tag_id=101",
+  "config": {
+    "mockBidders": [
+      {
+        "bidderName": "yahooAds",
+        "currency": "USD",
+        "price": 2
+      }
+    ]
+  },
+  "mockBidRequest": {
+    "id": "request-with-user-ext-obj",
+    "site": {
+      "page": "test.somepage.com"
+    },
+    "imp": [
+      {
+        "id": "my-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "prebid": {
+            "bidder": {
+              "YahooAds": {
+                "placementId": 12883451
+              }
+            }
+          }
+        }
+      }
+    ],
+    "user": {
+      "ext": {
+        "prebid": {
+          "buyeruids": {
+            "YahooAds": "123"
+          }
+        }
+      }
+    }
+  },
+  "expectedAmpResponse": {
+    "targeting": {
+      "hb_bidder": "YahooAds",
+      "hb_bidder_YahooAds": "YahooAds",
+      "hb_cache_host": "www.pbcserver.com",
+      "hb_cache_host_YahooA": "www.pbcserver.com",
+      "hb_cache_id": "0",
+      "hb_cache_id_YahooAds": "0",
+      "hb_cache_path": "/pbcache/endpoint",
+      "hb_cache_path_YahooA": "/pbcache/endpoint",
+      "hb_pb": "2.00",
+      "hb_pb_YahooAds": "2.00"
+    },
+    "ortb2": {
+      "ext": {
+        "warnings": {
+          "general": [
+            {
+              "code": 10002,
+              "message": "debug turned off for account"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "expectedReturnCode": 200
+}
\ No newline at end of file
diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json
new file mode 100644
index 00000000..976fcb3c
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json
@@ -0,0 +1,77 @@
+{
+  "description": "Amp request where root.user.ext.prebid.buyeruids field has case insensitive bidder name",
+  "query": "tag_id=101",
+  "config": {
+    "mockBidders": [
+      {
+        "bidderName": "appnexus",
+        "currency": "USD",
+        "price": 2
+      }
+    ]
+  },
+  "mockBidRequest": {
+    "id": "request-with-user-ext-obj",
+    "site": {
+      "page": "test.somepage.com"
+    },
+    "imp": [
+      {
+        "id": "my-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "prebid": {
+            "bidder": {
+              "Appnexus": {
+                "placementId": 12883451
+              }
+            }
+          }
+        }
+      }
+    ],
+    "user": {
+      "ext": {
+        "prebid": {
+          "buyeruids": {
+            "Appnexus": "123"
+          }
+        }
+      }
+    }
+  },
+  "expectedAmpResponse": {
+    "targeting": {
+      "hb_bidder": "Appnexus",
+      "hb_bidder_Appnexus": "Appnexus",
+      "hb_cache_host": "www.pbcserver.com",
+      "hb_cache_host_Appnex": "www.pbcserver.com",
+      "hb_cache_id": "0",
+      "hb_cache_id_Appnexus": "0",
+      "hb_cache_path": "/pbcache/endpoint",
+      "hb_cache_path_Appnex": "/pbcache/endpoint",
+      "hb_pb": "2.00",
+      "hb_pb_Appnexus": "2.00"
+    },
+    "ortb2": {
+      "ext": {
+        "warnings": {
+          "general": [
+            {
+              "code": 10002,
+              "message": "debug turned off for account"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "expectedReturnCode": 200
+}
\ No newline at end of file
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 25630fed..f758b3ee 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -197,7 +197,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderAceex:             aceex.Builder,
 		openrtb_ext.BidderAcuityAds:         acuityads.Builder,
 		openrtb_ext.BidderAdf:               adf.Builder,
-		openrtb_ext.BidderAdform:            adf.Builder,
 		openrtb_ext.BidderAdgeneration:      adgeneration.Builder,
 		openrtb_ext.BidderAdhese:            adhese.Builder,
 		openrtb_ext.BidderAdkernel:          adkernel.Builder,
@@ -258,7 +257,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderConnectAd:         connectad.Builder,
 		openrtb_ext.BidderConsumable:        consumable.Builder,
 		openrtb_ext.BidderConversant:        conversant.Builder,
-		openrtb_ext.BidderCopper6:           adtelligent.Builder,
 		openrtb_ext.BidderCpmstar:           cpmstar.Builder,
 		openrtb_ext.BidderCriteo:            criteo.Builder,
 		openrtb_ext.BidderCWire:             cwire.Builder,
diff --git a/exchange/utils.go b/exchange/utils.go
index 0d9c90cd..7d5beb64 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -327,6 +327,12 @@ func getAuctionBidderRequests(auctionRequest AuctionRequest,
 		return nil, []error{err}
 	}
 
+	lowerCaseExplicitBuyerUIDs := make(map[string]string)
+	for bidder, uid := range explicitBuyerUIDs {
+		lowerKey := strings.ToLower(bidder)
+		lowerCaseExplicitBuyerUIDs[lowerKey] = uid
+	}
+
 	var errs []error
 	for bidder, imps := range impsByBidder {
 		coreBidder := resolveBidder(bidder, aliases)
@@ -361,7 +367,7 @@ func getAuctionBidderRequests(auctionRequest AuctionRequest,
 		}
 
 		syncerKey := bidderToSyncerKey[string(coreBidder)]
-		if hadSync := prepareUser(&reqCopy, bidder, syncerKey, explicitBuyerUIDs, auctionRequest.UserSyncs); !hadSync && req.BidRequest.App == nil {
+		if hadSync := prepareUser(&reqCopy, bidder, syncerKey, lowerCaseExplicitBuyerUIDs, auctionRequest.UserSyncs); !hadSync && req.BidRequest.App == nil {
 			bidderRequest.BidderLabels.CookieFlag = metrics.CookieFlagNo
 		} else {
 			bidderRequest.BidderLabels.CookieFlag = metrics.CookieFlagYes
@@ -642,7 +648,7 @@ func createSanitizedImpExt(impExt, impExtPrebid map[string]json.RawMessage) (map
 func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, explicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool {
 	cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey)
 
-	if id, ok := explicitBuyerUIDs[givenBidder]; ok {
+	if id, ok := explicitBuyerUIDs[strings.ToLower(givenBidder)]; ok {
 		req.User = copyWithBuyerUID(req.User, id)
 	} else if hadCookie {
 		req.User = copyWithBuyerUID(req.User, cookieId)
diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go
index 0d60a700..13cc022c 100644
--- a/metrics/go_metrics.go
+++ b/metrics/go_metrics.go
@@ -2,6 +2,7 @@ package metrics
 
 import (
 	"fmt"
+	"strings"
 	"sync"
 	"time"
 
@@ -62,12 +63,13 @@ type Metrics struct {
 	PrivacyLMTRequest        metrics.Meter
 	PrivacyTCFRequestVersion map[TCFVersionValue]metrics.Meter
 
-	AdapterMetrics map[openrtb_ext.BidderName]*AdapterMetrics
+	AdapterMetrics map[string]*AdapterMetrics
 	// Don't export accountMetrics because we need helper functions here to insure its properly populated dynamically
 	accountMetrics        map[string]*accountMetrics
 	accountMetricsRWMutex sync.RWMutex
 
-	exchanges []openrtb_ext.BidderName
+	// adapter name exchanges
+	exchanges []string
 	modules   []string
 	// Will hold boolean values to help us disable metric collection if needed
 	MetricsDisabled config.DisabledMetrics
@@ -117,7 +119,7 @@ type accountMetrics struct {
 	bidsReceivedMeter metrics.Meter
 	priceHistogram    metrics.Histogram
 	// store account by adapter metrics. Type is map[PBSBidder.BidderCode]
-	adapterMetrics       map[openrtb_ext.BidderName]*AdapterMetrics
+	adapterMetrics       map[string]*AdapterMetrics
 	moduleMetrics        map[string]*ModuleMetrics
 	storedResponsesMeter metrics.Meter
 
@@ -145,7 +147,7 @@ type ModuleMetrics struct {
 // rather than loading metrics that never get filled.
 // This will also eventually let us configure metrics, such as setting a limited set of metrics
 // for a production instance, and then expanding again when we need more debugging.
-func NewBlankMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, disabledMetrics config.DisabledMetrics, moduleStageNames map[string][]string) *Metrics {
+func NewBlankMetrics(registry metrics.Registry, exchanges []string, disabledMetrics config.DisabledMetrics, moduleStageNames map[string][]string) *Metrics {
 	blankMeter := &metrics.NilMeter{}
 	blankTimer := &metrics.NilTimer{}
 
@@ -193,7 +195,7 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderNa
 		PrivacyLMTRequest:        blankMeter,
 		PrivacyTCFRequestVersion: make(map[TCFVersionValue]metrics.Meter, len(TCFVersions())),
 
-		AdapterMetrics:  make(map[openrtb_ext.BidderName]*AdapterMetrics, len(exchanges)),
+		AdapterMetrics:  make(map[string]*AdapterMetrics, len(exchanges)),
 		accountMetrics:  make(map[string]*accountMetrics),
 		MetricsDisabled: disabledMetrics,
 
@@ -272,7 +274,11 @@ func getModuleNames(moduleStageNames map[string][]string) []string {
 // mode metrics. The code would allways try to record the metrics, but effectively noop if we are
 // using a blank meter/timer.
 func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, disableAccountMetrics config.DisabledMetrics, syncerKeys []string, moduleStageNames map[string][]string) *Metrics {
-	newMetrics := NewBlankMetrics(registry, exchanges, disableAccountMetrics, moduleStageNames)
+	lowerCaseExchanges := []string{}
+	for _, exchange := range exchanges {
+		lowerCaseExchanges = append(lowerCaseExchanges, strings.ToLower(string(exchange)))
+	}
+	newMetrics := NewBlankMetrics(registry, lowerCaseExchanges, disableAccountMetrics, moduleStageNames)
 	newMetrics.ConnectionCounter = metrics.GetOrRegisterCounter("active_connections", registry)
 	newMetrics.TMaxTimeoutCounter = metrics.GetOrRegisterCounter("tmax_timeout", registry)
 	newMetrics.ConnectionAcceptErrorMeter = metrics.GetOrRegisterMeter("connection_accept_errors", registry)
@@ -331,7 +337,7 @@ func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, d
 		}
 	}
 
-	for _, a := range exchanges {
+	for _, a := range lowerCaseExchanges {
 		registerAdapterMetrics(registry, "adapter", string(a), newMetrics.AdapterMetrics[a])
 	}
 
@@ -546,7 +552,7 @@ func (me *Metrics) getAccountMetrics(id string) *accountMetrics {
 	am.debugRequestMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.debug_requests", id), me.MetricsRegistry)
 	am.bidsReceivedMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.bids_received", id), me.MetricsRegistry)
 	am.priceHistogram = metrics.GetOrRegisterHistogram(fmt.Sprintf("account.%s.prices", id), me.MetricsRegistry, metrics.NewExpDecaySample(1028, 0.015))
-	am.adapterMetrics = make(map[openrtb_ext.BidderName]*AdapterMetrics, len(me.exchanges))
+	am.adapterMetrics = make(map[string]*AdapterMetrics, len(me.exchanges))
 	am.moduleMetrics = make(map[string]*ModuleMetrics)
 	am.storedResponsesMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.stored_responses", id), me.MetricsRegistry)
 	if !me.MetricsDisabled.AccountAdapterDetails {
@@ -670,9 +676,11 @@ func (me *Metrics) RecordStoredDataError(labels StoredDataLabels) {
 
 // RecordAdapterPanic implements a part of the MetricsEngine interface
 func (me *Metrics) RecordAdapterPanic(labels AdapterLabels) {
-	am, ok := me.AdapterMetrics[labels.Adapter]
+	adapterStr := string(labels.Adapter)
+	lowerCaseAdapterName := strings.ToLower(adapterStr)
+	am, ok := me.AdapterMetrics[lowerCaseAdapterName]
 	if !ok {
-		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", string(labels.Adapter))
+		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
 		return
 	}
 	am.PanicMeter.Mark(1)
@@ -680,13 +688,15 @@ func (me *Metrics) RecordAdapterPanic(labels AdapterLabels) {
 
 // RecordAdapterRequest implements a part of the MetricsEngine interface
 func (me *Metrics) RecordAdapterRequest(labels AdapterLabels) {
-	am, ok := me.AdapterMetrics[labels.Adapter]
+	adapterStr := string(labels.Adapter)
+	lowerCaseAdapter := strings.ToLower(adapterStr)
+	am, ok := me.AdapterMetrics[lowerCaseAdapter]
 	if !ok {
-		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", string(labels.Adapter))
+		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
 		return
 	}
 
-	aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[labels.Adapter]
+	aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[lowerCaseAdapter]
 	switch labels.AdapterBids {
 	case AdapterBidNone:
 		am.NoBidMeter.Mark(1)
@@ -719,8 +729,8 @@ func (me *Metrics) RecordAdapterConnections(adapterName openrtb_ext.BidderName,
 	if me.MetricsDisabled.AdapterConnectionMetrics {
 		return
 	}
-
-	am, ok := me.AdapterMetrics[adapterName]
+	lowerCaseAdapterName := strings.ToLower(string(adapterName))
+	am, ok := me.AdapterMetrics[lowerCaseAdapterName]
 	if !ok {
 		glog.Errorf("Trying to log adapter connection metrics for %s: adapter not found", string(adapterName))
 		return
@@ -749,16 +759,18 @@ func (me *Metrics) RecordBidderServerResponseTime(bidderServerResponseTime time.
 // RecordAdapterBidReceived implements a part of the MetricsEngine interface.
 // This tracks how many bids from each Bidder use `adm` vs. `nurl.
 func (me *Metrics) RecordAdapterBidReceived(labels AdapterLabels, bidType openrtb_ext.BidType, hasAdm bool) {
-	am, ok := me.AdapterMetrics[labels.Adapter]
+	adapterStr := string(labels.Adapter)
+	lowerCaseAdapterName := strings.ToLower(adapterStr)
+	am, ok := me.AdapterMetrics[lowerCaseAdapterName]
 	if !ok {
-		glog.Errorf("Trying to run adapter bid metrics on %s: adapter metrics not found", string(labels.Adapter))
+		glog.Errorf("Trying to run adapter bid metrics on %s: adapter metrics not found", adapterStr)
 		return
 	}
 
 	// Adapter metrics
 	am.BidsReceivedMeter.Mark(1)
 	// Account-Adapter metrics
-	if aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[labels.Adapter]; ok {
+	if aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[lowerCaseAdapterName]; ok {
 		aam.BidsReceivedMeter.Mark(1)
 	}
 
@@ -775,22 +787,26 @@ func (me *Metrics) RecordAdapterBidReceived(labels AdapterLabels, bidType openrt
 
 // RecordAdapterPrice implements a part of the MetricsEngine interface. Generates a histogram of winning bid prices
 func (me *Metrics) RecordAdapterPrice(labels AdapterLabels, cpm float64) {
-	am, ok := me.AdapterMetrics[labels.Adapter]
+	adapterStr := string(labels.Adapter)
+	lowercaseAdapter := strings.ToLower(adapterStr)
+	am, ok := me.AdapterMetrics[lowercaseAdapter]
 	if !ok {
-		glog.Errorf("Trying to run adapter price metrics on %s: adapter metrics not found", string(labels.Adapter))
+		glog.Errorf("Trying to run adapter price metrics on %s: adapter metrics not found", adapterStr)
 		return
 	}
 	// Adapter metrics
 	am.PriceHistogram.Update(int64(cpm))
 	// Account-Adapter metrics
-	if aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[labels.Adapter]; ok {
+	if aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[lowercaseAdapter]; ok {
 		aam.PriceHistogram.Update(int64(cpm))
 	}
 }
 
 // RecordAdapterTime implements a part of the MetricsEngine interface. Records the adapter response time
 func (me *Metrics) RecordAdapterTime(labels AdapterLabels, length time.Duration) {
-	am, ok := me.AdapterMetrics[labels.Adapter]
+	adapterStr := string(labels.Adapter)
+	lowercaseAdapter := strings.ToLower(adapterStr)
+	am, ok := me.AdapterMetrics[lowercaseAdapter]
 	if !ok {
 		glog.Errorf("Trying to run adapter latency metrics on %s: adapter metrics not found", string(labels.Adapter))
 		return
@@ -798,7 +814,7 @@ func (me *Metrics) RecordAdapterTime(labels AdapterLabels, length time.Duration)
 	// Adapter metrics
 	am.RequestTimer.Update(length)
 	// Account-Adapter metrics
-	if aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[labels.Adapter]; ok {
+	if aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[lowercaseAdapter]; ok {
 		aam.RequestTimer.Update(length)
 	}
 }
@@ -911,13 +927,14 @@ func (me *Metrics) RecordRequestPrivacy(privacy PrivacyLabels) {
 }
 
 func (me *Metrics) RecordAdapterGDPRRequestBlocked(adapterName openrtb_ext.BidderName) {
+	adapterStr := string(adapterName)
 	if me.MetricsDisabled.AdapterGDPRRequestBlocked {
 		return
 	}
 
-	am, ok := me.AdapterMetrics[adapterName]
+	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
 	if !ok {
-		glog.Errorf("Trying to log adapter GDPR request blocked metric for %s: adapter not found", string(adapterName))
+		glog.Errorf("Trying to log adapter GDPR request blocked metric for %s: adapter not found", adapterStr)
 		return
 	}
 
@@ -937,9 +954,10 @@ func (me *Metrics) RecordAdsCertSignTime(adsCertSignTime time.Duration) {
 }
 
 func (me *Metrics) RecordBidValidationCreativeSizeError(adapter openrtb_ext.BidderName, pubID string) {
-	am, ok := me.AdapterMetrics[adapter]
+	adapterStr := string(adapter)
+	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
 	if !ok {
-		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", string(adapter))
+		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
 		return
 	}
 	am.BidValidationCreativeSizeErrorMeter.Mark(1)
@@ -951,9 +969,10 @@ func (me *Metrics) RecordBidValidationCreativeSizeError(adapter openrtb_ext.Bidd
 }
 
 func (me *Metrics) RecordBidValidationCreativeSizeWarn(adapter openrtb_ext.BidderName, pubID string) {
-	am, ok := me.AdapterMetrics[adapter]
+	adapterStr := string(adapter)
+	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
 	if !ok {
-		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", string(adapter))
+		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
 		return
 	}
 	am.BidValidationCreativeSizeWarnMeter.Mark(1)
@@ -965,9 +984,10 @@ func (me *Metrics) RecordBidValidationCreativeSizeWarn(adapter openrtb_ext.Bidde
 }
 
 func (me *Metrics) RecordBidValidationSecureMarkupError(adapter openrtb_ext.BidderName, pubID string) {
-	am, ok := me.AdapterMetrics[adapter]
+	adapterStr := string(adapter)
+	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
 	if !ok {
-		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", string(adapter))
+		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
 		return
 	}
 	am.BidValidationSecureMarkupErrorMeter.Mark(1)
@@ -979,9 +999,10 @@ func (me *Metrics) RecordBidValidationSecureMarkupError(adapter openrtb_ext.Bidd
 }
 
 func (me *Metrics) RecordBidValidationSecureMarkupWarn(adapter openrtb_ext.BidderName, pubID string) {
-	am, ok := me.AdapterMetrics[adapter]
+	adapterStr := string(adapter)
+	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
 	if !ok {
-		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", string(adapter))
+		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
 		return
 	}
 	am.BidValidationSecureMarkupWarnMeter.Mark(1)
diff --git a/metrics/metrics.go b/metrics/metrics.go
index 99e64af0..0c3025bd 100644
--- a/metrics/metrics.go
+++ b/metrics/metrics.go
@@ -282,6 +282,7 @@ func AdapterErrors() []AdapterError {
 		AdapterErrorTimeout,
 		AdapterErrorFailedToRequestBids,
 		AdapterErrorValidation,
+		AdapterErrorTmaxTimeout,
 		AdapterErrorUnknown,
 	}
 }
diff --git a/metrics/prometheus/preload.go b/metrics/prometheus/preload.go
index 59f70cfb..db40feab 100644
--- a/metrics/prometheus/preload.go
+++ b/metrics/prometheus/preload.go
@@ -9,7 +9,7 @@ import (
 func preloadLabelValues(m *Metrics, syncerKeys []string, moduleStageNames map[string][]string) {
 	var (
 		adapterErrorValues        = enumAsString(metrics.AdapterErrors())
-		adapterValues             = enumAsString(openrtb_ext.CoreBidderNames())
+		adapterValues             = enumAsLowerCaseString(openrtb_ext.CoreBidderNames())
 		bidTypeValues             = []string{markupDeliveryAdm, markupDeliveryNurl}
 		boolValues                = boolValuesAsString()
 		cacheResultValues         = enumAsString(metrics.CacheResults())
diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go
index 30fb6c5f..bd63997f 100644
--- a/metrics/prometheus/prometheus.go
+++ b/metrics/prometheus/prometheus.go
@@ -3,6 +3,7 @@ package prometheusmetrics
 import (
 	"fmt"
 	"strconv"
+	"strings"
 	"time"
 
 	"github.com/prebid/prebid-server/config"
@@ -762,15 +763,16 @@ func (m *Metrics) RecordStoredDataError(labels metrics.StoredDataLabels) {
 }
 
 func (m *Metrics) RecordAdapterRequest(labels metrics.AdapterLabels) {
+	lowerCasedAdapter := strings.ToLower(string(labels.Adapter))
 	m.adapterRequests.With(prometheus.Labels{
-		adapterLabel: string(labels.Adapter),
+		adapterLabel: lowerCasedAdapter,
 		cookieLabel:  string(labels.CookieFlag),
 		hasBidsLabel: strconv.FormatBool(labels.AdapterBids == metrics.AdapterBidPresent),
 	}).Inc()
 
 	for err := range labels.AdapterErrors {
 		m.adapterErrors.With(prometheus.Labels{
-			adapterLabel:      string(labels.Adapter),
+			adapterLabel:      lowerCasedAdapter,
 			adapterErrorLabel: string(err),
 		}).Inc()
 	}
@@ -779,22 +781,23 @@ func (m *Metrics) RecordAdapterRequest(labels metrics.AdapterLabels) {
 // Keeps track of created and reused connections to adapter bidders and the time from the
 // connection request, to the connection creation, or reuse from the pool across all engines
 func (m *Metrics) RecordAdapterConnections(adapterName openrtb_ext.BidderName, connWasReused bool, connWaitTime time.Duration) {
+	lowerCasedAdapterName := strings.ToLower(string(adapterName))
 	if m.metricsDisabled.AdapterConnectionMetrics {
 		return
 	}
 
 	if connWasReused {
 		m.adapterReusedConnections.With(prometheus.Labels{
-			adapterLabel: string(adapterName),
+			adapterLabel: lowerCasedAdapterName,
 		}).Inc()
 	} else {
 		m.adapterCreatedConnections.With(prometheus.Labels{
-			adapterLabel: string(adapterName),
+			adapterLabel: lowerCasedAdapterName,
 		}).Inc()
 	}
 
 	m.adapterConnectionWaitTime.With(prometheus.Labels{
-		adapterLabel: string(adapterName),
+		adapterLabel: lowerCasedAdapterName,
 	}).Observe(connWaitTime.Seconds())
 }
 
@@ -812,7 +815,7 @@ func (m *Metrics) RecordBidderServerResponseTime(bidderServerResponseTime time.D
 
 func (m *Metrics) RecordAdapterPanic(labels metrics.AdapterLabels) {
 	m.adapterPanics.With(prometheus.Labels{
-		adapterLabel: string(labels.Adapter),
+		adapterLabel: strings.ToLower(string(labels.Adapter)),
 	}).Inc()
 }
 
@@ -823,14 +826,14 @@ func (m *Metrics) RecordAdapterBidReceived(labels metrics.AdapterLabels, bidType
 	}
 
 	m.adapterBids.With(prometheus.Labels{
-		adapterLabel:        string(labels.Adapter),
+		adapterLabel:        strings.ToLower(string(labels.Adapter)),
 		markupDeliveryLabel: markupDelivery,
 	}).Inc()
 }
 
 func (m *Metrics) RecordAdapterPrice(labels metrics.AdapterLabels, cpm float64) {
 	m.adapterPrices.With(prometheus.Labels{
-		adapterLabel: string(labels.Adapter),
+		adapterLabel: strings.ToLower(string(labels.Adapter)),
 	}).Observe(cpm)
 }
 
@@ -843,7 +846,7 @@ func (m *Metrics) RecordOverheadTime(overhead metrics.OverheadType, duration tim
 func (m *Metrics) RecordAdapterTime(labels metrics.AdapterLabels, length time.Duration) {
 	if len(labels.AdapterErrors) == 0 {
 		m.adapterRequestsTimer.With(prometheus.Labels{
-			adapterLabel: string(labels.Adapter),
+			adapterLabel: strings.ToLower(string(labels.Adapter)),
 		}).Observe(length.Seconds())
 	}
 }
@@ -955,7 +958,7 @@ func (m *Metrics) RecordAdapterGDPRRequestBlocked(adapterName openrtb_ext.Bidder
 	}
 
 	m.adapterGDPRBlockedRequests.With(prometheus.Labels{
-		adapterLabel: string(adapterName),
+		adapterLabel: strings.ToLower(string(adapterName)),
 	}).Inc()
 }
 
@@ -975,8 +978,9 @@ func (m *Metrics) RecordAdsCertSignTime(adsCertSignTime time.Duration) {
 }
 
 func (m *Metrics) RecordBidValidationCreativeSizeError(adapter openrtb_ext.BidderName, account string) {
+	lowerCasedAdapter := strings.ToLower(string(adapter))
 	m.adapterBidResponseValidationSizeError.With(prometheus.Labels{
-		adapterLabel: string(adapter), successLabel: successLabel,
+		adapterLabel: lowerCasedAdapter, successLabel: successLabel,
 	}).Inc()
 
 	if !m.metricsDisabled.AccountAdapterDetails && account != metrics.PublisherUnknown {
@@ -987,8 +991,9 @@ func (m *Metrics) RecordBidValidationCreativeSizeError(adapter openrtb_ext.Bidde
 }
 
 func (m *Metrics) RecordBidValidationCreativeSizeWarn(adapter openrtb_ext.BidderName, account string) {
+	lowerCasedAdapter := strings.ToLower(string(adapter))
 	m.adapterBidResponseValidationSizeWarn.With(prometheus.Labels{
-		adapterLabel: string(adapter), successLabel: successLabel,
+		adapterLabel: lowerCasedAdapter, successLabel: successLabel,
 	}).Inc()
 
 	if !m.metricsDisabled.AccountAdapterDetails && account != metrics.PublisherUnknown {
@@ -1000,7 +1005,7 @@ func (m *Metrics) RecordBidValidationCreativeSizeWarn(adapter openrtb_ext.Bidder
 
 func (m *Metrics) RecordBidValidationSecureMarkupError(adapter openrtb_ext.BidderName, account string) {
 	m.adapterBidResponseSecureMarkupError.With(prometheus.Labels{
-		adapterLabel: string(adapter), successLabel: successLabel,
+		adapterLabel: strings.ToLower(string(adapter)), successLabel: successLabel,
 	}).Inc()
 
 	if !m.metricsDisabled.AccountAdapterDetails && account != metrics.PublisherUnknown {
@@ -1012,7 +1017,7 @@ func (m *Metrics) RecordBidValidationSecureMarkupError(adapter openrtb_ext.Bidde
 
 func (m *Metrics) RecordBidValidationSecureMarkupWarn(adapter openrtb_ext.BidderName, account string) {
 	m.adapterBidResponseSecureMarkupWarn.With(prometheus.Labels{
-		adapterLabel: string(adapter), successLabel: successLabel,
+		adapterLabel: strings.ToLower(string(adapter)), successLabel: successLabel,
 	}).Inc()
 
 	if !m.metricsDisabled.AccountAdapterDetails && account != metrics.PublisherUnknown {
diff --git a/metrics/prometheus/type_conversion.go b/metrics/prometheus/type_conversion.go
index 0ae5366b..9bf2ec94 100644
--- a/metrics/prometheus/type_conversion.go
+++ b/metrics/prometheus/type_conversion.go
@@ -2,6 +2,7 @@ package prometheusmetrics
 
 import (
 	"strconv"
+	"strings"
 )
 
 func enumAsString[T ~string](values []T) []string {
@@ -12,6 +13,14 @@ func enumAsString[T ~string](values []T) []string {
 	return valuesAsString
 }
 
+func enumAsLowerCaseString[T ~string](values []T) []string {
+	valuesAsString := make([]string, len(values))
+	for i, v := range values {
+		valuesAsString[i] = strings.ToLower(string(v))
+	}
+	return valuesAsString
+}
+
 func boolValuesAsString() []string {
 	return []string{
 		strconv.FormatBool(true),
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 744c7fad..8b0262bc 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -23,7 +23,6 @@ var coreBidderNames []BidderName = []BidderName{
 	BidderAceex,
 	BidderAcuityAds,
 	BidderAdf,
-	BidderAdform,
 	BidderAdgeneration,
 	BidderAdhese,
 	BidderAdkernel,
@@ -84,7 +83,6 @@ var coreBidderNames []BidderName = []BidderName{
 	BidderConnectAd,
 	BidderConsumable,
 	BidderConversant,
-	BidderCopper6,
 	BidderCpmstar,
 	BidderCriteo,
 	BidderCWire,
@@ -315,7 +313,6 @@ const (
 	BidderAceex             BidderName = "aceex"
 	BidderAcuityAds         BidderName = "acuityads"
 	BidderAdf               BidderName = "adf"
-	BidderAdform            BidderName = "adform"
 	BidderAdgeneration      BidderName = "adgeneration"
 	BidderAdhese            BidderName = "adhese"
 	BidderAdkernel          BidderName = "adkernel"
@@ -376,7 +373,6 @@ const (
 	BidderConnectAd         BidderName = "connectad"
 	BidderConsumable        BidderName = "consumable"
 	BidderConversant        BidderName = "conversant"
-	BidderCopper6           BidderName = "copper6"
 	BidderCpmstar           BidderName = "cpmstar"
 	BidderCriteo            BidderName = "criteo"
 	BidderCWire             BidderName = "cwire"
diff --git a/static/bidder-info/adform.yaml b/static/bidder-info/adform.yaml
index 2310f346..4aa6e70f 100644
--- a/static/bidder-info/adform.yaml
+++ b/static/bidder-info/adform.yaml
@@ -1,19 +1,1 @@
-endpoint: "https://adx.adform.net/adx/openrtb"
-maintainer:
-  email: "scope.sspp@adform.com"
-gvlVendorID: 50
-capabilities:
-  app:
-    mediaTypes:
-      - banner
-      - native
-      - video
-  site:
-    mediaTypes:
-      - banner
-      - native
-      - video
-userSync:
-  redirect:
-    url: "https://cm.adform.net/cookie?redirect_url={{.RedirectURL}}"
-    userMacro: "$UID"
+aliasOf: adf
diff --git a/static/bidder-info/copper6.yaml b/static/bidder-info/copper6.yaml
index 213cbe36..b4e259ef 100644
--- a/static/bidder-info/copper6.yaml
+++ b/static/bidder-info/copper6.yaml
@@ -1,15 +1,7 @@
+aliasOf: adtelligent
 endpoint: "http://ghb.app.copper6.com/pbs/ortb"
 maintainer:
   email: "info@copper6.com"
-capabilities:
-  app:
-    mediaTypes:
-      - banner
-      - video
-  site:
-    mediaTypes:
-      - banner
-      - video
 userSync:
   # Copper6 ssp supports user syncing, but requires configuration by the host. contact this
   # bidder directly at the email address in this file to ask about enabling user sync.
diff --git a/static/bidder-info/orbidder.yaml b/static/bidder-info/orbidder.yaml
index 74348c75..c42fb91d 100644
--- a/static/bidder-info/orbidder.yaml
+++ b/static/bidder-info/orbidder.yaml
@@ -11,6 +11,7 @@ capabilities:
       - banner
       - native
 userSync:
+  supportCors: true
   redirect:
     url: "https://orbidder.otto.de/pbs-usersync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&redirect={{.RedirectURL}}"
     userMacro: "[ODN_ID]"
\ No newline at end of file
diff --git a/static/bidder-params/adform.json b/static/bidder-params/adform.json
deleted file mode 100644
index e112f122..00000000
--- a/static/bidder-params/adform.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-04/schema#",
-  "title": "Adform Adapter Params",
-  "description": "A schema which validates params accepted by the adf adapter",
-  "type": "object",
-  "properties": {
-    "mid": {
-      "type": ["integer", "string"],
-      "pattern": "^\\d+$",
-      "description": "An ID which identifies the placement selling the impression"
-    },
-    "inv": {
-      "type": ["integer"],
-      "description": "An ID which identifies the Adform inventory source id"
-    },
-    "mname": {
-      "type": ["string"],
-      "description": "A Name which identifies the placement selling the impression"
-    },
-    "priceType": {
-      "type": ["string"],
-      "description": "gross or net. Default is net.",
-      "pattern": "gross|net"
-    }
-  },
-  "anyOf":[
-    {
-      "required": ["mid"]
-    }, {
-      "required": ["inv", "mname"]
-    }
-  ]
-}
diff --git a/static/bidder-params/copper6.json b/static/bidder-params/copper6.json
deleted file mode 100644
index fa4050f6..00000000
--- a/static/bidder-params/copper6.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-04/schema#",
-  "title": "Copper6 Adapter Params",
-  "description": "A schema which validates params accepted by the Copper6 ssp adapter",
-
-  "type": "object",
-  "properties": {
-    "placementId": {
-      "type": "integer",
-      "description": "An ID which identifies this placement of the impression"
-    },
-    "siteId": {
-      "type": "integer",
-      "description": "An ID which identifies the site selling the impression"
-    },
-    "aid": {
-      "type": "integer",
-      "description": "An ID which identifies the channel"
-    },
-    "bidFloor": {
-      "type": "number",
-      "description": "BidFloor, US Dollars"
-    }
-  },
-  "required": ["aid"]
-}
diff --git a/usersync/bidderfilter.go b/usersync/bidderfilter.go
index 2d7d16ff..2e4df476 100644
--- a/usersync/bidderfilter.go
+++ b/usersync/bidderfilter.go
@@ -1,5 +1,9 @@
 package usersync
 
+import (
+	"strings"
+)
+
 // BidderFilter determines if a bidder has permission to perform a user sync activity.
 type BidderFilter interface {
 	// Allowed returns true if the filter determines the bidder has permission and false if either
@@ -40,7 +44,7 @@ func (f SpecificBidderFilter) Allowed(bidder string) bool {
 func NewSpecificBidderFilter(bidders []string, mode BidderFilterMode) BidderFilter {
 	biddersLookup := make(map[string]struct{}, len(bidders))
 	for _, bidder := range bidders {
-		biddersLookup[bidder] = struct{}{}
+		biddersLookup[strings.ToLower(bidder)] = struct{}{}
 	}
 
 	return SpecificBidderFilter{biddersLookup: biddersLookup, mode: mode}
diff --git a/usersync/chooser.go b/usersync/chooser.go
index 3f478049..578c6371 100644
--- a/usersync/chooser.go
+++ b/usersync/chooser.go
@@ -1,5 +1,10 @@
 package usersync
 
+import (
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"strings"
+)
+
 // Chooser determines which syncers are eligible for a given request.
 type Chooser interface {
 	// Choose considers bidders to sync, filters the bidders, and returns the result of the
@@ -15,9 +20,10 @@ func NewChooser(bidderSyncerLookup map[string]Syncer) Chooser {
 	}
 
 	return standardChooser{
-		bidderSyncerLookup: bidderSyncerLookup,
-		biddersAvailable:   bidders,
-		bidderChooser:      standardBidderChooser{shuffler: randomShuffler{}},
+		bidderSyncerLookup:       bidderSyncerLookup,
+		biddersAvailable:         bidders,
+		bidderChooser:            standardBidderChooser{shuffler: randomShuffler{}},
+		normalizeValidBidderName: openrtb_ext.NormalizeBidderName,
 	}
 }
 
@@ -100,9 +106,10 @@ type Privacy interface {
 
 // standardChooser implements the user syncer algorithm per official Prebid specification.
 type standardChooser struct {
-	bidderSyncerLookup map[string]Syncer
-	biddersAvailable   []string
-	bidderChooser      bidderChooser
+	bidderSyncerLookup       map[string]Syncer
+	biddersAvailable         []string
+	bidderChooser            bidderChooser
+	normalizeValidBidderName func(name string) (openrtb_ext.BidderName, bool)
 }
 
 // Choose randomly selects user syncers which are permitted by the user's privacy settings and
@@ -136,7 +143,12 @@ func (c standardChooser) Choose(request Request, cookie *Cookie) Result {
 }
 
 func (c standardChooser) evaluate(bidder string, syncersSeen map[string]struct{}, syncTypeFilter SyncTypeFilter, privacy Privacy, cookie *Cookie) (Syncer, BidderEvaluation) {
-	syncer, exists := c.bidderSyncerLookup[bidder]
+	bidderNormalized, exists := c.normalizeValidBidderName(bidder)
+	if !exists {
+		return nil, BidderEvaluation{Status: StatusUnknownBidder, Bidder: bidder}
+	}
+
+	syncer, exists := c.bidderSyncerLookup[bidderNormalized.String()]
 	if !exists {
 		return nil, BidderEvaluation{Status: StatusUnknownBidder, Bidder: bidder}
 	}
@@ -147,7 +159,7 @@ func (c standardChooser) evaluate(bidder string, syncersSeen map[string]struct{}
 	}
 	syncersSeen[syncer.Key()] = struct{}{}
 
-	if !syncer.SupportsType(syncTypeFilter.ForBidder(bidder)) {
+	if !syncer.SupportsType(syncTypeFilter.ForBidder(strings.ToLower(bidder))) {
 		return nil, BidderEvaluation{Status: StatusTypeNotSupported, Bidder: bidder, SyncerKey: syncer.Key()}
 	}
 
@@ -160,11 +172,11 @@ func (c standardChooser) evaluate(bidder string, syncersSeen map[string]struct{}
 		return nil, BidderEvaluation{Status: StatusBlockedByPrivacy, Bidder: bidder, SyncerKey: syncer.Key()}
 	}
 
-	if !privacy.GDPRAllowsBidderSync(bidder) {
+	if !privacy.GDPRAllowsBidderSync(bidderNormalized.String()) {
 		return nil, BidderEvaluation{Status: StatusBlockedByGDPR, Bidder: bidder, SyncerKey: syncer.Key()}
 	}
 
-	if !privacy.CCPAAllowsBidderSync(bidder) {
+	if !privacy.CCPAAllowsBidderSync(bidderNormalized.String()) {
 		return nil, BidderEvaluation{Status: StatusBlockedByCCPA, Bidder: bidder, SyncerKey: syncer.Key()}
 	}
 


Test patch:
diff --git a/adapters/sovrn/sovrntest/video/simple-video.json b/adapters/sovrn/sovrntest/video/simple-video.json
index 9cfeef5e..fae6778a 100644
--- a/adapters/sovrn/sovrntest/video/simple-video.json
+++ b/adapters/sovrn/sovrntest/video/simple-video.json
@@ -10,7 +10,6 @@
           "video/3gpp",
           "video/x-ms-wmv"
         ],
-        "minduration": 5,
         "maxduration": 30,
         "protocols": [
           4,
@@ -79,7 +78,6 @@
                   "video/3gpp",
                   "video/x-ms-wmv"
                 ],
-                "minduration": 5,
                 "maxduration": 30,
                 "protocols": [
                   4,
diff --git a/adapters/sovrn/sovrntest/videosupplemental/no-minduration.json b/adapters/sovrn/sovrntest/videosupplemental/no-minduration.json
deleted file mode 100644
index 88703dda..00000000
--- a/adapters/sovrn/sovrntest/videosupplemental/no-minduration.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-  "mockBidRequest": {
-    "id": "test-request-id",
-    "imp": [
-      {
-        "id": "test-imp-id",
-        "video": {
-          "mimes": [
-            "video/mp4",
-            "video/3gpp",
-            "video/x-ms-wmv"
-          ],
-          "maxduration": 30,
-          "protocols": [
-            4,
-            5,
-            6,
-            8
-          ]
-        },
-        "ext": {
-          "bidder": {
-            "tagid": "123456"
-          }
-        }
-      }
-    ],
-    "device": {
-      "ua": "test-user-agent",
-      "ip": "123.123.123.123",
-      "language": "en",
-      "dnt": 0
-    },
-    "site": {
-      "domain": "www.publisher.com",
-      "page": "http://www.publisher.com/awesome/site"
-    },
-    "user": {
-      "buyeruid": "test_reader_id"
-    }
-  },
-  "expectedMakeRequestsErrors": [
-    {
-      "value": "Missing required video parameter",
-      "comparison": "literal"
-    }
-  ],
-  "httpCalls": []
-}
diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go
index 45f7a75d..af7819b9 100644
--- a/endpoints/cookie_sync_test.go
+++ b/endpoints/cookie_sync_test.go
@@ -87,7 +87,7 @@ func TestNewCookieSyncEndpoint(t *testing.T) {
 	assert.IsType(t, &cookieSyncEndpoint{}, endpoint)
 
 	assert.Equal(t, expected.config, result.config)
-	assert.Equal(t, expected.chooser, result.chooser)
+	assert.ObjectsAreEqualValues(expected.chooser, result.chooser)
 	assert.Equal(t, expected.metrics, result.metrics)
 	assert.Equal(t, expected.pbsAnalytics, result.pbsAnalytics)
 	assert.Equal(t, expected.accountsFetcher, result.accountsFetcher)
diff --git a/endpoints/events/vtrack_test.go b/endpoints/events/vtrack_test.go
index 2c40c9b4..1e36a9e6 100644
--- a/endpoints/events/vtrack_test.go
+++ b/endpoints/events/vtrack_test.go
@@ -13,6 +13,7 @@ import (
 	"testing"
 
 	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/prebid/prebid-server/prebid_cache_client"
 	"github.com/prebid/prebid-server/stored_requests"
 	"github.com/stretchr/testify/assert"
@@ -28,15 +29,17 @@ const (
 
 // Mock pbs cache client
 type vtrackMockCacheClient struct {
-	Fail  bool
-	Error error
-	Uuids []string
+	Fail   bool
+	Error  error
+	Uuids  []string
+	Values []prebid_cache_client.Cacheable
 }
 
 func (m *vtrackMockCacheClient) PutJson(ctx context.Context, values []prebid_cache_client.Cacheable) ([]string, []error) {
 	if m.Fail {
 		return []string{}, []error{m.Error}
 	}
+	m.Values = values
 	return m.Uuids, []error{}
 }
 func (m *vtrackMockCacheClient) GetExtCacheData() (scheme string, host string, path string) {
@@ -64,10 +67,11 @@ func TestShouldRespondWithBadRequestWhenAccountParameterIsMissing(t *testing.T)
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: nil,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         nil,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -105,10 +109,11 @@ func TestShouldRespondWithBadRequestWhenRequestBodyIsEmpty(t *testing.T) {
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: nil,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         nil,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -146,10 +151,11 @@ func TestShouldRespondWithBadRequestWhenRequestBodyIsInvalid(t *testing.T) {
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: nil,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         nil,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -190,10 +196,11 @@ func TestShouldRespondWithBadRequestWhenBidIdIsMissing(t *testing.T) {
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: nil,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         nil,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -242,10 +249,11 @@ func TestShouldRespondWithBadRequestWhenBidderIsMissing(t *testing.T) {
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: nil,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         nil,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -291,10 +299,11 @@ func TestShouldRespondWithInternalServerErrorWhenPbsCacheClientFails(t *testing.
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: nil,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         nil,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -340,10 +349,11 @@ func TestShouldTolerateAccountNotFound(t *testing.T) {
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: nil,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         nil,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -397,10 +407,11 @@ func TestShouldSendToCacheExpectedPutsAndUpdatableBiddersWhenBidderVastNotAllowe
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: bidderInfos,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         bidderInfos,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -459,11 +470,15 @@ func TestShouldSendToCacheExpectedPutsAndUpdatableBiddersWhenBidderVastAllowed(t
 
 	recorder := httptest.NewRecorder()
 
+	var mockNormalizeBidderName normalizeBidderName = func(name string) (openrtb_ext.BidderName, bool) {
+		return openrtb_ext.BidderName(name), true
+	}
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: bidderInfos,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         bidderInfos,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: mockNormalizeBidderName,
 	}
 
 	// execute
@@ -478,6 +493,95 @@ func TestShouldSendToCacheExpectedPutsAndUpdatableBiddersWhenBidderVastAllowed(t
 	assert.Equal(t, 200, recorder.Result().StatusCode, "Expected 200 when account is not found and request is valid")
 	assert.Equal(t, "{\"responses\":[{\"uuid\":\"uuid1\"},{\"uuid\":\"uuid2\"}]}", string(d), "Expected 200 when account is found and request is valid")
 	assert.Equal(t, "application/json", recorder.Header().Get("Content-Type"))
+	assert.Len(t, mockCacheClient.Values, 2)
+	assert.Contains(t, string(mockCacheClient.Values[0].Data), "bidder=bidder")
+	assert.Contains(t, string(mockCacheClient.Values[1].Data), "bidder=updatable_bidder")
+}
+
+func TestShouldSendToCacheExpectedPutsAndUpdatableCaseSensitiveBiddersWhenBidderVastAllowed(t *testing.T) {
+	// mock pbs cache client
+	mockCacheClient := &vtrackMockCacheClient{
+		Fail:  false,
+		Uuids: []string{"uuid1", "uuid2"},
+	}
+
+	// mock AccountsFetcher
+	mockAccountsFetcher := &mockAccountsFetcher{
+		Fail: false,
+	}
+
+	// config
+	cfg := &config.Configuration{
+		MaxRequestSize: maxSize, VTrack: config.VTrack{
+			TimeoutMS: int64(2000), AllowUnknownBidder: false,
+		},
+		AccountDefaults: config.Account{},
+	}
+	cfg.MarshalAccountDefaults()
+
+	// bidder info
+	bidderInfos := make(config.BidderInfos)
+	bidderInfos["appnexus"] = config.BidderInfo{
+		Disabled:                false,
+		ModifyingVastXmlAllowed: true,
+	}
+
+	d, err := getVTrackRequestData(true, true)
+	assert.NoError(t, err)
+
+	cacheReq := &BidCacheRequest{
+		Puts: []prebid_cache_client.Cacheable{
+			{
+				Type:       prebid_cache_client.TypeXML,
+				BidID:      "bidId1",
+				Bidder:     "APPNEXUS", // case sensitive name
+				Data:       d,
+				TTLSeconds: 3600,
+				Timestamp:  1000,
+			},
+			{
+				Type:       prebid_cache_client.TypeXML,
+				BidID:      "bidId2",
+				Bidder:     "ApPnExUs", // case sensitive name
+				Data:       d,
+				TTLSeconds: 3600,
+				Timestamp:  1000,
+			},
+		},
+	}
+	buf := &bytes.Buffer{}
+	enc := json.NewEncoder(buf)
+	enc.SetEscapeHTML(false)
+	err = enc.Encode(cacheReq)
+	assert.NoError(t, err)
+	data := buf.String()
+
+	req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(data))
+
+	recorder := httptest.NewRecorder()
+	e := vtrackEndpoint{
+		Cfg:                 cfg,
+		BidderInfos:         bidderInfos,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
+	}
+
+	// execute
+	e.Handle(recorder, req, nil)
+
+	d, err = io.ReadAll(recorder.Result().Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// validate
+	assert.Equal(t, 200, recorder.Result().StatusCode, "Expected 200 when account is not found and request is valid")
+	assert.Equal(t, "{\"responses\":[{\"uuid\":\"uuid1\"},{\"uuid\":\"uuid2\"}]}", string(d), "Expected 200 when account is found and request is valid")
+	assert.Equal(t, "application/json", recorder.Header().Get("Content-Type"))
+	assert.Len(t, mockCacheClient.Values, 2)
+	assert.Contains(t, string(mockCacheClient.Values[0].Data), "bidder=APPNEXUS")
+	assert.Contains(t, string(mockCacheClient.Values[1].Data), "bidder=ApPnExUs")
 }
 
 func TestShouldSendToCacheExpectedPutsAndUpdatableUnknownBiddersWhenUnknownBidderIsAllowed(t *testing.T) {
@@ -515,10 +619,11 @@ func TestShouldSendToCacheExpectedPutsAndUpdatableUnknownBiddersWhenUnknownBidde
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: bidderInfos,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         bidderInfos,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -571,10 +676,11 @@ func TestShouldReturnBadRequestWhenRequestExceedsMaxRequestSize(t *testing.T) {
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: bidderInfos,
-		Cache:       mockCacheClient,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         bidderInfos,
+		Cache:               mockCacheClient,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
@@ -615,10 +721,11 @@ func TestShouldRespondWithInternalErrorPbsCacheIsNotConfigured(t *testing.T) {
 	recorder := httptest.NewRecorder()
 
 	e := vtrackEndpoint{
-		Cfg:         cfg,
-		BidderInfos: nil,
-		Cache:       nil,
-		Accounts:    mockAccountsFetcher,
+		Cfg:                 cfg,
+		BidderInfos:         nil,
+		Cache:               nil,
+		Accounts:            mockAccountsFetcher,
+		normalizeBidderName: openrtb_ext.NormalizeBidderName,
 	}
 
 	// execute
diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go
index 3c0feb4f..4315ec79 100644
--- a/endpoints/openrtb2/amp_auction_test.go
+++ b/endpoints/openrtb2/amp_auction_test.go
@@ -50,6 +50,9 @@ func TestGoodAmpRequests(t *testing.T) {
 				"imp-with-stored-resp.json",
 				"gdpr-no-consentstring.json",
 				"gdpr.json",
+				"buyeruids-case-insensitive.json",
+				"buyeruids-camel-case.json",
+				"aliased-buyeruids-case-insensitive.json",
 			},
 		},
 		{
diff --git a/exchange/exchangetest/buyeruid_case_insensitive.json b/exchange/exchangetest/buyeruid_case_insensitive.json
new file mode 100644
index 00000000..6999e8c9
--- /dev/null
+++ b/exchange/exchangetest/buyeruid_case_insensitive.json
@@ -0,0 +1,144 @@
+{
+  "incomingRequest": {
+    "ortbRequest": {
+      "id": "some-request-id",
+      "site": {
+        "page": "test.somepage.com"
+      },
+      "user": {
+        "id": "userId",
+        "ext": {
+          "prebid": {
+            "buyeruids": {
+              "APPnexUS": "12345"
+            }
+          }
+        }
+      },
+      "imp": [
+        {
+          "id": "my-imp-id",
+          "video": {
+            "mimes": [
+              "video/mp4"
+            ]
+          },
+          "ext": {
+            "prebid": {
+              "bidder": {
+                "APPnexus": {
+                  "placementId": 1
+                },
+                "appNEXUS": {
+                  "placementId": 2
+                },
+                "amx": {}
+              }
+            }
+          }
+        }
+      ],
+      "ext": {
+        "prebid": {
+          "aliases": {
+            "APPnexus": "appnexus",
+            "appNEXUS": "appnexus"
+          }
+        }
+      }
+    }
+  },
+  "outgoingRequests": {
+    "APPnexus": {
+      "expectRequest": {
+        "ortbRequest": {
+          "id": "some-request-id",
+          "site": {
+            "page": "test.somepage.com"
+          },
+          "user": {
+            "id": "userId",
+            "buyeruid": "12345"
+          },
+          "imp": [
+            {
+              "id": "my-imp-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": 1
+                }
+              }
+            }
+          ]
+        }
+      }
+    },
+    "appNEXUS": {
+      "expectRequest": {
+        "ortbRequest": {
+          "id": "some-request-id",
+          "site": {
+            "page": "test.somepage.com"
+          },
+          "user": {
+            "id": "userId",
+            "buyeruid": "12345"
+          },
+          "imp": [
+            {
+              "id": "my-imp-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": 2
+                }
+              }
+            }
+          ]
+        }
+      }
+    },
+    "amx": {
+      "expectRequest": {
+        "ortbRequest": {
+          "id": "some-request-id",
+          "site": {
+            "page": "test.somepage.com"
+          },
+          "user": {
+            "id": "userId"
+          },
+          "imp": [
+            {
+              "id": "my-imp-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "bidder": {
+                }
+              }
+            }
+          ]
+        }
+      }
+    }
+  },
+  "response": {
+    "bids": {
+      "id": "some-request-id",
+      "ext": {}
+    }
+  }
+}
diff --git a/metrics/config/metrics_test.go b/metrics/config/metrics_test.go
index f77dcf00..1eae1a25 100644
--- a/metrics/config/metrics_test.go
+++ b/metrics/config/metrics_test.go
@@ -2,6 +2,7 @@ package config
 
 import (
 	"fmt"
+	"strings"
 	"testing"
 	"time"
 
@@ -168,13 +169,14 @@ func TestMultiMetricsEngine(t *testing.T) {
 	VerifyMetrics(t, "Request", goEngine.RequestStatuses[metrics.ReqTypeORTB2Web][metrics.RequestStatusOK].Count(), 5)
 	VerifyMetrics(t, "ImpMeter", goEngine.ImpMeter.Count(), 8)
 	VerifyMetrics(t, "NoCookieMeter", goEngine.NoCookieMeter.Count(), 0)
-	VerifyMetrics(t, "AdapterMetrics.Pubmatic.GotBidsMeter", goEngine.AdapterMetrics[openrtb_ext.BidderPubmatic].GotBidsMeter.Count(), 5)
-	VerifyMetrics(t, "AdapterMetrics.Pubmatic.NoBidMeter", goEngine.AdapterMetrics[openrtb_ext.BidderPubmatic].NoBidMeter.Count(), 0)
+
+	VerifyMetrics(t, "AdapterMetrics.pubmatic.GotBidsMeter", goEngine.AdapterMetrics[strings.ToLower(string(openrtb_ext.BidderPubmatic))].GotBidsMeter.Count(), 5)
+	VerifyMetrics(t, "AdapterMetrics.pubmatic.NoBidMeter", goEngine.AdapterMetrics[strings.ToLower(string(openrtb_ext.BidderPubmatic))].NoBidMeter.Count(), 0)
 	for _, err := range metrics.AdapterErrors() {
-		VerifyMetrics(t, "AdapterMetrics.Pubmatic.Request.ErrorMeter."+string(err), goEngine.AdapterMetrics[openrtb_ext.BidderPubmatic].ErrorMeters[err].Count(), 0)
+		VerifyMetrics(t, "AdapterMetrics.pubmatic.Request.ErrorMeter."+string(err), goEngine.AdapterMetrics[strings.ToLower(string(openrtb_ext.BidderPubmatic))].ErrorMeters[err].Count(), 0)
 	}
-	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, "AdapterMetrics.appnexus.GotBidsMeter", goEngine.AdapterMetrics[strings.ToLower(string(openrtb_ext.BidderAppnexus))].GotBidsMeter.Count(), 0)
+	VerifyMetrics(t, "AdapterMetrics.appnexus.NoBidMeter", goEngine.AdapterMetrics[strings.ToLower(string(openrtb_ext.BidderAppnexus))].NoBidMeter.Count(), 5)
 
 	VerifyMetrics(t, "RecordRequestQueueTime.Video.Rejected", goEngine.RequestsQueueTimer[metrics.ReqTypeVideo][false].Count(), 1)
 	VerifyMetrics(t, "RecordRequestQueueTime.Video.Accepted", goEngine.RequestsQueueTimer[metrics.ReqTypeVideo][true].Count(), 0)
@@ -186,7 +188,7 @@ func TestMultiMetricsEngine(t *testing.T) {
 	VerifyMetrics(t, "StoredImpCache.Hit", goEngine.StoredImpCacheMeter[metrics.CacheHit].Count(), 5)
 	VerifyMetrics(t, "AccountCache.Hit", goEngine.AccountCacheMeter[metrics.CacheHit].Count(), 6)
 
-	VerifyMetrics(t, "AdapterMetrics.AppNexus.GDPRRequestBlocked", goEngine.AdapterMetrics[openrtb_ext.BidderAppnexus].GDPRRequestBlocked.Count(), 1)
+	VerifyMetrics(t, "AdapterMetrics.appNexus.GDPRRequestBlocked", goEngine.AdapterMetrics[strings.ToLower(string(openrtb_ext.BidderAppnexus))].GDPRRequestBlocked.Count(), 1)
 
 	// verify that each module has its own metric recorded
 	for module, stages := range modulesStages {
diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go
index 8acd1923..08ee65f5 100644
--- a/metrics/go_metrics_test.go
+++ b/metrics/go_metrics_test.go
@@ -15,15 +15,15 @@ func TestNewMetrics(t *testing.T) {
 	registry := metrics.NewRegistry()
 	syncerKeys := []string{"foo"}
 	moduleStageNames := map[string][]string{"foobar": {"entry", "raw"}, "another_module": {"raw", "auction"}}
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{}, syncerKeys, moduleStageNames)
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Adapter1"), openrtb_ext.BidderName("Adapter2")}, config.DisabledMetrics{}, syncerKeys, moduleStageNames)
 
 	ensureContains(t, registry, "app_requests", m.AppRequestMeter)
 	ensureContains(t, registry, "debug_requests", m.DebugRequestMeter)
 	ensureContains(t, registry, "no_cookie_requests", m.NoCookieMeter)
 	ensureContains(t, registry, "request_time", m.RequestTimer)
 	ensureContains(t, registry, "amp_no_cookie_requests", m.AmpNoCookieMeter)
-	ensureContainsAdapterMetrics(t, registry, "adapter.appnexus", m.AdapterMetrics["appnexus"])
-	ensureContainsAdapterMetrics(t, registry, "adapter.rubicon", m.AdapterMetrics["rubicon"])
+	ensureContainsAdapterMetrics(t, registry, "adapter.adapter1", m.AdapterMetrics["adapter1"])
+	ensureContainsAdapterMetrics(t, registry, "adapter.adapter2", m.AdapterMetrics["adapter2"])
 	ensureContains(t, registry, "cookie_sync_requests", m.CookieSyncMeter)
 	ensureContains(t, registry, "cookie_sync_requests.ok", m.CookieSyncStatusMeter[CookieSyncOK])
 	ensureContains(t, registry, "cookie_sync_requests.bad_request", m.CookieSyncStatusMeter[CookieSyncBadRequest])
@@ -95,19 +95,21 @@ func TestNewMetrics(t *testing.T) {
 
 func TestRecordBidType(t *testing.T) {
 	registry := metrics.NewRegistry()
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{}, nil, nil)
+	adapterName := "FOO"
+	lowerCaseAdapterName := "foo"
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapterName)}, config.DisabledMetrics{}, nil, nil)
 
 	m.RecordAdapterBidReceived(AdapterLabels{
-		Adapter: openrtb_ext.BidderAppnexus,
+		Adapter: openrtb_ext.BidderName(adapterName),
 	}, openrtb_ext.BidTypeBanner, true)
-	VerifyMetrics(t, "Appnexus Banner Adm Bids", m.AdapterMetrics[openrtb_ext.BidderAppnexus].MarkupMetrics[openrtb_ext.BidTypeBanner].AdmMeter.Count(), 1)
-	VerifyMetrics(t, "Appnexus Banner Nurl Bids", m.AdapterMetrics[openrtb_ext.BidderAppnexus].MarkupMetrics[openrtb_ext.BidTypeBanner].NurlMeter.Count(), 0)
+	VerifyMetrics(t, "foo Banner Adm Bids", m.AdapterMetrics[lowerCaseAdapterName].MarkupMetrics[openrtb_ext.BidTypeBanner].AdmMeter.Count(), 1)
+	VerifyMetrics(t, "foo Banner Nurl Bids", m.AdapterMetrics[lowerCaseAdapterName].MarkupMetrics[openrtb_ext.BidTypeBanner].NurlMeter.Count(), 0)
 
 	m.RecordAdapterBidReceived(AdapterLabels{
-		Adapter: openrtb_ext.BidderAppnexus,
+		Adapter: openrtb_ext.BidderName(adapterName),
 	}, openrtb_ext.BidTypeVideo, false)
-	VerifyMetrics(t, "Appnexus Video Adm Bids", m.AdapterMetrics[openrtb_ext.BidderAppnexus].MarkupMetrics[openrtb_ext.BidTypeVideo].AdmMeter.Count(), 0)
-	VerifyMetrics(t, "Appnexus Video Nurl Bids", m.AdapterMetrics[openrtb_ext.BidderAppnexus].MarkupMetrics[openrtb_ext.BidTypeVideo].NurlMeter.Count(), 1)
+	VerifyMetrics(t, "foo Video Adm Bids", m.AdapterMetrics[lowerCaseAdapterName].MarkupMetrics[openrtb_ext.BidTypeVideo].AdmMeter.Count(), 0)
+	VerifyMetrics(t, "foo Video Nurl Bids", m.AdapterMetrics[lowerCaseAdapterName].MarkupMetrics[openrtb_ext.BidTypeVideo].NurlMeter.Count(), 1)
 }
 
 func ensureContains(t *testing.T, registry metrics.Registry, name string, metric interface{}) {
@@ -198,17 +200,19 @@ func TestRecordBidTypeDisabledConfig(t *testing.T) {
 			PubID:                  "acct-id",
 		},
 	}
-
+	adapter := "AnyName"
+	lowerCaseAdapter := "anyname"
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, test.DisabledMetrics, nil, nil)
+
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, test.DisabledMetrics, nil, nil)
 
 		m.RecordAdapterBidReceived(AdapterLabels{
-			Adapter: openrtb_ext.BidderAppnexus,
+			Adapter: openrtb_ext.BidderName(adapter),
 			PubID:   test.PubID,
 		}, test.BidType, test.hasAdm)
-		assert.Equal(t, test.ExpectedAdmMeterCount, m.AdapterMetrics[openrtb_ext.BidderAppnexus].MarkupMetrics[test.BidType].AdmMeter.Count(), "Appnexus Banner Adm Bids")
-		assert.Equal(t, test.ExpectedNurlMeterCount, m.AdapterMetrics[openrtb_ext.BidderAppnexus].MarkupMetrics[test.BidType].NurlMeter.Count(), "Appnexus Banner Nurl Bids")
+		assert.Equal(t, test.ExpectedAdmMeterCount, m.AdapterMetrics[lowerCaseAdapter].MarkupMetrics[test.BidType].AdmMeter.Count(), "AnyName Banner Adm Bids")
+		assert.Equal(t, test.ExpectedNurlMeterCount, m.AdapterMetrics[lowerCaseAdapter].MarkupMetrics[test.BidType].NurlMeter.Count(), "AnyName Banner Nurl Bids")
 
 		if test.DisabledMetrics.AccountAdapterDetails {
 			assert.Len(t, m.accountMetrics[test.PubID].adapterMetrics, 0, "Test failed. Account metrics that contain adapter information are disabled, therefore we expect no entries in m.accountMetrics[accountId].adapterMetrics, we have %d \n", len(m.accountMetrics[test.PubID].adapterMetrics))
@@ -272,9 +276,10 @@ func TestRecordDebugRequest(t *testing.T) {
 			expectedDebugCount:        0,
 		},
 	}
+	adapter := "AnyName"
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, test.givenDisabledMetrics, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, test.givenDisabledMetrics, nil, nil)
 
 		m.RecordDebugRequest(test.givenDebugEnabledFlag, test.givenPubID)
 		am := m.getAccountMetrics(test.givenPubID)
@@ -311,16 +316,18 @@ func TestRecordBidValidationCreativeSize(t *testing.T) {
 			expectedAccountCount: 0,
 		},
 	}
+	adapter := "AnyName"
+	lowerCaseAdapter := "anyname"
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, test.givenDisabledMetrics, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, test.givenDisabledMetrics, nil, nil)
 
-		m.RecordBidValidationCreativeSizeError(openrtb_ext.BidderAppnexus, test.givenPubID)
-		m.RecordBidValidationCreativeSizeWarn(openrtb_ext.BidderAppnexus, test.givenPubID)
+		m.RecordBidValidationCreativeSizeError(openrtb_ext.BidderName(adapter), test.givenPubID)
+		m.RecordBidValidationCreativeSizeWarn(openrtb_ext.BidderName(adapter), test.givenPubID)
 		am := m.getAccountMetrics(test.givenPubID)
 
-		assert.Equal(t, test.expectedAdapterCount, m.AdapterMetrics[openrtb_ext.BidderAppnexus].BidValidationCreativeSizeErrorMeter.Count())
-		assert.Equal(t, test.expectedAdapterCount, m.AdapterMetrics[openrtb_ext.BidderAppnexus].BidValidationCreativeSizeWarnMeter.Count())
+		assert.Equal(t, test.expectedAdapterCount, m.AdapterMetrics[lowerCaseAdapter].BidValidationCreativeSizeErrorMeter.Count())
+		assert.Equal(t, test.expectedAdapterCount, m.AdapterMetrics[lowerCaseAdapter].BidValidationCreativeSizeWarnMeter.Count())
 		assert.Equal(t, test.expectedAccountCount, am.bidValidationCreativeSizeMeter.Count())
 		assert.Equal(t, test.expectedAccountCount, am.bidValidationCreativeSizeWarnMeter.Count())
 	}
@@ -353,16 +360,18 @@ func TestRecordBidValidationSecureMarkup(t *testing.T) {
 			expectedAccountCount: 0,
 		},
 	}
+	adapter := "AnyName"
+	lowerCaseAdapter := "anyname"
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, test.givenDisabledMetrics, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, test.givenDisabledMetrics, nil, nil)
 
-		m.RecordBidValidationSecureMarkupError(openrtb_ext.BidderAppnexus, test.givenPubID)
-		m.RecordBidValidationSecureMarkupWarn(openrtb_ext.BidderAppnexus, test.givenPubID)
+		m.RecordBidValidationSecureMarkupError(openrtb_ext.BidderName(adapter), test.givenPubID)
+		m.RecordBidValidationSecureMarkupWarn(openrtb_ext.BidderName(adapter), test.givenPubID)
 		am := m.getAccountMetrics(test.givenPubID)
 
-		assert.Equal(t, test.expectedAdapterCount, m.AdapterMetrics[openrtb_ext.BidderAppnexus].BidValidationSecureMarkupErrorMeter.Count())
-		assert.Equal(t, test.expectedAdapterCount, m.AdapterMetrics[openrtb_ext.BidderAppnexus].BidValidationSecureMarkupWarnMeter.Count())
+		assert.Equal(t, test.expectedAdapterCount, m.AdapterMetrics[lowerCaseAdapter].BidValidationSecureMarkupErrorMeter.Count())
+		assert.Equal(t, test.expectedAdapterCount, m.AdapterMetrics[lowerCaseAdapter].BidValidationSecureMarkupWarnMeter.Count())
 		assert.Equal(t, test.expectedAccountCount, am.bidValidationSecureMarkupMeter.Count())
 		assert.Equal(t, test.expectedAccountCount, am.bidValidationSecureMarkupWarnMeter.Count())
 	}
@@ -385,9 +394,10 @@ func TestRecordDNSTime(t *testing.T) {
 			outExpDuration:      time.Duration(0),
 		},
 	}
+	adapter := "AnyName"
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
 
 		m.RecordDNSTime(test.inDnsLookupDuration)
 
@@ -412,9 +422,10 @@ func TestRecordTLSHandshakeTime(t *testing.T) {
 			expectedDuration:     time.Duration(0),
 		},
 	}
+	adapter := "AnyName"
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
 
 		m.RecordTLSHandshakeTime(test.tLSHandshakeDuration)
 
@@ -442,9 +453,10 @@ func TestRecordBidderServerResponseTime(t *testing.T) {
 			expectedSum:   1000,
 		},
 	}
+	adapter := "AnyName"
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
 
 		m.RecordBidderServerResponseTime(test.time)
 
@@ -467,7 +479,8 @@ func TestRecordAdapterConnections(t *testing.T) {
 		expectedConnCreatedCount int64
 		expectedConnWaitTime     time.Duration
 	}
-
+	adapter := "AnyName"
+	lowerCaseAdapterName := "anyname"
 	testCases := []struct {
 		description string
 		in          testIn
@@ -476,7 +489,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 		{
 			description: "Successful, new connection created, has connection wait",
 			in: testIn{
-				adapterName:         openrtb_ext.BidderAppnexus,
+				adapterName:         openrtb_ext.BidderName(adapter),
 				connWasReused:       false,
 				connWait:            time.Second * 5,
 				connMetricsDisabled: false,
@@ -490,7 +503,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 		{
 			description: "Successful, new connection created, has connection wait",
 			in: testIn{
-				adapterName:         openrtb_ext.BidderAppnexus,
+				adapterName:         openrtb_ext.BidderName(adapter),
 				connWasReused:       false,
 				connWait:            time.Second * 4,
 				connMetricsDisabled: false,
@@ -503,7 +516,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 		{
 			description: "Successful, was reused, no connection wait",
 			in: testIn{
-				adapterName:         openrtb_ext.BidderAppnexus,
+				adapterName:         openrtb_ext.BidderName(adapter),
 				connWasReused:       true,
 				connMetricsDisabled: false,
 			},
@@ -515,7 +528,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 		{
 			description: "Successful, was reused, has connection wait",
 			in: testIn{
-				adapterName:         openrtb_ext.BidderAppnexus,
+				adapterName:         openrtb_ext.BidderName(adapter),
 				connWasReused:       true,
 				connWait:            time.Second * 5,
 				connMetricsDisabled: false,
@@ -538,7 +551,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 		{
 			description: "Adapter connection metrics are disabled, nothing gets updated",
 			in: testIn{
-				adapterName:         openrtb_ext.BidderAppnexus,
+				adapterName:         openrtb_ext.BidderName(adapter),
 				connWasReused:       false,
 				connWait:            time.Second * 5,
 				connMetricsDisabled: true,
@@ -549,19 +562,18 @@ func TestRecordAdapterConnections(t *testing.T) {
 
 	for i, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{AdapterConnectionMetrics: test.in.connMetricsDisabled}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, config.DisabledMetrics{AdapterConnectionMetrics: test.in.connMetricsDisabled}, nil, nil)
 
 		m.RecordAdapterConnections(test.in.adapterName, test.in.connWasReused, test.in.connWait)
-
-		assert.Equal(t, test.out.expectedConnReusedCount, m.AdapterMetrics[openrtb_ext.BidderAppnexus].ConnReused.Count(), "Test [%d] incorrect number of reused connections to adapter", i)
-		assert.Equal(t, test.out.expectedConnCreatedCount, m.AdapterMetrics[openrtb_ext.BidderAppnexus].ConnCreated.Count(), "Test [%d] incorrect number of new connections to adapter created", i)
-		assert.Equal(t, test.out.expectedConnWaitTime.Nanoseconds(), m.AdapterMetrics[openrtb_ext.BidderAppnexus].ConnWaitTime.Sum(), "Test [%d] incorrect wait time in connection to adapter", i)
+		assert.Equal(t, test.out.expectedConnReusedCount, m.AdapterMetrics[lowerCaseAdapterName].ConnReused.Count(), "Test [%d] incorrect number of reused connections to adapter", i)
+		assert.Equal(t, test.out.expectedConnCreatedCount, m.AdapterMetrics[lowerCaseAdapterName].ConnCreated.Count(), "Test [%d] incorrect number of new connections to adapter created", i)
+		assert.Equal(t, test.out.expectedConnWaitTime.Nanoseconds(), m.AdapterMetrics[lowerCaseAdapterName].ConnWaitTime.Sum(), "Test [%d] incorrect wait time in connection to adapter", i)
 	}
 }
 
 func TestNewMetricsWithDisabledConfig(t *testing.T) {
 	registry := metrics.NewRegistry()
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{AccountAdapterDetails: true, AccountModulesMetrics: true}, nil, map[string][]string{"foobar": {"entry", "raw"}})
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Foo"), openrtb_ext.BidderName("bar")}, config.DisabledMetrics{AccountAdapterDetails: true, AccountModulesMetrics: true}, nil, map[string][]string{"foobar": {"entry", "raw"}})
 
 	assert.True(t, m.MetricsDisabled.AccountAdapterDetails, "Accound adapter metrics should be disabled")
 	assert.True(t, m.MetricsDisabled.AccountModulesMetrics, "Accound modules metrics should be disabled")
@@ -569,7 +581,7 @@ func TestNewMetricsWithDisabledConfig(t *testing.T) {
 
 func TestRecordPrebidCacheRequestTimeWithSuccess(t *testing.T) {
 	registry := metrics.NewRegistry()
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Foo")}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
 
 	m.RecordPrebidCacheRequestTime(true, 42)
 
@@ -579,7 +591,7 @@ func TestRecordPrebidCacheRequestTimeWithSuccess(t *testing.T) {
 
 func TestRecordPrebidCacheRequestTimeWithNotSuccess(t *testing.T) {
 	registry := metrics.NewRegistry()
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Foo")}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
 
 	m.RecordPrebidCacheRequestTime(false, 42)
 
@@ -647,7 +659,7 @@ func TestRecordStoredDataFetchTime(t *testing.T) {
 
 	for _, tt := range tests {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Foo"), openrtb_ext.BidderName("Bar")}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
 		m.RecordStoredDataFetchTime(StoredDataLabels{
 			DataType:      tt.dataType,
 			DataFetchType: tt.fetchType,
@@ -721,7 +733,7 @@ func TestRecordStoredDataError(t *testing.T) {
 
 	for _, tt := range tests {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Foo"), openrtb_ext.BidderName("Bar")}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
 		m.RecordStoredDataError(StoredDataLabels{
 			DataType: tt.dataType,
 			Error:    tt.errorType,
@@ -734,7 +746,7 @@ func TestRecordStoredDataError(t *testing.T) {
 
 func TestRecordRequestPrivacy(t *testing.T) {
 	registry := metrics.NewRegistry()
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Foo"), openrtb_ext.BidderName("Bar")}, config.DisabledMetrics{AccountAdapterDetails: true}, nil, nil)
 
 	// CCPA
 	m.RecordRequestPrivacy(PrivacyLabels{
@@ -780,6 +792,8 @@ func TestRecordRequestPrivacy(t *testing.T) {
 
 func TestRecordAdapterGDPRRequestBlocked(t *testing.T) {
 	var fakeBidder openrtb_ext.BidderName = "fooAdvertising"
+	adapter := "AnyName"
+	lowerCaseAdapterName := "anyname"
 
 	tests := []struct {
 		description     string
@@ -790,7 +804,7 @@ func TestRecordAdapterGDPRRequestBlocked(t *testing.T) {
 		{
 			description:     "",
 			metricsDisabled: false,
-			adapterName:     openrtb_ext.BidderAppnexus,
+			adapterName:     openrtb_ext.BidderName(adapter),
 			expectedCount:   1,
 		},
 		{
@@ -802,24 +816,23 @@ func TestRecordAdapterGDPRRequestBlocked(t *testing.T) {
 		{
 			description:     "",
 			metricsDisabled: true,
-			adapterName:     openrtb_ext.BidderAppnexus,
+			adapterName:     openrtb_ext.BidderName(adapter),
 			expectedCount:   0,
 		},
 	}
-
 	for _, tt := range tests {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{AdapterGDPRRequestBlocked: tt.metricsDisabled}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, config.DisabledMetrics{AdapterGDPRRequestBlocked: tt.metricsDisabled}, nil, nil)
 
 		m.RecordAdapterGDPRRequestBlocked(tt.adapterName)
 
-		assert.Equal(t, tt.expectedCount, m.AdapterMetrics[openrtb_ext.BidderAppnexus].GDPRRequestBlocked.Count(), tt.description)
+		assert.Equal(t, tt.expectedCount, m.AdapterMetrics[lowerCaseAdapterName].GDPRRequestBlocked.Count(), tt.description)
 	}
 }
 
 func TestRecordCookieSync(t *testing.T) {
 	registry := metrics.NewRegistry()
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{}, nil, nil)
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Foo"), openrtb_ext.BidderName("Bar")}, config.DisabledMetrics{}, nil, nil)
 
 	// Known
 	m.RecordCookieSync(CookieSyncBadRequest)
@@ -837,7 +850,7 @@ func TestRecordCookieSync(t *testing.T) {
 func TestRecordSyncerRequest(t *testing.T) {
 	registry := metrics.NewRegistry()
 	syncerKeys := []string{"foo"}
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{}, syncerKeys, nil)
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Adapter1"), openrtb_ext.BidderName("Adapter2")}, config.DisabledMetrics{}, syncerKeys, nil)
 
 	// Known
 	m.RecordSyncerRequest("foo", SyncerCookieSyncOK)
@@ -856,7 +869,7 @@ func TestRecordSyncerRequest(t *testing.T) {
 
 func TestRecordSetUid(t *testing.T) {
 	registry := metrics.NewRegistry()
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{}, nil, nil)
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Foo"), openrtb_ext.BidderName("Bar")}, config.DisabledMetrics{}, nil, nil)
 
 	// Known
 	m.RecordSetUid(SetUidOptOut)
@@ -875,7 +888,7 @@ func TestRecordSetUid(t *testing.T) {
 func TestRecordSyncerSet(t *testing.T) {
 	registry := metrics.NewRegistry()
 	syncerKeys := []string{"foo"}
-	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus, openrtb_ext.BidderRubicon}, config.DisabledMetrics{}, syncerKeys, nil)
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("Adapter1"), openrtb_ext.BidderName("Adapter2")}, config.DisabledMetrics{}, syncerKeys, nil)
 
 	// Known
 	m.RecordSyncerSet("foo", SyncerSetUidCleared)
@@ -929,7 +942,7 @@ func TestStoredResponses(t *testing.T) {
 	}
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{AccountStoredResponses: test.accountStoredResponsesMetricsDisabled}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("AnyName")}, config.DisabledMetrics{AccountStoredResponses: test.accountStoredResponsesMetricsDisabled}, nil, nil)
 
 		m.RecordStoredResponse(test.givenPubID)
 		am := m.getAccountMetrics(test.givenPubID)
@@ -963,7 +976,7 @@ func TestRecordAdsCertSignTime(t *testing.T) {
 	}
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("AnyName")}, config.DisabledMetrics{}, nil, nil)
 
 		m.RecordAdsCertSignTime(test.inAdsCertSignDuration)
 
@@ -994,7 +1007,7 @@ func TestRecordAdsCertReqMetric(t *testing.T) {
 
 	for _, test := range testCases {
 		registry := metrics.NewRegistry()
-		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, config.DisabledMetrics{}, nil, nil)
+		m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName("AnyName")}, config.DisabledMetrics{}, nil, nil)
 
 		m.RecordAdsCertReq(test.requestSuccess)
 
@@ -1131,3 +1144,127 @@ func VerifyMetrics(t *testing.T, name string, expected int64, actual int64) {
 		t.Errorf("Error in metric %s: expected %d, got %d.", name, expected, actual)
 	}
 }
+
+func TestRecordAdapterPanic(t *testing.T) {
+	registry := metrics.NewRegistry()
+	adapter := "AnyName"
+	lowerCaseAdapterName := "anyname"
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, config.DisabledMetrics{AccountAdapterDetails: true, AccountModulesMetrics: true}, nil, map[string][]string{"foobar": {"entry", "raw"}})
+	m.RecordAdapterPanic(AdapterLabels{Adapter: openrtb_ext.BidderName(adapter)})
+	assert.Equal(t, m.AdapterMetrics[lowerCaseAdapterName].PanicMeter.Count(), int64(1))
+}
+
+func TestRecordAdapterPrice(t *testing.T) {
+	registry := metrics.NewRegistry()
+	syncerKeys := []string{"foo"}
+	adapter := "AnyName"
+	lowerCaseAdapterName := "anyname"
+	pubID := "pub1"
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter), openrtb_ext.BidderAppnexus}, config.DisabledMetrics{}, syncerKeys, nil)
+	m.RecordAdapterPrice(AdapterLabels{Adapter: openrtb_ext.BidderName(adapter), PubID: pubID}, 1000)
+	assert.Equal(t, m.AdapterMetrics[lowerCaseAdapterName].PriceHistogram.Max(), int64(1000))
+	assert.Equal(t, m.getAccountMetrics(pubID).adapterMetrics[lowerCaseAdapterName].PriceHistogram.Max(), int64(1000))
+}
+
+func TestRecordAdapterTime(t *testing.T) {
+	registry := metrics.NewRegistry()
+	syncerKeys := []string{"foo"}
+	adapter := "AnyName"
+	lowerCaseAdapterName := "anyname"
+	pubID := "pub1"
+	m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter), openrtb_ext.BidderAppnexus, openrtb_ext.BidderName("Adapter2")}, config.DisabledMetrics{}, syncerKeys, nil)
+	m.RecordAdapterTime(AdapterLabels{Adapter: openrtb_ext.BidderName(adapter), PubID: pubID}, 1000)
+	assert.Equal(t, m.AdapterMetrics[lowerCaseAdapterName].RequestTimer.Max(), int64(1000))
+	assert.Equal(t, m.getAccountMetrics(pubID).adapterMetrics[lowerCaseAdapterName].RequestTimer.Max(), int64(1000))
+}
+
+func TestRecordAdapterRequest(t *testing.T) {
+	syncerKeys := []string{"foo"}
+	moduleStageNames := map[string][]string{"foobar": {"entry", "raw"}, "another_module": {"raw", "auction"}}
+	adapter := "AnyName"
+	lowerCaseAdapter := "anyname"
+	type errorCount struct {
+		badInput, badServer, timeout, failedToRequestBid, validation, tmaxTimeout, unknown int64
+	}
+	type adapterBidsCount struct {
+		NoBid, GotBid int64
+	}
+	tests := []struct {
+		description              string
+		labels                   AdapterLabels
+		expectedNoCookieCount    int64
+		expectedAdapterBidsCount adapterBidsCount
+		expectedErrorCount       errorCount
+	}{
+		{
+			description: "no-bid",
+			labels: AdapterLabels{
+				Adapter:     openrtb_ext.BidderName(adapter),
+				AdapterBids: AdapterBidNone,
+				PubID:       "acc-1",
+			},
+			expectedAdapterBidsCount: adapterBidsCount{NoBid: 1},
+		},
+		{
+			description: "got-bid",
+			labels: AdapterLabels{
+				Adapter:     openrtb_ext.BidderName(adapter),
+				AdapterBids: AdapterBidPresent,
+				PubID:       "acc-2",
+			},
+			expectedAdapterBidsCount: adapterBidsCount{GotBid: 1},
+		},
+		{
+			description: "adapter-errors",
+			labels: AdapterLabels{
+				Adapter: openrtb_ext.BidderName(adapter),
+				PubID:   "acc-1",
+				AdapterErrors: map[AdapterError]struct{}{
+					AdapterErrorBadInput:            {},
+					AdapterErrorBadServerResponse:   {},
+					AdapterErrorFailedToRequestBids: {},
+					AdapterErrorTimeout:             {},
+					AdapterErrorValidation:          {},
+					AdapterErrorTmaxTimeout:         {},
+					AdapterErrorUnknown:             {},
+				},
+			},
+			expectedErrorCount: errorCount{
+				badInput:           1,
+				badServer:          1,
+				timeout:            1,
+				failedToRequestBid: 1,
+				validation:         1,
+				tmaxTimeout:        1,
+				unknown:            1,
+			},
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.description, func(t *testing.T) {
+			registry := metrics.NewRegistry()
+			m := NewMetrics(registry, []openrtb_ext.BidderName{openrtb_ext.BidderName(adapter)}, config.DisabledMetrics{}, syncerKeys, moduleStageNames)
+			m.RecordAdapterRequest(test.labels)
+			adapterMetric := m.AdapterMetrics[lowerCaseAdapter]
+			if assert.NotNil(t, adapterMetric) {
+				assert.Equal(t, test.expectedAdapterBidsCount, adapterBidsCount{
+					NoBid:  adapterMetric.NoBidMeter.Count(),
+					GotBid: adapterMetric.GotBidsMeter.Count(),
+				})
+			}
+			assert.Equal(t, test.expectedNoCookieCount, adapterMetric.NoCookieMeter.Count())
+			adapterErrMetric := adapterMetric.ErrorMeters
+			if assert.NotNil(t, adapterErrMetric) {
+				assert.Equal(t, test.expectedErrorCount, errorCount{
+					badInput:           adapterErrMetric[AdapterErrorBadInput].Count(),
+					badServer:          adapterErrMetric[AdapterErrorBadServerResponse].Count(),
+					timeout:            adapterErrMetric[AdapterErrorTimeout].Count(),
+					failedToRequestBid: adapterErrMetric[AdapterErrorFailedToRequestBids].Count(),
+					validation:         adapterErrMetric[AdapterErrorValidation].Count(),
+					tmaxTimeout:        adapterErrMetric[AdapterErrorTmaxTimeout].Count(),
+					unknown:            adapterErrMetric[AdapterErrorUnknown].Count(),
+				})
+			}
+		})
+	}
+}
diff --git a/metrics/prometheus/prometheus_test.go b/metrics/prometheus/prometheus_test.go
index e57ae5e1..a2b0e84d 100644
--- a/metrics/prometheus/prometheus_test.go
+++ b/metrics/prometheus/prometheus_test.go
@@ -64,7 +64,7 @@ func TestMetricCountGatekeeping(t *testing.T) {
 	// Verify Per-Adapter Cardinality
 	// - This assertion provides a warning for newly added adapter metrics. Threre are 40+ adapters which makes the
 	//   cost of new per-adapter metrics rather expensive. Thought should be given when adding new per-adapter metrics.
-	assert.True(t, perAdapterCardinalityCount <= 29, "Per-Adapter Cardinality count equals %d \n", perAdapterCardinalityCount)
+	assert.True(t, perAdapterCardinalityCount <= 30, "Per-Adapter Cardinality count equals %d \n", perAdapterCardinalityCount)
 }
 
 func TestConnectionMetrics(t *testing.T) {
@@ -226,18 +226,19 @@ func TestBidValidationCreativeSizeMetric(t *testing.T) {
 			expectedAccountCount:               0,
 		},
 	}
-
+	adapterName := openrtb_ext.BidderName("AnyName")
+	lowerCasedAdapterName := "anyname"
 	for _, test := range testCases {
 		m := createMetricsForTesting()
 		m.metricsDisabled.AccountAdapterDetails = test.givenAccountAdapterMetricsDisabled
-		m.RecordBidValidationCreativeSizeError(adapterLabel, "acct-id")
-		m.RecordBidValidationCreativeSizeWarn(adapterLabel, "acct-id")
+		m.RecordBidValidationCreativeSizeError(adapterName, "acct-id")
+		m.RecordBidValidationCreativeSizeWarn(adapterName, "acct-id")
 
 		assertCounterVecValue(t, "", "account bid validation", m.accountBidResponseValidationSizeError, test.expectedAccountCount, prometheus.Labels{accountLabel: "acct-id", successLabel: successLabel})
-		assertCounterVecValue(t, "", "adapter bid validation", m.adapterBidResponseValidationSizeError, test.expectedAdapterCount, prometheus.Labels{adapterLabel: adapterLabel, successLabel: successLabel})
+		assertCounterVecValue(t, "", "adapter bid validation", m.adapterBidResponseValidationSizeError, test.expectedAdapterCount, prometheus.Labels{adapterLabel: lowerCasedAdapterName, successLabel: successLabel})
 
 		assertCounterVecValue(t, "", "account bid validation", m.accountBidResponseValidationSizeWarn, test.expectedAccountCount, prometheus.Labels{accountLabel: "acct-id", successLabel: successLabel})
-		assertCounterVecValue(t, "", "adapter bid validation", m.adapterBidResponseValidationSizeWarn, test.expectedAdapterCount, prometheus.Labels{adapterLabel: adapterLabel, successLabel: successLabel})
+		assertCounterVecValue(t, "", "adapter bid validation", m.adapterBidResponseValidationSizeWarn, test.expectedAdapterCount, prometheus.Labels{adapterLabel: lowerCasedAdapterName, successLabel: successLabel})
 	}
 }
 
@@ -263,17 +264,19 @@ func TestBidValidationSecureMarkupMetric(t *testing.T) {
 		},
 	}
 
+	adapterName := openrtb_ext.BidderName("AnyName")
+	lowerCasedAdapterName := "anyname"
 	for _, test := range testCases {
 		m := createMetricsForTesting()
 		m.metricsDisabled.AccountAdapterDetails = test.givenAccountAdapterMetricsDisabled
-		m.RecordBidValidationSecureMarkupError(adapterLabel, "acct-id")
-		m.RecordBidValidationSecureMarkupWarn(adapterLabel, "acct-id")
+		m.RecordBidValidationSecureMarkupError(adapterName, "acct-id")
+		m.RecordBidValidationSecureMarkupWarn(adapterName, "acct-id")
 
 		assertCounterVecValue(t, "", "Account Secure Markup Error", m.accountBidResponseSecureMarkupError, test.expectedAccountCount, prometheus.Labels{accountLabel: "acct-id", successLabel: successLabel})
-		assertCounterVecValue(t, "", "Adapter Secure Markup Error", m.adapterBidResponseSecureMarkupError, test.expectedAdapterCount, prometheus.Labels{adapterLabel: adapterLabel, successLabel: successLabel})
+		assertCounterVecValue(t, "", "Adapter Secure Markup Error", m.adapterBidResponseSecureMarkupError, test.expectedAdapterCount, prometheus.Labels{adapterLabel: lowerCasedAdapterName, successLabel: successLabel})
 
 		assertCounterVecValue(t, "", "Account Secure Markup Warn", m.accountBidResponseSecureMarkupWarn, test.expectedAccountCount, prometheus.Labels{accountLabel: "acct-id", successLabel: successLabel})
-		assertCounterVecValue(t, "", "Adapter Secure Markup Warn", m.adapterBidResponseSecureMarkupWarn, test.expectedAdapterCount, prometheus.Labels{adapterLabel: adapterLabel, successLabel: successLabel})
+		assertCounterVecValue(t, "", "Adapter Secure Markup Warn", m.adapterBidResponseSecureMarkupWarn, test.expectedAdapterCount, prometheus.Labels{adapterLabel: lowerCasedAdapterName, successLabel: successLabel})
 	}
 }
 
@@ -768,10 +771,11 @@ func TestRecordStoredDataError(t *testing.T) {
 }
 
 func TestAdapterBidReceivedMetric(t *testing.T) {
-	adapterName := "anyName"
+	adapterName := openrtb_ext.BidderName("anyName")
+	lowerCasedAdapterName := "anyname"
 	performTest := func(m *Metrics, hasAdm bool) {
 		labels := metrics.AdapterLabels{
-			Adapter: openrtb_ext.BidderName(adapterName),
+			Adapter: adapterName,
 		}
 		bidType := openrtb_ext.BidTypeBanner
 		m.RecordAdapterBidReceived(labels, bidType, hasAdm)
@@ -809,13 +813,13 @@ func TestAdapterBidReceivedMetric(t *testing.T) {
 		assertCounterVecValue(t, test.description, "adapterBids[adm]", m.adapterBids,
 			test.expectedAdmCount,
 			prometheus.Labels{
-				adapterLabel:        adapterName,
+				adapterLabel:        lowerCasedAdapterName,
 				markupDeliveryLabel: markupDeliveryAdm,
 			})
 		assertCounterVecValue(t, test.description, "adapterBids[nurl]", m.adapterBids,
 			test.expectedNurlCount,
 			prometheus.Labels{
-				adapterLabel:        adapterName,
+				adapterLabel:        lowerCasedAdapterName,
 				markupDeliveryLabel: markupDeliveryNurl,
 			})
 	}
@@ -824,6 +828,7 @@ func TestAdapterBidReceivedMetric(t *testing.T) {
 func TestRecordAdapterPriceMetric(t *testing.T) {
 	m := createMetricsForTesting()
 	adapterName := "anyName"
+	lowerCasedAdapterName := "anyname"
 	cpm := float64(42)
 
 	m.RecordAdapterPrice(metrics.AdapterLabels{
@@ -832,12 +837,13 @@ func TestRecordAdapterPriceMetric(t *testing.T) {
 
 	expectedCount := uint64(1)
 	expectedSum := cpm
-	result := getHistogramFromHistogramVec(m.adapterPrices, adapterLabel, adapterName)
+	result := getHistogramFromHistogramVec(m.adapterPrices, adapterLabel, lowerCasedAdapterName)
 	assertHistogram(t, "adapterPrices", result, expectedCount, expectedSum)
 }
 
 func TestAdapterRequestMetrics(t *testing.T) {
 	adapterName := "anyName"
+	lowerCasedAdapterName := "anyname"
 	performTest := func(m *Metrics, cookieFlag metrics.CookieFlag, adapterBids metrics.AdapterBid) {
 		labels := metrics.AdapterLabels{
 			Adapter:     openrtb_ext.BidderName(adapterName),
@@ -937,7 +943,7 @@ func TestAdapterRequestMetrics(t *testing.T) {
 		processMetrics(m.adapterRequests, func(m dto.Metric) {
 			isMetricForAdapter := false
 			for _, label := range m.GetLabel() {
-				if label.GetName() == adapterLabel && label.GetValue() == adapterName {
+				if label.GetName() == adapterLabel && label.GetValue() == lowerCasedAdapterName {
 					isMetricForAdapter = true
 				}
 			}
@@ -974,6 +980,7 @@ func TestAdapterRequestMetrics(t *testing.T) {
 
 func TestAdapterRequestErrorMetrics(t *testing.T) {
 	adapterName := "anyName"
+	lowerCasedAdapterName := "anyname"
 	performTest := func(m *Metrics, adapterErrors map[metrics.AdapterError]struct{}) {
 		labels := metrics.AdapterLabels{
 			Adapter:       openrtb_ext.BidderName(adapterName),
@@ -1030,7 +1037,7 @@ func TestAdapterRequestErrorMetrics(t *testing.T) {
 		processMetrics(m.adapterErrors, func(m dto.Metric) {
 			isMetricForAdapter := false
 			for _, label := range m.GetLabel() {
-				if label.GetName() == adapterLabel && label.GetValue() == adapterName {
+				if label.GetName() == adapterLabel && label.GetValue() == lowerCasedAdapterName {
 					isMetricForAdapter = true
 				}
 			}
@@ -1052,6 +1059,7 @@ func TestAdapterRequestErrorMetrics(t *testing.T) {
 
 func TestAdapterTimeMetric(t *testing.T) {
 	adapterName := "anyName"
+	lowerCasedAdapterName := "anyname"
 	performTest := func(m *Metrics, timeInMs float64, adapterErrors map[metrics.AdapterError]struct{}) {
 		m.RecordAdapterTime(metrics.AdapterLabels{
 			Adapter:       openrtb_ext.BidderName(adapterName),
@@ -1090,24 +1098,24 @@ func TestAdapterTimeMetric(t *testing.T) {
 
 		test.testCase(m)
 
-		result := getHistogramFromHistogramVec(m.adapterRequestsTimer, adapterLabel, adapterName)
+		result := getHistogramFromHistogramVec(m.adapterRequestsTimer, adapterLabel, lowerCasedAdapterName)
 		assertHistogram(t, test.description, result, test.expectedCount, test.expectedSum)
 	}
 }
 
 func TestAdapterPanicMetric(t *testing.T) {
 	m := createMetricsForTesting()
-	adapterName := "anyName"
-
+	adapterName := openrtb_ext.BidderName("anyName")
+	lowerCasedAdapterName := "anyname"
 	m.RecordAdapterPanic(metrics.AdapterLabels{
-		Adapter: openrtb_ext.BidderName(adapterName),
+		Adapter: adapterName,
 	})
 
 	expectedCount := float64(1)
 	assertCounterVecValue(t, "", "adapterPanics", m.adapterPanics,
 		expectedCount,
 		prometheus.Labels{
-			adapterLabel: adapterName,
+			adapterLabel: lowerCasedAdapterName,
 		})
 }
 
@@ -1509,6 +1517,8 @@ func TestRecordBidderServerResponseTime(t *testing.T) {
 }
 
 func TestRecordAdapterConnections(t *testing.T) {
+	adapterName := openrtb_ext.BidderName("Adapter")
+	lowerCasedAdapterName := "adapter"
 
 	type testIn struct {
 		adapterName   openrtb_ext.BidderName
@@ -1531,7 +1541,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 		{
 			description: "[1] Successful, new connection created, was idle, has connection wait",
 			in: testIn{
-				adapterName:   openrtb_ext.BidderAppnexus,
+				adapterName:   adapterName,
 				connWasReused: false,
 				connWait:      time.Second * 5,
 			},
@@ -1545,7 +1555,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 		{
 			description: "[2] Successful, new connection created, not idle, has connection wait",
 			in: testIn{
-				adapterName:   openrtb_ext.BidderAppnexus,
+				adapterName:   adapterName,
 				connWasReused: false,
 				connWait:      time.Second * 4,
 			},
@@ -1559,7 +1569,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 		{
 			description: "[3] Successful, was reused, was idle, no connection wait",
 			in: testIn{
-				adapterName:   openrtb_ext.BidderAppnexus,
+				adapterName:   adapterName,
 				connWasReused: true,
 			},
 			out: testOut{
@@ -1572,7 +1582,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 		{
 			description: "[4] Successful, was reused, not idle, has connection wait",
 			in: testIn{
-				adapterName:   openrtb_ext.BidderAppnexus,
+				adapterName:   adapterName,
 				connWasReused: true,
 				connWait:      time.Second * 5,
 			},
@@ -1602,7 +1612,7 @@ func TestRecordAdapterConnections(t *testing.T) {
 			"adapter_connection_reused",
 			m.adapterReusedConnections,
 			float64(test.out.expectedConnReusedCount),
-			prometheus.Labels{adapterLabel: string(test.in.adapterName)})
+			prometheus.Labels{adapterLabel: lowerCasedAdapterName})
 
 		// Assert number of new created connections
 		assertCounterVecValue(t,
@@ -1610,10 +1620,10 @@ func TestRecordAdapterConnections(t *testing.T) {
 			"adapter_connection_created",
 			m.adapterCreatedConnections,
 			float64(test.out.expectedConnCreatedCount),
-			prometheus.Labels{adapterLabel: string(test.in.adapterName)})
+			prometheus.Labels{adapterLabel: lowerCasedAdapterName})
 
 		// Assert connection wait time
-		histogram := getHistogramFromHistogramVec(m.adapterConnectionWaitTime, adapterLabel, string(test.in.adapterName))
+		histogram := getHistogramFromHistogramVec(m.adapterConnectionWaitTime, adapterLabel, lowerCasedAdapterName)
 		assert.Equal(t, test.out.expectedConnWaitCount, histogram.GetSampleCount(), assertDesciptions[2])
 		assert.Equal(t, test.out.expectedConnWaitTime, histogram.GetSampleSum(), assertDesciptions[3])
 	}
@@ -1781,8 +1791,9 @@ func assertHistogram(t *testing.T, name string, histogram dto.Histogram, expecte
 
 func TestRecordAdapterGDPRRequestBlocked(t *testing.T) {
 	m := createMetricsForTesting()
-
-	m.RecordAdapterGDPRRequestBlocked(openrtb_ext.BidderAppnexus)
+	adapterName := openrtb_ext.BidderName("AnyName")
+	lowerCasedAdapterName := "anyname"
+	m.RecordAdapterGDPRRequestBlocked(adapterName)
 
 	assertCounterVecValue(t,
 		"Increment adapter GDPR request blocked counter",
@@ -1790,7 +1801,7 @@ func TestRecordAdapterGDPRRequestBlocked(t *testing.T) {
 		m.adapterGDPRBlockedRequests,
 		1,
 		prometheus.Labels{
-			adapterLabel: string(openrtb_ext.BidderAppnexus),
+			adapterLabel: lowerCasedAdapterName,
 		})
 }
 
diff --git a/usersync/bidderfilter_test.go b/usersync/bidderfilter_test.go
index ddc75733..009c051b 100644
--- a/usersync/bidderfilter_test.go
+++ b/usersync/bidderfilter_test.go
@@ -1,6 +1,7 @@
 package usersync
 
 import (
+	"strings"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -69,6 +70,12 @@ func TestSpecificBidderFilter(t *testing.T) {
 			mode:        BidderFilterMode(-1),
 			expected:    false,
 		},
+		{
+			description: "Case Insensitive Include - One",
+			bidders:     []string{strings.ToUpper(bidder)},
+			mode:        BidderFilterModeInclude,
+			expected:    true,
+		},
 	}
 
 	for _, test := range testCases {
diff --git a/usersync/chooser_test.go b/usersync/chooser_test.go
index 4f38002c..6ab5a6b5 100644
--- a/usersync/chooser_test.go
+++ b/usersync/chooser_test.go
@@ -1,12 +1,13 @@
 package usersync
 
 import (
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 	"testing"
 	"time"
 
 	"github.com/prebid/prebid-server/macros"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/mock"
 )
 
 func TestNewChooser(t *testing.T) {
@@ -47,7 +48,10 @@ func TestChooserChoose(t *testing.T) {
 	fakeSyncerA := fakeSyncer{key: "keyA", supportsIFrame: true}
 	fakeSyncerB := fakeSyncer{key: "keyB", supportsIFrame: true}
 	fakeSyncerC := fakeSyncer{key: "keyC", supportsIFrame: false}
-	bidderSyncerLookup := map[string]Syncer{"a": fakeSyncerA, "b": fakeSyncerB, "c": fakeSyncerC}
+	bidderSyncerLookup := map[string]Syncer{"a": fakeSyncerA, "b": fakeSyncerB, "c": fakeSyncerC, "appnexus": fakeSyncerA}
+	normalizedBidderNamesLookup := func(name string) (openrtb_ext.BidderName, bool) {
+		return openrtb_ext.BidderName(name), true
+	}
 	syncerChoiceA := SyncerChoice{Bidder: "a", Syncer: fakeSyncerA}
 	syncerChoiceB := SyncerChoice{Bidder: "b", Syncer: fakeSyncerB}
 	syncTypeFilter := SyncTypeFilter{
@@ -61,16 +65,18 @@ func TestChooserChoose(t *testing.T) {
 		givenRequest       Request
 		givenChosenBidders []string
 		givenCookie        Cookie
+		bidderNamesLookup  func(name string) (openrtb_ext.BidderName, bool)
 		expected           Result
 	}{
 		{
 			description: "Cookie Opt Out",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   0,
 			},
 			givenChosenBidders: []string{"a"},
 			givenCookie:        Cookie{optOut: true},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusBlockedByUserOptOut,
 				BiddersEvaluated: nil,
@@ -80,11 +86,12 @@ func TestChooserChoose(t *testing.T) {
 		{
 			description: "GDPR Host Cookie Not Allowed",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: false, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: false, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   0,
 			},
 			givenChosenBidders: []string{"a"},
 			givenCookie:        Cookie{},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusBlockedByGDPR,
 				BiddersEvaluated: nil,
@@ -94,11 +101,12 @@ func TestChooserChoose(t *testing.T) {
 		{
 			description: "No Bidders",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   0,
 			},
 			givenChosenBidders: []string{},
 			givenCookie:        Cookie{},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusOK,
 				BiddersEvaluated: []BidderEvaluation{},
@@ -108,11 +116,12 @@ func TestChooserChoose(t *testing.T) {
 		{
 			description: "One Bidder - Sync",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   0,
 			},
 			givenChosenBidders: []string{"a"},
 			givenCookie:        Cookie{},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusOK,
 				BiddersEvaluated: []BidderEvaluation{{Bidder: "a", SyncerKey: "keyA", Status: StatusOK}},
@@ -122,11 +131,12 @@ func TestChooserChoose(t *testing.T) {
 		{
 			description: "One Bidder - No Sync",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   0,
 			},
 			givenChosenBidders: []string{"c"},
 			givenCookie:        Cookie{},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusOK,
 				BiddersEvaluated: []BidderEvaluation{{Bidder: "c", SyncerKey: "keyC", Status: StatusTypeNotSupported}},
@@ -136,11 +146,12 @@ func TestChooserChoose(t *testing.T) {
 		{
 			description: "Many Bidders - All Sync - Limit Disabled With 0",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   0,
 			},
 			givenChosenBidders: []string{"a", "b"},
 			givenCookie:        Cookie{},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusOK,
 				BiddersEvaluated: []BidderEvaluation{{Bidder: "a", SyncerKey: "keyA", Status: StatusOK}, {Bidder: "b", SyncerKey: "keyB", Status: StatusOK}},
@@ -150,11 +161,12 @@ func TestChooserChoose(t *testing.T) {
 		{
 			description: "Many Bidders - All Sync - Limit Disabled With Negative Value",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   -1,
 			},
 			givenChosenBidders: []string{"a", "b"},
 			givenCookie:        Cookie{},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusOK,
 				BiddersEvaluated: []BidderEvaluation{{Bidder: "a", SyncerKey: "keyA", Status: StatusOK}, {Bidder: "b", SyncerKey: "keyB", Status: StatusOK}},
@@ -164,11 +176,12 @@ func TestChooserChoose(t *testing.T) {
 		{
 			description: "Many Bidders - Limited Sync",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   1,
 			},
 			givenChosenBidders: []string{"a", "b"},
 			givenCookie:        Cookie{},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusOK,
 				BiddersEvaluated: []BidderEvaluation{{Bidder: "a", SyncerKey: "keyA", Status: StatusOK}},
@@ -178,11 +191,12 @@ func TestChooserChoose(t *testing.T) {
 		{
 			description: "Many Bidders - Limited Sync - Disqualified Syncers Don't Count Towards Limit",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   1,
 			},
 			givenChosenBidders: []string{"c", "a", "b"},
 			givenCookie:        Cookie{},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusOK,
 				BiddersEvaluated: []BidderEvaluation{{Bidder: "c", SyncerKey: "keyC", Status: StatusTypeNotSupported}, {Bidder: "a", SyncerKey: "keyA", Status: StatusOK}},
@@ -192,17 +206,65 @@ func TestChooserChoose(t *testing.T) {
 		{
 			description: "Many Bidders - Some Sync, Some Don't",
 			givenRequest: Request{
-				Privacy: fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
 				Limit:   0,
 			},
 			givenChosenBidders: []string{"a", "c"},
 			givenCookie:        Cookie{},
+			bidderNamesLookup:  normalizedBidderNamesLookup,
 			expected: Result{
 				Status:           StatusOK,
 				BiddersEvaluated: []BidderEvaluation{{Bidder: "a", SyncerKey: "keyA", Status: StatusOK}, {Bidder: "c", SyncerKey: "keyC", Status: StatusTypeNotSupported}},
 				SyncersChosen:    []SyncerChoice{syncerChoiceA},
 			},
 		},
+		{
+			description: "Unknown Bidder",
+			givenRequest: Request{
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Limit:   0,
+			},
+			givenChosenBidders: []string{"a"},
+			givenCookie:        Cookie{},
+			bidderNamesLookup: func(name string) (openrtb_ext.BidderName, bool) {
+				return openrtb_ext.BidderName(name), false
+			},
+			expected: Result{
+				Status:           StatusOK,
+				BiddersEvaluated: []BidderEvaluation{{Bidder: "a", Status: StatusUnknownBidder}},
+				SyncersChosen:    []SyncerChoice{},
+			},
+		},
+		{
+			description: "Case insensitive bidder name",
+			givenRequest: Request{
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Limit:   0,
+			},
+			givenChosenBidders: []string{"AppNexus"},
+			givenCookie:        Cookie{},
+			bidderNamesLookup:  openrtb_ext.NormalizeBidderName,
+			expected: Result{
+				Status:           StatusOK,
+				BiddersEvaluated: []BidderEvaluation{{Bidder: "AppNexus", SyncerKey: "keyA", Status: StatusOK}},
+				SyncersChosen:    []SyncerChoice{{Bidder: "AppNexus", Syncer: fakeSyncerA}},
+			},
+		},
+		{
+			description: "Duplicate bidder name",
+			givenRequest: Request{
+				Privacy: &fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+				Limit:   0,
+			},
+			givenChosenBidders: []string{"AppNexus", "appNexus"},
+			givenCookie:        Cookie{},
+			bidderNamesLookup:  openrtb_ext.NormalizeBidderName,
+			expected: Result{
+				Status:           StatusOK,
+				BiddersEvaluated: []BidderEvaluation{{Bidder: "AppNexus", SyncerKey: "keyA", Status: StatusOK}, {Bidder: "appNexus", SyncerKey: "keyA", Status: StatusDuplicate}},
+				SyncersChosen:    []SyncerChoice{{Bidder: "AppNexus", Syncer: fakeSyncerA}},
+			},
+		},
 	}
 
 	bidders := []string{"anyRequested"}
@@ -219,9 +281,10 @@ func TestChooserChoose(t *testing.T) {
 			Return(test.givenChosenBidders)
 
 		chooser := standardChooser{
-			bidderSyncerLookup: bidderSyncerLookup,
-			biddersAvailable:   biddersAvailable,
-			bidderChooser:      mockBidderChooser,
+			bidderSyncerLookup:       bidderSyncerLookup,
+			biddersAvailable:         biddersAvailable,
+			bidderChooser:            mockBidderChooser,
+			normalizeValidBidderName: test.bidderNamesLookup,
 		}
 
 		result := chooser.Choose(test.givenRequest, &test.givenCookie)
@@ -232,113 +295,199 @@ func TestChooserChoose(t *testing.T) {
 func TestChooserEvaluate(t *testing.T) {
 	fakeSyncerA := fakeSyncer{key: "keyA", supportsIFrame: true}
 	fakeSyncerB := fakeSyncer{key: "keyB", supportsIFrame: false}
-	bidderSyncerLookup := map[string]Syncer{"a": fakeSyncerA, "b": fakeSyncerB}
+	bidderSyncerLookup := map[string]Syncer{"a": fakeSyncerA, "b": fakeSyncerB, "appnexus": fakeSyncerA, "suntContent": fakeSyncerA}
 	syncTypeFilter := SyncTypeFilter{
 		IFrame:   NewUniformBidderFilter(BidderFilterModeInclude),
 		Redirect: NewUniformBidderFilter(BidderFilterModeExclude)}
-
+	normalizedBidderNamesLookup := func(name string) (openrtb_ext.BidderName, bool) {
+		return openrtb_ext.BidderName(name), true
+	}
 	cookieNeedsSync := Cookie{}
 	cookieAlreadyHasSyncForA := Cookie{uids: map[string]UIDEntry{"keyA": {Expires: time.Now().Add(time.Duration(24) * time.Hour)}}}
 	cookieAlreadyHasSyncForB := Cookie{uids: map[string]UIDEntry{"keyB": {Expires: time.Now().Add(time.Duration(24) * time.Hour)}}}
 
 	testCases := []struct {
-		description        string
-		givenBidder        string
-		givenSyncersSeen   map[string]struct{}
-		givenPrivacy       Privacy
-		givenCookie        Cookie
-		expectedSyncer     Syncer
-		expectedEvaluation BidderEvaluation
+		description                 string
+		givenBidder                 string
+		normalisedBidderName        string
+		givenSyncersSeen            map[string]struct{}
+		givenPrivacy                fakePrivacy
+		givenCookie                 Cookie
+		givenSyncTypeFilter         SyncTypeFilter
+		normalizedBidderNamesLookup func(name string) (openrtb_ext.BidderName, bool)
+		expectedSyncer              Syncer
+		expectedEvaluation          BidderEvaluation
 	}{
 		{
-			description:        "Valid",
-			givenBidder:        "a",
-			givenSyncersSeen:   map[string]struct{}{},
-			givenPrivacy:       fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
-			givenCookie:        cookieNeedsSync,
-			expectedSyncer:     fakeSyncerA,
-			expectedEvaluation: BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusOK},
+			description:                 "Valid",
+			givenBidder:                 "a",
+			normalisedBidderName:        "a",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: normalizedBidderNamesLookup,
+			expectedSyncer:              fakeSyncerA,
+			expectedEvaluation:          BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusOK},
+		},
+		{
+			description:                 "Unknown Bidder",
+			givenBidder:                 "unknown",
+			normalisedBidderName:        "",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: normalizedBidderNamesLookup,
+			expectedSyncer:              nil,
+			expectedEvaluation:          BidderEvaluation{Bidder: "unknown", Status: StatusUnknownBidder},
+		},
+		{
+			description:                 "Duplicate Syncer",
+			givenBidder:                 "a",
+			normalisedBidderName:        "",
+			givenSyncersSeen:            map[string]struct{}{"keyA": {}},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: normalizedBidderNamesLookup,
+			expectedSyncer:              nil,
+			expectedEvaluation:          BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusDuplicate},
+		},
+		{
+			description:                 "Incompatible Kind",
+			givenBidder:                 "b",
+			normalisedBidderName:        "",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: normalizedBidderNamesLookup,
+			expectedSyncer:              nil,
+			expectedEvaluation:          BidderEvaluation{Bidder: "b", SyncerKey: "keyB", Status: StatusTypeNotSupported},
+		},
+		{
+			description:                 "Already Synced",
+			givenBidder:                 "a",
+			normalisedBidderName:        "",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:                 cookieAlreadyHasSyncForA,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: normalizedBidderNamesLookup,
+			expectedSyncer:              nil,
+			expectedEvaluation:          BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusAlreadySynced},
 		},
 		{
-			description:        "Unknown Bidder",
-			givenBidder:        "unknown",
-			givenSyncersSeen:   map[string]struct{}{},
-			givenPrivacy:       fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
-			givenCookie:        cookieNeedsSync,
-			expectedSyncer:     nil,
-			expectedEvaluation: BidderEvaluation{Bidder: "unknown", Status: StatusUnknownBidder},
+			description:                 "Different Bidder Already Synced",
+			givenBidder:                 "a",
+			normalisedBidderName:        "a",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:                 cookieAlreadyHasSyncForB,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: normalizedBidderNamesLookup,
+			expectedSyncer:              fakeSyncerA,
+			expectedEvaluation:          BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusOK},
 		},
 		{
-			description:        "Duplicate Syncer",
-			givenBidder:        "a",
-			givenSyncersSeen:   map[string]struct{}{"keyA": {}},
-			givenPrivacy:       fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
-			givenCookie:        cookieNeedsSync,
-			expectedSyncer:     nil,
-			expectedEvaluation: BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusDuplicate},
+			description:                 "Blocked By GDPR",
+			givenBidder:                 "a",
+			normalisedBidderName:        "a",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: false, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: normalizedBidderNamesLookup,
+			expectedSyncer:              nil,
+			expectedEvaluation:          BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusBlockedByGDPR},
 		},
 		{
-			description:        "Incompatible Kind",
-			givenBidder:        "b",
-			givenSyncersSeen:   map[string]struct{}{},
-			givenPrivacy:       fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
-			givenCookie:        cookieNeedsSync,
-			expectedSyncer:     nil,
-			expectedEvaluation: BidderEvaluation{Bidder: "b", SyncerKey: "keyB", Status: StatusTypeNotSupported},
+			description:                 "Blocked By CCPA",
+			givenBidder:                 "a",
+			normalisedBidderName:        "a",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: false, activityAllowUserSync: true},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: normalizedBidderNamesLookup,
+			expectedSyncer:              nil,
+			expectedEvaluation:          BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusBlockedByCCPA},
 		},
 		{
-			description:        "Already Synced",
-			givenBidder:        "a",
-			givenSyncersSeen:   map[string]struct{}{},
-			givenPrivacy:       fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
-			givenCookie:        cookieAlreadyHasSyncForA,
-			expectedSyncer:     nil,
-			expectedEvaluation: BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusAlreadySynced},
+			description:                 "Blocked By activity control",
+			givenBidder:                 "a",
+			normalisedBidderName:        "",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: false},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: normalizedBidderNamesLookup,
+			expectedSyncer:              nil,
+			expectedEvaluation:          BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusBlockedByPrivacy},
 		},
 		{
-			description:        "Different Bidder Already Synced",
-			givenBidder:        "a",
-			givenSyncersSeen:   map[string]struct{}{},
-			givenPrivacy:       fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
-			givenCookie:        cookieAlreadyHasSyncForB,
-			expectedSyncer:     fakeSyncerA,
-			expectedEvaluation: BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusOK},
+			description:                 "Case insensitive bidder name",
+			givenBidder:                 "AppNexus",
+			normalisedBidderName:        "appnexus",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: openrtb_ext.NormalizeBidderName,
+			expectedSyncer:              fakeSyncerA,
+			expectedEvaluation:          BidderEvaluation{Bidder: "AppNexus", SyncerKey: "keyA", Status: StatusOK},
 		},
 		{
-			description:        "Blocked By GDPR",
-			givenBidder:        "a",
-			givenSyncersSeen:   map[string]struct{}{},
-			givenPrivacy:       fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: false, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
-			givenCookie:        cookieNeedsSync,
-			expectedSyncer:     nil,
-			expectedEvaluation: BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusBlockedByGDPR},
+			description:          "Case insensitivity check for sync type filter",
+			givenBidder:          "SuntContent",
+			normalisedBidderName: "suntContent",
+			givenSyncersSeen:     map[string]struct{}{},
+			givenPrivacy:         fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:          cookieNeedsSync,
+			givenSyncTypeFilter: SyncTypeFilter{
+				IFrame:   NewSpecificBidderFilter([]string{"SuntContent"}, BidderFilterModeInclude),
+				Redirect: NewSpecificBidderFilter([]string{"SuntContent"}, BidderFilterModeExclude)},
+			normalizedBidderNamesLookup: openrtb_ext.NormalizeBidderName,
+			expectedSyncer:              fakeSyncerA,
+			expectedEvaluation:          BidderEvaluation{Bidder: "SuntContent", SyncerKey: "keyA", Status: StatusOK},
 		},
 		{
-			description:        "Blocked By CCPA",
-			givenBidder:        "a",
-			givenSyncersSeen:   map[string]struct{}{},
-			givenPrivacy:       fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: false, activityAllowUserSync: true},
-			givenCookie:        cookieNeedsSync,
-			expectedSyncer:     nil,
-			expectedEvaluation: BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusBlockedByCCPA},
+			description:                 "Case Insensitivity Check For Blocked By GDPR",
+			givenBidder:                 "AppNexus",
+			normalisedBidderName:        "appnexus",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: false, ccpaAllowsBidderSync: true, activityAllowUserSync: true},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: openrtb_ext.NormalizeBidderName,
+			expectedSyncer:              nil,
+			expectedEvaluation:          BidderEvaluation{Bidder: "AppNexus", SyncerKey: "keyA", Status: StatusBlockedByGDPR},
 		},
 		{
-			description:        "Blocked By activity control",
-			givenBidder:        "a",
-			givenSyncersSeen:   map[string]struct{}{},
-			givenPrivacy:       fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: true, activityAllowUserSync: false},
-			givenCookie:        cookieNeedsSync,
-			expectedSyncer:     nil,
-			expectedEvaluation: BidderEvaluation{Bidder: "a", SyncerKey: "keyA", Status: StatusBlockedByPrivacy},
+			description:                 "Case Insensitivity Check For Blocked By CCPA",
+			givenBidder:                 "AppNexus",
+			normalisedBidderName:        "appnexus",
+			givenSyncersSeen:            map[string]struct{}{},
+			givenPrivacy:                fakePrivacy{gdprAllowsHostCookie: true, gdprAllowsBidderSync: true, ccpaAllowsBidderSync: false, activityAllowUserSync: true},
+			givenCookie:                 cookieNeedsSync,
+			givenSyncTypeFilter:         syncTypeFilter,
+			normalizedBidderNamesLookup: openrtb_ext.NormalizeBidderName,
+			expectedSyncer:              nil,
+			expectedEvaluation:          BidderEvaluation{Bidder: "AppNexus", SyncerKey: "keyA", Status: StatusBlockedByCCPA},
 		},
 	}
 
 	for _, test := range testCases {
-		chooser, _ := NewChooser(bidderSyncerLookup).(standardChooser)
-		sync, evaluation := chooser.evaluate(test.givenBidder, test.givenSyncersSeen, syncTypeFilter, test.givenPrivacy, &test.givenCookie)
+		t.Run(test.description, func(t *testing.T) {
+			chooser, _ := NewChooser(bidderSyncerLookup).(standardChooser)
+			chooser.normalizeValidBidderName = test.normalizedBidderNamesLookup
+			sync, evaluation := chooser.evaluate(test.givenBidder, test.givenSyncersSeen, test.givenSyncTypeFilter, &test.givenPrivacy, &test.givenCookie)
 
-		assert.Equal(t, test.expectedSyncer, sync, test.description+":syncer")
-		assert.Equal(t, test.expectedEvaluation, evaluation, test.description+":evaluation")
+			assert.Equal(t, test.normalisedBidderName, test.givenPrivacy.inputBidderName)
+			assert.Equal(t, test.expectedSyncer, sync, test.description+":syncer")
+			assert.Equal(t, test.expectedEvaluation, evaluation, test.description+":evaluation")
+		})
 	}
 }
 
@@ -386,20 +535,23 @@ type fakePrivacy struct {
 	gdprAllowsBidderSync  bool
 	ccpaAllowsBidderSync  bool
 	activityAllowUserSync bool
+	inputBidderName       string
 }
 
-func (p fakePrivacy) GDPRAllowsHostCookie() bool {
+func (p *fakePrivacy) GDPRAllowsHostCookie() bool {
 	return p.gdprAllowsHostCookie
 }
 
-func (p fakePrivacy) GDPRAllowsBidderSync(bidder string) bool {
+func (p *fakePrivacy) GDPRAllowsBidderSync(bidder string) bool {
+	p.inputBidderName = bidder
 	return p.gdprAllowsBidderSync
 }
 
-func (p fakePrivacy) CCPAAllowsBidderSync(bidder string) bool {
+func (p *fakePrivacy) CCPAAllowsBidderSync(bidder string) bool {
+	p.inputBidderName = bidder
 	return p.ccpaAllowsBidderSync
 }
 
-func (p fakePrivacy) ActivityAllowsUserSync(bidder string) bool {
+func (p *fakePrivacy) ActivityAllowsUserSync(bidder string) bool {
 	return p.activityAllowUserSync
 }