Repository: prebid/prebid-server
Pull request #1306 (2020-05-18 14:49:24)

eplanning: Support for apps


Patch:
diff --git a/adapters/advangelists/usersync.go b/adapters/advangelists/usersync.go
index 6167a2e3..10c46d18 100644
--- a/adapters/advangelists/usersync.go
+++ b/adapters/advangelists/usersync.go
@@ -8,5 +8,5 @@ import (
 )
 
 func NewAdvangelistsSyncer(temp *template.Template) usersync.Usersyncer {
-	return adapters.NewSyncer("advangelists", 61, temp, adapters.SyncTypeIframe)
+	return adapters.NewSyncer("advangelists", 0, temp, adapters.SyncTypeIframe)
 }
diff --git a/adapters/consumable/consumable.go b/adapters/consumable/consumable.go
index d3954104..1fa23377 100644
--- a/adapters/consumable/consumable.go
+++ b/adapters/consumable/consumable.go
@@ -7,6 +7,7 @@ import (
 	"github.com/prebid/prebid-server/adapters"
 	"github.com/prebid/prebid-server/errortypes"
 	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/prebid/prebid-server/privacy/ccpa"
 	"net/http"
 	"net/url"
 	"strconv"
@@ -32,6 +33,8 @@ type bidRequest struct {
 	Url                string      `json:"url,omitempty"`
 	EnableBotFiltering bool        `json:"enableBotFiltering,omitempty"`
 	Parallel           bool        `json:"parallel"`
+	CCPA               string      `json:"ccpa,omitempty"`
+	GDPR               *bidGdpr    `json:"gdpr,omitempty"`
 }
 
 type placement struct {
@@ -47,6 +50,11 @@ type user struct {
 	Key string `json:"key,omitempty"`
 }
 
+type bidGdpr struct {
+	Applies *bool  `json:"applies,omitempty"`
+	Consent string `json:"consent,omitempty"`
+}
+
 type bidResponse struct {
 	Decisions map[string]decision `json:"decisions"` // map by bidId
 }
@@ -124,6 +132,34 @@ func (a *ConsumableAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *a
 		body.Url = request.Site.Page     // where the impression will be made
 	}
 
+	gdpr := bidGdpr{}
+
+	ccpaPolicy, err := ccpa.ReadPolicy(request)
+	if err == nil {
+		body.CCPA = ccpaPolicy.Value
+	}
+
+	// TODO: Replace with gdpr.ReadPolicy when it is available
+	if request.Regs != nil && request.Regs.Ext != nil {
+		var extRegs openrtb_ext.ExtRegs
+		if err := json.Unmarshal(request.Regs.Ext, &extRegs); err == nil {
+			if extRegs.GDPR != nil {
+				applies := *extRegs.GDPR != 0
+				gdpr.Applies = &applies
+				body.GDPR = &gdpr
+			}
+		}
+	}
+
+	// TODO: Replace with gdpr.ReadPolicy when it is available
+	if request.User != nil && request.User.Ext != nil {
+		var extUser openrtb_ext.ExtUser
+		if err := json.Unmarshal(request.User.Ext, &extUser); err == nil {
+			gdpr.Consent = extUser.Consent
+			body.GDPR = &gdpr
+		}
+	}
+
 	for i, impression := range request.Imp {
 
 		_, consumableExt, err := extractExtensions(impression)
diff --git a/adapters/consumable/consumable/supplemental/simple-banner-gdpr-2.json b/adapters/consumable/consumable/supplemental/simple-banner-gdpr-2.json
new file mode 100644
index 00000000..32c3fd6e
--- /dev/null
+++ b/adapters/consumable/consumable/supplemental/simple-banner-gdpr-2.json
@@ -0,0 +1,127 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 250}]
+        },
+        "ext": {
+          "bidder": {
+            "networkId": 11,
+            "siteId": 32,
+            "unitId": 42
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36",
+      "ip": "123.123.123.123"
+    },
+    "site": {
+      "domain": "www.some.com",
+      "page": "http://www.some.com/page-where-ad-will-be-shown"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://e.serverbid.com/api/v2",
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ],
+          "Forwarded": [
+            "for=123.123.123.123"
+          ],
+          "Origin": [
+            "http://www.some.com"
+          ],
+          "Referer": [
+            "http://www.some.com/page-where-ad-will-be-shown"
+          ]
+        },
+        "body": {
+          "placements": [
+            {
+              "adTypes": [2730],
+              "divName": "test-imp-id",
+              "networkId": 11,
+              "siteId": 32,
+              "unitId": 42
+            }
+          ],
+          "networkId": 11,
+          "siteId": 32,
+          "unitId": 42,
+          "time": 1451651415,
+          "url": "http://www.some.com/page-where-ad-will-be-shown",
+          "includePricingData": true,
+          "user":{},
+          "enableBotFiltering": true,
+          "parallel": true,
+          "gdpr": {
+            "applies": false
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "decisions": {
+            "test-imp-id": {
+              "adId": 1234567890,
+              "pricing": {
+                "clearPrice": 0.5
+              },
+              "width": 728,
+              "height": 250,
+              "impressionUrl": "http://localhost:8080/shown",
+              "contents" : [
+                {
+                  "body": "<blink>Remember this: https://www.google.com/search?q=blink+tag ?</blink>"
+                }
+              ]
+            }
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-request-id",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "<blink>Remember this: https://www.google.com/search?q=blink+tag ?</blink>",
+            "crid": "1234567890",
+            "exp": 30,
+            "w": 728,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/consumable/consumable/supplemental/simple-banner-gdpr-3.json b/adapters/consumable/consumable/supplemental/simple-banner-gdpr-3.json
new file mode 100644
index 00000000..afbb7e2b
--- /dev/null
+++ b/adapters/consumable/consumable/supplemental/simple-banner-gdpr-3.json
@@ -0,0 +1,127 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 250}]
+        },
+        "ext": {
+          "bidder": {
+            "networkId": 11,
+            "siteId": 32,
+            "unitId": 42
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36",
+      "ip": "123.123.123.123"
+    },
+    "site": {
+      "domain": "www.some.com",
+      "page": "http://www.some.com/page-where-ad-will-be-shown"
+    },
+    "user": {
+      "ext": {
+        "consent": "abcdefghijklm"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://e.serverbid.com/api/v2",
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ],
+          "Forwarded": [
+            "for=123.123.123.123"
+          ],
+          "Origin": [
+            "http://www.some.com"
+          ],
+          "Referer": [
+            "http://www.some.com/page-where-ad-will-be-shown"
+          ]
+        },
+        "body": {
+          "placements": [
+            {
+              "adTypes": [2730],
+              "divName": "test-imp-id",
+              "networkId": 11,
+              "siteId": 32,
+              "unitId": 42
+            }
+          ],
+          "networkId": 11,
+          "siteId": 32,
+          "unitId": 42,
+          "time": 1451651415,
+          "url": "http://www.some.com/page-where-ad-will-be-shown",
+          "includePricingData": true,
+          "user":{},
+          "enableBotFiltering": true,
+          "parallel": true,
+          "gdpr": {
+            "consent": "abcdefghijklm"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "decisions": {
+            "test-imp-id": {
+              "adId": 1234567890,
+              "pricing": {
+                "clearPrice": 0.5
+              },
+              "width": 728,
+              "height": 250,
+              "impressionUrl": "http://localhost:8080/shown",
+              "contents" : [
+                {
+                  "body": "<blink>Remember this: https://www.google.com/search?q=blink+tag ?</blink>"
+                }
+              ]
+            }
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-request-id",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "<blink>Remember this: https://www.google.com/search?q=blink+tag ?</blink>",
+            "crid": "1234567890",
+            "exp": 30,
+            "w": 728,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/consumable/consumable/supplemental/simple-banner-gdpr.json b/adapters/consumable/consumable/supplemental/simple-banner-gdpr.json
new file mode 100644
index 00000000..1d422e25
--- /dev/null
+++ b/adapters/consumable/consumable/supplemental/simple-banner-gdpr.json
@@ -0,0 +1,133 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 250}]
+        },
+        "ext": {
+          "bidder": {
+            "networkId": 11,
+            "siteId": 32,
+            "unitId": 42
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36",
+      "ip": "123.123.123.123"
+    },
+    "site": {
+      "domain": "www.some.com",
+      "page": "http://www.some.com/page-where-ad-will-be-shown"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 1
+      }
+    },
+    "user": {
+      "ext": {
+        "consent": "abcdefghijklm"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://e.serverbid.com/api/v2",
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ],
+          "Forwarded": [
+            "for=123.123.123.123"
+          ],
+          "Origin": [
+            "http://www.some.com"
+          ],
+          "Referer": [
+            "http://www.some.com/page-where-ad-will-be-shown"
+          ]
+        },
+        "body": {
+          "placements": [
+            {
+              "adTypes": [2730],
+              "divName": "test-imp-id",
+              "networkId": 11,
+              "siteId": 32,
+              "unitId": 42
+            }
+          ],
+          "networkId": 11,
+          "siteId": 32,
+          "unitId": 42,
+          "time": 1451651415,
+          "url": "http://www.some.com/page-where-ad-will-be-shown",
+          "includePricingData": true,
+          "user":{},
+          "enableBotFiltering": true,
+          "parallel": true,
+          "gdpr": {
+            "applies": true,
+            "consent": "abcdefghijklm"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "decisions": {
+            "test-imp-id": {
+              "adId": 1234567890,
+              "pricing": {
+                "clearPrice": 0.5
+              },
+              "width": 728,
+              "height": 250,
+              "impressionUrl": "http://localhost:8080/shown",
+              "contents" : [
+                {
+                  "body": "<blink>Remember this: https://www.google.com/search?q=blink+tag ?</blink>"
+                }
+              ]
+            }
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-request-id",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "<blink>Remember this: https://www.google.com/search?q=blink+tag ?</blink>",
+            "crid": "1234567890",
+            "exp": 30,
+            "w": 728,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/consumable/consumable/supplemental/simple-banner-us-privacy.json b/adapters/consumable/consumable/supplemental/simple-banner-us-privacy.json
new file mode 100644
index 00000000..6313606e
--- /dev/null
+++ b/adapters/consumable/consumable/supplemental/simple-banner-us-privacy.json
@@ -0,0 +1,125 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 250}]
+        },
+        "ext": {
+          "bidder": {
+            "networkId": 11,
+            "siteId": 32,
+            "unitId": 42
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36",
+      "ip": "123.123.123.123"
+    },
+    "site": {
+      "domain": "www.some.com",
+      "page": "http://www.some.com/page-where-ad-will-be-shown"
+    },
+    "regs": {
+      "ext": {
+        "us_privacy": "1NYN"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://e.serverbid.com/api/v2",
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ],
+          "Forwarded": [
+            "for=123.123.123.123"
+          ],
+          "Origin": [
+            "http://www.some.com"
+          ],
+          "Referer": [
+            "http://www.some.com/page-where-ad-will-be-shown"
+          ]
+        },
+        "body": {
+          "placements": [
+            {
+              "adTypes": [2730],
+              "divName": "test-imp-id",
+              "networkId": 11,
+              "siteId": 32,
+              "unitId": 42
+            }
+          ],
+          "networkId": 11,
+          "siteId": 32,
+          "unitId": 42,
+          "time": 1451651415,
+          "url": "http://www.some.com/page-where-ad-will-be-shown",
+          "includePricingData": true,
+          "user":{},
+          "enableBotFiltering": true,
+          "parallel": true,
+          "ccpa": "1NYN"
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "decisions": {
+            "test-imp-id": {
+              "adId": 1234567890,
+              "pricing": {
+                "clearPrice": 0.5
+              },
+              "width": 728,
+              "height": 250,
+              "impressionUrl": "http://localhost:8080/shown",
+              "contents" : [
+                {
+                  "body": "<blink>Remember this: https://www.google.com/search?q=blink+tag ?</blink>"
+                }
+              ]
+            }
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-request-id",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "<blink>Remember this: https://www.google.com/search?q=blink+tag ?</blink>",
+            "crid": "1234567890",
+            "exp": 30,
+            "w": 728,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/consumable/usersync.go b/adapters/consumable/usersync.go
index 68a93c80..0e0938c7 100644
--- a/adapters/consumable/usersync.go
+++ b/adapters/consumable/usersync.go
@@ -7,7 +7,7 @@ import (
 	"github.com/prebid/prebid-server/usersync"
 )
 
-var VENDOR_ID uint16 = 65535 // TODO: Insert consumable value when one is assigned
+var VENDOR_ID uint16 = 591
 
 func NewConsumableSyncer(temp *template.Template) usersync.Usersyncer {
 
diff --git a/adapters/eplanning/eplanning.go b/adapters/eplanning/eplanning.go
index 49acd30e..5fb9ccf2 100644
--- a/adapters/eplanning/eplanning.go
+++ b/adapters/eplanning/eplanning.go
@@ -23,6 +23,7 @@ const nullSize = "1x1"
 const defaultPageURL = "FILE"
 const sec = "ROS"
 const dfpClientID = "1"
+const requestTargetInventory = "1"
 
 var cleanNameSteps = []cleanNameStep{
 	{regexp.MustCompile(`_|\.|-|\/`), ""},
@@ -117,24 +118,61 @@ func (adapter *EPlanningAdapter) MakeRequests(request *openrtb.BidRequest, reqIn
 		pageDomain = defaultPageURL
 	}
 
-	uri := adapter.URI + fmt.Sprintf("/%s/%s/%s/%s?r=pbs&ncb=1&ur=%s&e=%s", clientID, dfpClientID, pageDomain, sec, url.QueryEscape(pageURL), strings.Join(spacesStrings, "+"))
+	var requestTarget string
+	if request.App != nil && request.App.Bundle != "" {
+		requestTarget = request.App.Bundle
+	} else {
+		requestTarget = pageDomain
+	}
+
+	uriObj, err := url.Parse(adapter.URI)
+	if err != nil {
+		errors = append(errors, err)
+		return nil, errors
+	}
+
+	uriObj.Path = uriObj.Path + fmt.Sprintf("/%s/%s/%s/%s", clientID, dfpClientID, requestTarget, sec)
+	query := url.Values{}
+	query.Set("r", "pbs")
+	query.Set("ncb", "1")
+	if request.App == nil {
+		query.Set("ur", pageURL)
+	}
+	query.Set("e", strings.Join(spacesStrings, "+"))
 
 	if request.User != nil && request.User.BuyerUID != "" {
-		uri = uri + fmt.Sprintf("&uid=%s", request.User.BuyerUID)
+		query.Set("uid", request.User.BuyerUID)
 	}
 
 	if ip != "" {
-		uri = uri + fmt.Sprintf("&ip=%s", ip)
+		query.Set("ip", ip)
 	}
 
 	var body []byte
 	if adapter.testing {
 		body = []byte("{}")
 	} else {
-		uri = uri + fmt.Sprintf("&rnd=%d", rand.Int())
+		t := strconv.Itoa(rand.Int())
+		query.Set("rnd", t)
 		body = nil
 	}
 
+	if request.App != nil {
+		if request.App.Name != "" {
+			query.Set("appn", request.App.Name)
+		}
+		if request.App.ID != "" {
+			query.Set("appid", request.App.ID)
+		}
+		if request.Device != nil && request.Device.IFA != "" {
+			query.Set("ifa", request.Device.IFA)
+		}
+		query.Set("app", requestTargetInventory)
+	}
+
+	uriObj.RawQuery = query.Encode()
+	uri := uriObj.String()
+
 	requestData := adapters.RequestData{
 		Method:  "GET",
 		Uri:     uri,
diff --git a/adapters/mobilefuse/mobilefuse.go b/adapters/mobilefuse/mobilefuse.go
new file mode 100644
index 00000000..3351f10d
--- /dev/null
+++ b/adapters/mobilefuse/mobilefuse.go
@@ -0,0 +1,193 @@
+package mobilefuse
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/golang/glog"
+	"github.com/mxmCherry/openrtb"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/macros"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"net/http"
+	"strconv"
+	"text/template"
+)
+
+type MobileFuseAdapter struct {
+	EndpointTemplate template.Template
+}
+
+func NewMobileFuseBidder(endpointTemplate string) adapters.Bidder {
+	parsedTemplate, err := template.New("endpointTemplate").Parse(endpointTemplate)
+
+	if err != nil {
+		glog.Fatal("Unable parse endpoint template: " + err.Error())
+		return nil
+	}
+
+	return &MobileFuseAdapter{EndpointTemplate: *parsedTemplate}
+}
+
+func (adapter *MobileFuseAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	var adapterRequests []*adapters.RequestData
+
+	adapterRequest, errs := adapter.makeRequest(request)
+
+	if errs == nil {
+		adapterRequests = append(adapterRequests, adapterRequest)
+	}
+
+	return adapterRequests, errs
+}
+
+func (adapter *MobileFuseAdapter) MakeBids(incomingRequest *openrtb.BidRequest, outgoingRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if response.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if response.StatusCode == http.StatusBadRequest {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Unexpected status code: %d.", response.StatusCode),
+		}}
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d.", response.StatusCode),
+		}}
+	}
+
+	var incomingBidResponse openrtb.BidResponse
+
+	if err := json.Unmarshal(response.Body, &incomingBidResponse); err != nil {
+		return nil, []error{err}
+	}
+
+	outgoingBidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+
+	for _, seatbid := range incomingBidResponse.SeatBid {
+		for i := range seatbid.Bid {
+			outgoingBidResponse.Bids = append(outgoingBidResponse.Bids, &adapters.TypedBid{
+				Bid:     &seatbid.Bid[i],
+				BidType: adapter.getBidType(seatbid.Bid[i].ImpID, incomingRequest.Imp),
+			})
+		}
+	}
+
+	return outgoingBidResponse, nil
+}
+
+func (adapter *MobileFuseAdapter) makeRequest(bidRequest *openrtb.BidRequest) (*adapters.RequestData, []error) {
+	var errs []error
+
+	mobileFuseExtension, errs := adapter.getFirstMobileFuseExtension(bidRequest)
+
+	if errs != nil {
+		return nil, errs
+	}
+
+	endpoint, err := adapter.getEndpoint(mobileFuseExtension)
+
+	if err != nil {
+		return nil, append(errs, err)
+	}
+
+	validImps := adapter.getValidImps(bidRequest, mobileFuseExtension)
+
+	if len(validImps) == 0 {
+		err := fmt.Errorf("No valid imps")
+		errs = append(errs, err)
+		return nil, errs
+	}
+
+	mobileFuseBidRequest := *bidRequest
+	mobileFuseBidRequest.Imp = validImps
+	body, err := json.Marshal(mobileFuseBidRequest)
+
+	if err != nil {
+		return nil, append(errs, err)
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+
+	return &adapters.RequestData{
+		Method:  "POST",
+		Uri:     endpoint,
+		Body:    body,
+		Headers: headers,
+	}, errs
+}
+
+func (adapter *MobileFuseAdapter) getFirstMobileFuseExtension(request *openrtb.BidRequest) (*openrtb_ext.ExtImpMobileFuse, []error) {
+	var mobileFuseImpExtension openrtb_ext.ExtImpMobileFuse
+	var errs []error
+
+	for _, imp := range request.Imp {
+		var bidder_imp_extension adapters.ExtImpBidder
+
+		err := json.Unmarshal(imp.Ext, &bidder_imp_extension)
+
+		if err != nil {
+			errs = append(errs, err)
+			continue
+		}
+
+		err = json.Unmarshal(bidder_imp_extension.Bidder, &mobileFuseImpExtension)
+
+		if err != nil {
+			errs = append(errs, err)
+			continue
+		}
+
+		break
+	}
+
+	return &mobileFuseImpExtension, errs
+}
+
+func (adapter *MobileFuseAdapter) getEndpoint(ext *openrtb_ext.ExtImpMobileFuse) (string, error) {
+	publisher_id := strconv.Itoa(ext.PublisherId)
+
+	url, errs := macros.ResolveMacros(adapter.EndpointTemplate, macros.EndpointTemplateParams{PublisherID: publisher_id})
+
+	if errs != nil {
+		return "", errs
+	}
+
+	if ext.TagidSrc == "ext" {
+		url += "&tagid_src=ext"
+	}
+
+	return url, nil
+}
+
+func (adapter *MobileFuseAdapter) getValidImps(bidRequest *openrtb.BidRequest, ext *openrtb_ext.ExtImpMobileFuse) []openrtb.Imp {
+	var validImps []openrtb.Imp
+
+	for _, imp := range bidRequest.Imp {
+		if imp.Banner != nil || imp.Video != nil {
+			if imp.Banner != nil && imp.Video != nil {
+				imp.Video = nil
+			}
+
+			imp.TagID = strconv.Itoa(ext.PlacementId)
+			imp.Ext = nil
+			validImps = append(validImps, imp)
+
+			break
+		}
+	}
+
+	return validImps
+}
+
+func (adapter *MobileFuseAdapter) getBidType(imp_id string, imps []openrtb.Imp) openrtb_ext.BidType {
+	if imps[0].Video != nil {
+		return openrtb_ext.BidTypeVideo
+	}
+
+	return openrtb_ext.BidTypeBanner
+}
diff --git a/adapters/visx/visx.go b/adapters/visx/visx.go
index 14fd2b68..418fafd4 100644
--- a/adapters/visx/visx.go
+++ b/adapters/visx/visx.go
@@ -14,11 +14,38 @@ type VisxAdapter struct {
 	endpoint string
 }
 
+type visxBid struct {
+	ImpID   string   `json:"impid"`
+	Price   float64  `json:"price"`
+	UID     int      `json:"auid"`
+	CrID    string   `json:"crid,omitempty"`
+	AdM     string   `json:"adm,omitempty"`
+	ADomain []string `json:"adomain,omitempty"`
+	DealID  string   `json:"dealid,omitempty"`
+	W       uint64   `json:"w,omitempty"`
+	H       uint64   `json:"h,omitempty"`
+}
+
+type visxSeatBid struct {
+	Bid  []visxBid `json:"bid"`
+	Seat string    `json:"seat,omitempty"`
+}
+
+type visxResponse struct {
+	SeatBid []visxSeatBid `json:"seatbid,omitempty"`
+}
+
 // MakeRequests makes the HTTP requests which should be made to fetch bids.
 func (a *VisxAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
 	var errors = make([]error, 0)
 
-	reqJSON, err := json.Marshal(request)
+	// copy the request, because we are going to mutate it
+	requestCopy := *request
+	if len(requestCopy.Cur) == 0 {
+		requestCopy.Cur = []string{"USD"}
+	}
+
+	reqJSON, err := json.Marshal(requestCopy)
 	if err != nil {
 		errors = append(errors, err)
 		return nil, errors
@@ -53,7 +80,7 @@ func (a *VisxAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequ
 		}}
 	}
 
-	var bidResp openrtb.BidResponse
+	var bidResp visxResponse
 	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
 		return nil, []error{err}
 	}
@@ -62,8 +89,19 @@ func (a *VisxAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequ
 
 	for _, sb := range bidResp.SeatBid {
 		for i := range sb.Bid {
+			bid := openrtb.Bid{}
+			bid.ID = internalRequest.ID
+			bid.CrID = sb.Bid[i].CrID
+			bid.ImpID = sb.Bid[i].ImpID
+			bid.Price = sb.Bid[i].Price
+			bid.AdM = sb.Bid[i].AdM
+			bid.W = sb.Bid[i].W
+			bid.H = sb.Bid[i].H
+			bid.ADomain = sb.Bid[i].ADomain
+			bid.DealID = sb.Bid[i].DealID
+
 			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
-				Bid:     &sb.Bid[i],
+				Bid:     &bid,
 				BidType: "banner",
 			})
 		}
diff --git a/config/config.go b/config/config.go
index 4c1d6983..703606b2 100755
--- a/config/config.go
+++ b/config/config.go
@@ -142,6 +142,7 @@ type GDPR struct {
 	Timeouts                GDPRTimeouts `mapstructure:"timeouts_ms"`
 	NonStandardPublishers   []string     `mapstructure:"non_standard_publishers,flow"`
 	NonStandardPublisherMap map[string]int
+	AMPException            bool `mapstructure:"amp_exception"`
 }
 
 func (cfg *GDPR) validate(errs configErrors) configErrors {
@@ -728,6 +729,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.lunamedia.endpoint", "http://api.lunamedia.io/xp/get?pubid={{.PublisherID}}")
 	v.SetDefault("adapters.marsmedia.endpoint", "https://bid306.rtbsrv.com/bidder/?bid=f3xtet")
 	v.SetDefault("adapters.mgid.endpoint", "https://prebid.mgid.com/prebid/")
+	v.SetDefault("adapters.mobilefuse.endpoint", "http://mfx-us-east.mobilefuse.com/openrtb?pub_id={{.PublisherID}}")
 	v.SetDefault("adapters.nanointeractive.endpoint", "https://ad.audiencemanager.de/hbs")
 	v.SetDefault("adapters.ninthdecimal.endpoint", "http://rtb.ninthdecimal.com/xp/get?pubid={{.PublisherID}}")
 	v.SetDefault("adapters.openx.endpoint", "http://rtb.openx.net/prebid")
@@ -768,6 +770,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("gdpr.timeouts_ms.init_vendorlist_fetches", 0)
 	v.SetDefault("gdpr.timeouts_ms.active_vendorlist_fetch", 0)
 	v.SetDefault("gdpr.non_standard_publishers", []string{""})
+	v.SetDefault("gdpr.amp_exception", false)
 	v.SetDefault("ccpa.enforce", false)
 	v.SetDefault("currency_converter.fetch_url", "https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json")
 	v.SetDefault("currency_converter.fetch_interval_seconds", 1800) // fetch currency rates every 30 minutes
diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go
index 97ac8d0c..586481dd 100644
--- a/endpoints/openrtb2/amp_auction.go
+++ b/endpoints/openrtb2/amp_auction.go
@@ -71,6 +71,7 @@ func NewAmpEndpoint(
 		defRequest,
 		defReqJSON,
 		bidderMap,
+		nil,
 		nil}).AmpAuction), nil
 
 }
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 4594a4d5..bcb13724 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -9,6 +9,7 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/url"
+	"regexp"
 	"strconv"
 	"time"
 
@@ -57,6 +58,7 @@ func NewEndpoint(ex exchange.Exchange, validator openrtb_ext.BidderParamValidato
 		defRequest,
 		defReqJSON,
 		bidderMap,
+		nil,
 		nil}).Auction), nil
 }
 
@@ -74,6 +76,7 @@ type endpointDeps struct {
 	defReqJSON       []byte
 	bidderMap        map[string]openrtb_ext.BidderName
 	cache            prebid_cache_client.Client
+	debugLogRegexp   *regexp.Regexp
 }
 
 func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go
index cf764bc9..020a5196 100644
--- a/endpoints/openrtb2/video_auction.go
+++ b/endpoints/openrtb2/video_auction.go
@@ -9,12 +9,13 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/url"
+	"regexp"
 	"strconv"
 	"strings"
 	"time"
 
 	"github.com/buger/jsonparser"
-	"github.com/evanphx/json-patch"
+	jsonpatch "github.com/evanphx/json-patch"
 	"github.com/gofrs/uuid"
 	"github.com/prebid/prebid-server/errortypes"
 
@@ -40,7 +41,9 @@ func NewVideoEndpoint(ex exchange.Exchange, validator openrtb_ext.BidderParamVal
 	}
 	defRequest := defReqJSON != nil && len(defReqJSON) > 0
 
-	return httprouter.Handle((&endpointDeps{ex, validator, requestsById, videoFetcher, categories, cfg, met, pbsAnalytics, disabledBidders, defRequest, defReqJSON, bidderMap, cache}).VideoAuctionEndpoint), nil
+	videoEndpointRegexp := regexp.MustCompile(`[<>]`)
+
+	return httprouter.Handle((&endpointDeps{ex, validator, requestsById, videoFetcher, categories, cfg, met, pbsAnalytics, disabledBidders, defRequest, defReqJSON, bidderMap, cache, videoEndpointRegexp}).VideoAuctionEndpoint), nil
 }
 
 /*
@@ -89,29 +92,17 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
 		cacheTTL = int64(deps.cfg.CacheURL.DefaultTTLs.Video)
 	}
 	debugLog := exchange.DebugLog{
-		EnableDebug: strings.EqualFold(debugQuery, "true"),
-		CacheType:   prebid_cache_client.TypeXML,
-		TTL:         cacheTTL,
+		Enabled:   strings.EqualFold(debugQuery, "true"),
+		CacheType: prebid_cache_client.TypeXML,
+		TTL:       cacheTTL,
+		Regexp:    deps.debugLogRegexp,
 	}
 
 	defer func() {
 		if len(debugLog.CacheKey) > 0 && vo.VideoResponse == nil {
-			debugLog.Data = fmt.Sprintf("<!--\n%s\n\nNo response created\n-->", debugLog.Data)
-			data, err := json.Marshal(debugLog.Data)
-			if err == nil {
-				toCache := []prebid_cache_client.Cacheable{
-					{
-						Type:       debugLog.CacheType,
-						Data:       data,
-						TTLSeconds: debugLog.TTL,
-						Key:        "log_" + debugLog.CacheKey,
-					},
-				}
-				if deps.cache != nil {
-					ctx, cancel := context.WithDeadline(context.Background(), start.Add(time.Duration(100)*time.Millisecond))
-					defer cancel()
-					deps.cache.PutJson(ctx, toCache)
-				}
+			err := putDebugLogError(deps.cache, &debugLog, start)
+			if err != nil {
+				vo.Errors = append(vo.Errors, err)
 			}
 		}
 		deps.metricsEngine.RecordRequest(labels)
@@ -130,12 +121,12 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
 	}
 
 	resolvedRequest := requestJson
-	if debugLog.EnableDebug {
-		debugLog.Data = fmt.Sprintf("Request:\n%s", string(requestJson))
+	if debugLog.Enabled {
+		debugLog.Data.Request = string(requestJson)
 		if headerBytes, err := json.Marshal(r.Header); err == nil {
-			debugLog.Data = fmt.Sprintf("%s\n\nHeaders:\n%s", debugLog.Data, string(headerBytes))
+			debugLog.Data.Headers = string(headerBytes)
 		} else {
-			debugLog.Data = fmt.Sprintf("%s\n\nUnable to marshal headers data\n", debugLog.Data)
+			debugLog.Data.Headers = fmt.Sprintf("Unable to marshal headers data: %s", err.Error())
 		}
 	}
 
@@ -182,7 +173,7 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
 	//create full open rtb req from full video request
 	mergeData(videoBidReq, bidReq)
 	// If debug query param is set, force the response to enable test flag
-	if debugLog.EnableDebug {
+	if debugLog.Enabled {
 		bidReq.Test = 1
 	}
 
@@ -281,6 +272,34 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
 
 }
 
+func putDebugLogError(cache prebid_cache_client.Client, debugLog *exchange.DebugLog, start time.Time) error {
+	debugLog.Data.Response = "No response created"
+
+	debugLog.BuildCacheString()
+
+	data, err := json.Marshal(debugLog.CacheString)
+	if err != nil {
+		return err
+	}
+
+	toCache := []prebid_cache_client.Cacheable{
+		{
+			Type:       debugLog.CacheType,
+			Data:       data,
+			TTLSeconds: debugLog.TTL,
+			Key:        "log_" + debugLog.CacheKey,
+		},
+	}
+
+	if cache != nil {
+		ctx, cancel := context.WithDeadline(context.Background(), start.Add(time.Duration(100)*time.Millisecond))
+		defer cancel()
+		cache.PutJson(ctx, toCache)
+	}
+
+	return nil
+}
+
 func cleanupVideoBidRequest(videoReq *openrtb_ext.BidRequestVideo, podErrors []PodError) *openrtb_ext.BidRequestVideo {
 	for i := len(podErrors) - 1; i >= 0; i-- {
 		videoReq.PodConfig.Pods = append(videoReq.PodConfig.Pods[:podErrors[i].PodIndex], videoReq.PodConfig.Pods[podErrors[i].PodIndex+1:]...)
@@ -289,7 +308,7 @@ func cleanupVideoBidRequest(videoReq *openrtb_ext.BidRequestVideo, podErrors []P
 }
 
 func handleError(labels *pbsmetrics.Labels, w http.ResponseWriter, errL []error, vo *analytics.VideoObject, debugLog *exchange.DebugLog) {
-	if debugLog != nil && debugLog.EnableDebug {
+	if debugLog != nil && debugLog.Enabled {
 		if rawUUID, err := uuid.NewV4(); err == nil {
 			debugLog.CacheKey = rawUUID.String()
 		}
diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go
index 9110b20f..15e57f55 100755
--- a/exchange/adapter_map.go
+++ b/exchange/adapter_map.go
@@ -44,6 +44,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/lunamedia"
 	"github.com/prebid/prebid-server/adapters/marsmedia"
 	"github.com/prebid/prebid-server/adapters/mgid"
+	"github.com/prebid/prebid-server/adapters/mobilefuse"
 	"github.com/prebid/prebid-server/adapters/nanointeractive"
 	"github.com/prebid/prebid-server/adapters/ninthdecimal"
 	"github.com/prebid/prebid-server/adapters/openx"
@@ -121,6 +122,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter
 		openrtb_ext.BidderLunaMedia:       lunamedia.NewLunaMediaBidder(cfg.Adapters[string(openrtb_ext.BidderLunaMedia)].Endpoint),
 		openrtb_ext.BidderMarsmedia:       marsmedia.NewMarsmediaBidder(cfg.Adapters[string(openrtb_ext.BidderMarsmedia)].Endpoint),
 		openrtb_ext.BidderMgid:            mgid.NewMgidBidder(cfg.Adapters[string(openrtb_ext.BidderMgid)].Endpoint),
+		openrtb_ext.BidderMobileFuse:      mobilefuse.NewMobileFuseBidder(cfg.Adapters[string(openrtb_ext.BidderMobileFuse)].Endpoint),
 		openrtb_ext.BidderNanoInteractive: nanointeractive.NewNanoIneractiveBidder(cfg.Adapters[string(openrtb_ext.BidderNanoInteractive)].Endpoint),
 		openrtb_ext.BidderNinthDecimal:    ninthdecimal.NewNinthDecimalBidder(cfg.Adapters[string(openrtb_ext.BidderNinthDecimal)].Endpoint),
 		openrtb_ext.BidderOrbidder:        orbidder.NewOrbidderBidder(cfg.Adapters[string(openrtb_ext.BidderOrbidder)].Endpoint),
diff --git a/exchange/auction.go b/exchange/auction.go
index 9909b78d..dcb73708 100644
--- a/exchange/auction.go
+++ b/exchange/auction.go
@@ -3,8 +3,10 @@ package exchange
 import (
 	"context"
 	"encoding/json"
+	"encoding/xml"
 	"errors"
 	"fmt"
+	"regexp"
 	"strings"
 
 	uuid "github.com/gofrs/uuid"
@@ -15,6 +17,36 @@ import (
 	"github.com/prebid/prebid-server/prebid_cache_client"
 )
 
+type DebugLog struct {
+	Enabled     bool
+	CacheType   prebid_cache_client.PayloadType
+	Data        DebugData
+	TTL         int64
+	CacheKey    string
+	CacheString string
+	Regexp      *regexp.Regexp
+}
+
+type DebugData struct {
+	Request  string
+	Headers  string
+	Response string
+}
+
+func (d *DebugLog) BuildCacheString() {
+	if d.Regexp != nil {
+		d.Data.Request = fmt.Sprintf(d.Regexp.ReplaceAllString(d.Data.Request, ""))
+		d.Data.Headers = fmt.Sprintf(d.Regexp.ReplaceAllString(d.Data.Headers, ""))
+		d.Data.Response = fmt.Sprintf(d.Regexp.ReplaceAllString(d.Data.Response, ""))
+	}
+
+	d.Data.Request = fmt.Sprintf("<Request>%s</Request>", d.Data.Request)
+	d.Data.Headers = fmt.Sprintf("<Headers>%s</Headers>", d.Data.Headers)
+	d.Data.Response = fmt.Sprintf("<Response>%s</Response>", d.Data.Response)
+
+	d.CacheString = fmt.Sprintf("%s<Log>%s%s%s</Log>", xml.Header, d.Data.Request, d.Data.Headers, d.Data.Response)
+}
+
 func newAuction(seatBids map[openrtb_ext.BidderName]*pbsOrtbSeatBid, numImps int) *auction {
 	winningBids := make(map[string]*pbsOrtbBid, numImps)
 	winningBidsByBidder := make(map[string]map[openrtb_ext.BidderName]*pbsOrtbBid, numImps)
@@ -147,9 +179,10 @@ func (a *auction) doCache(ctx context.Context, cache prebid_cache_client.Client,
 		}
 	}
 
-	if debugLog != nil && debugLog.EnableDebug {
+	if debugLog != nil && debugLog.Enabled {
+		debugLog.BuildCacheString()
 		debugLog.CacheKey = hbCacheID
-		if jsonBytes, err := json.Marshal(debugLog.Data); err == nil {
+		if jsonBytes, err := json.Marshal(debugLog.CacheString); err == nil {
 			toCache = append(toCache, prebid_cache_client.Cacheable{
 				Type:       debugLog.CacheType,
 				Data:       jsonBytes,
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 48903dd9..6d51b87d 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -27,14 +27,6 @@ import (
 	"github.com/prebid/prebid-server/prebid_cache_client"
 )
 
-type DebugLog struct {
-	EnableDebug bool
-	CacheType   prebid_cache_client.PayloadType
-	Data        string
-	TTL         int64
-	CacheKey    string
-}
-
 // Exchange runs Auctions. Implementations must be threadsafe, and will be shared across many goroutines.
 type Exchange interface {
 	// HoldAuction executes an OpenRTB v2.5 Auction.
@@ -174,25 +166,33 @@ func (e *exchange) HoldAuction(ctx context.Context, bidRequest *openrtb.BidReque
 
 		if targData != nil {
 			auc.setRoundedPrices(targData.priceGranularity)
-			if debugLog != nil && debugLog.EnableDebug {
-				bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, bidRequest, resolvedRequest, errs)
-				if bidRespExtBytes, err := json.Marshal(bidResponseExt); err == nil {
-					debugLog.Data = fmt.Sprintf("<!--\n%s\n\nResponse:\n%s\n-->", debugLog.Data, string(bidRespExtBytes))
-				} else {
-					errs = append(errs, errors.New("Unable to marshal response ext for debugging"))
-				}
-			}
 
 			if requestExt.Prebid.SupportDeals {
 				dealErrs := applyDealSupport(bidRequest, auc, bidCategory)
 				errs = append(errs, dealErrs...)
 			}
 
+			if debugLog != nil && debugLog.Enabled {
+				bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, bidRequest, resolvedRequest, errs)
+				if bidRespExtBytes, err := json.Marshal(bidResponseExt); err == nil {
+					debugLog.Data.Response = string(bidRespExtBytes)
+				} else {
+					debugLog.Data.Response = "Unable to marshal response ext for debugging"
+					errs = append(errs, errors.New(debugLog.Data.Response))
+				}
+			}
+
 			cacheErrs := auc.doCache(ctx, e.cache, targData, bidRequest, 60, &e.defaultTTLs, bidCategory, debugLog)
 			if len(cacheErrs) > 0 {
 				errs = append(errs, cacheErrs...)
 			}
 			targData.setTargeting(auc, bidRequest.App != nil, bidCategory)
+
+			// Ensure caching errors are added if the bid response ext has already been created
+			if bidResponseExt != nil && len(cacheErrs) > 0 {
+				bidderCacheErrs := errsToBidderErrors(cacheErrs)
+				bidResponseExt.Errors[openrtb_ext.PrebidExtKey] = append(bidResponseExt.Errors[openrtb_ext.PrebidExtKey], bidderCacheErrs...)
+			}
 		}
 
 	}
diff --git a/exchange/utils.go b/exchange/utils.go
index f09b1151..d961089c 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -43,6 +43,7 @@ func cleanOpenRTBRequests(ctx context.Context,
 
 	gdpr := extractGDPR(orig, usersyncIfAmbiguous)
 	consent := extractConsent(orig)
+	ampGDPRException := (labels.RType == pbsmetrics.ReqTypeAMP) && gDPR.AMPException()
 
 	privacyEnforcement := privacy.Enforcement{
 		COPPA: orig.Regs != nil && orig.Regs.COPPA == 1,
@@ -65,7 +66,7 @@ func cleanOpenRTBRequests(ctx context.Context,
 			privacyEnforcement.GDPR = false
 		}
 
-		privacyEnforcement.Apply(bidReq)
+		privacyEnforcement.Apply(bidReq, ampGDPRException)
 	}
 
 	return
diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go
index 4e36e22f..9390d942 100644
--- a/gdpr/gdpr.go
+++ b/gdpr/gdpr.go
@@ -24,6 +24,9 @@ type Permissions interface {
 	//
 	// If the consent string was nonsensical, the returned error will be an ErrorMalformedConsent.
 	PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, error)
+
+	// Exposes the AMP execption flag
+	AMPException() bool
 }
 
 const (
diff --git a/gdpr/impl.go b/gdpr/impl.go
index 615c3a09..8743d7f2 100644
--- a/gdpr/impl.go
+++ b/gdpr/impl.go
@@ -58,6 +58,10 @@ func (p *permissionsImpl) PersonalInfoAllowed(ctx context.Context, bidder openrt
 	return false, nil
 }
 
+func (p *permissionsImpl) AMPException() bool {
+	return p.cfg.AMPException
+}
+
 func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, consent string) (bool, error) {
 	// If we're not given a consent string, respect the preferences in the app config.
 	if consent == "" {
@@ -145,3 +149,7 @@ func (a AlwaysAllow) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.B
 func (a AlwaysAllow) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, error) {
 	return true, nil
 }
+
+func (a AlwaysAllow) AMPException() bool {
+	return false
+}
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index a0a8c6a8..7db59e69 100755
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -62,6 +62,7 @@ const (
 	BidderLunaMedia        BidderName = "lunamedia"
 	BidderMarsmedia        BidderName = "marsmedia"
 	BidderMgid             BidderName = "mgid"
+	BidderMobileFuse       BidderName = "mobilefuse"
 	BidderNanoInteractive  BidderName = "nanointeractive"
 	BidderNinthDecimal     BidderName = "ninthdecimal"
 	BidderOpenx            BidderName = "openx"
@@ -135,6 +136,7 @@ var BidderMap = map[string]BidderName{
 	"lunamedia":         BidderLunaMedia,
 	"marsmedia":         BidderMarsmedia,
 	"mgid":              BidderMgid,
+	"mobilefuse":        BidderMobileFuse,
 	"nanointeractive":   BidderNanoInteractive,
 	"ninthdecimal":      BidderNinthDecimal,
 	"openx":             BidderOpenx,
diff --git a/openrtb_ext/imp_mobilefuse.go b/openrtb_ext/imp_mobilefuse.go
new file mode 100644
index 00000000..ea53c591
--- /dev/null
+++ b/openrtb_ext/imp_mobilefuse.go
@@ -0,0 +1,8 @@
+package openrtb_ext
+
+// ExtImpMobileFuse defines the contract for bidrequest.imp[i].ext.mobilefuse
+type ExtImpMobileFuse struct {
+	PlacementId int    `json:"placement_id"`
+	PublisherId int    `json:"pub_id"`
+	TagidSrc    string `json:"tagid_src"`
+}
diff --git a/privacy/enforcement.go b/privacy/enforcement.go
index 0230ca6b..96d03ef4 100644
--- a/privacy/enforcement.go
+++ b/privacy/enforcement.go
@@ -17,14 +17,14 @@ func (e Enforcement) Any() bool {
 }
 
 // Apply cleans personally identifiable information from an OpenRTB bid request.
-func (e Enforcement) Apply(bidRequest *openrtb.BidRequest) {
-	e.apply(bidRequest, NewScrubber())
+func (e Enforcement) Apply(bidRequest *openrtb.BidRequest, ampGDPRException bool) {
+	e.apply(bidRequest, ampGDPRException, NewScrubber())
 }
 
-func (e Enforcement) apply(bidRequest *openrtb.BidRequest, scrubber Scrubber) {
+func (e Enforcement) apply(bidRequest *openrtb.BidRequest, ampGDPRException bool, scrubber Scrubber) {
 	if bidRequest != nil && e.Any() {
 		bidRequest.Device = scrubber.ScrubDevice(bidRequest.Device, e.getIPv6ScrubStrategy(), e.getGeoScrubStrategy())
-		bidRequest.User = scrubber.ScrubUser(bidRequest.User, e.getDemographicScrubStrategy(), e.getGeoScrubStrategy())
+		bidRequest.User = scrubber.ScrubUser(bidRequest.User, e.getUserScrubStrategy(ampGDPRException), e.getGeoScrubStrategy())
 	}
 }
 
@@ -52,10 +52,13 @@ func (e Enforcement) getGeoScrubStrategy() ScrubStrategyGeo {
 	return ScrubStrategyGeoNone
 }
 
-func (e Enforcement) getDemographicScrubStrategy() ScrubStrategyDemographic {
+func (e Enforcement) getUserScrubStrategy(ampGDPRException bool) ScrubStrategyUser {
 	if e.COPPA {
-		return ScrubStrategyDemographicAgeAndGender
+		return ScrubStrategyUserIDAndDemographic
 	}
 
-	return ScrubStrategyDemographicNone
+	if e.GDPR && ampGDPRException {
+		return ScrubStrategyUserNone
+	}
+	return ScrubStrategyUserID
 }
diff --git a/privacy/scrubber.go b/privacy/scrubber.go
index 45b79c20..ec313e91 100644
--- a/privacy/scrubber.go
+++ b/privacy/scrubber.go
@@ -34,21 +34,24 @@ const (
 	ScrubStrategyGeoReducedPrecision
 )
 
-// ScrubStrategyDemographic defines the approach to non-location demographic data.
-type ScrubStrategyDemographic int
+// ScrubStrategyUser defines the approach to scrub PII from user data.
+type ScrubStrategyUser int
 
 const (
-	// ScrubStrategyDemographicNone does not remove non-location demographic data.
-	ScrubStrategyDemographicNone ScrubStrategyDemographic = iota
+	// ScrubStrategyUserNone does not remove non-location data.
+	ScrubStrategyUserNone ScrubStrategyUser = iota
 
-	// ScrubStrategyDemographicAgeAndGender removes age and gender data.
-	ScrubStrategyDemographicAgeAndGender
+	// ScrubStrategyUserIDAndDemographic removes the user's buyer id, exchange id year of birth, and gender.
+	ScrubStrategyUserIDAndDemographic
+
+	// ScrubStrategyUserID removes the user's buyer id.
+	ScrubStrategyUserID
 )
 
 // Scrubber removes PII from parts of an OpenRTB request.
 type Scrubber interface {
 	ScrubDevice(device *openrtb.Device, ipv6 ScrubStrategyIPV6, geo ScrubStrategyGeo) *openrtb.Device
-	ScrubUser(user *openrtb.User, demographic ScrubStrategyDemographic, geo ScrubStrategyGeo) *openrtb.User
+	ScrubUser(user *openrtb.User, strategy ScrubStrategyUser, geo ScrubStrategyGeo) *openrtb.User
 }
 
 type scrubber struct{}
@@ -90,19 +93,22 @@ func (scrubber) ScrubDevice(device *openrtb.Device, ipv6 ScrubStrategyIPV6, geo
 	return &deviceCopy
 }
 
-func (scrubber) ScrubUser(user *openrtb.User, demographic ScrubStrategyDemographic, geo ScrubStrategyGeo) *openrtb.User {
+func (scrubber) ScrubUser(user *openrtb.User, strategy ScrubStrategyUser, geo ScrubStrategyGeo) *openrtb.User {
 	if user == nil {
 		return nil
 	}
 
 	userCopy := *user
-	userCopy.BuyerUID = ""
-	userCopy.ID = ""
 
-	switch demographic {
-	case ScrubStrategyDemographicAgeAndGender:
+	switch strategy {
+	case ScrubStrategyUserIDAndDemographic:
+		userCopy.BuyerUID = ""
+		userCopy.ID = ""
 		userCopy.Yob = 0
 		userCopy.Gender = ""
+	case ScrubStrategyUserID:
+		userCopy.BuyerUID = ""
+		userCopy.ID = ""
 	}
 
 	switch geo {
diff --git a/router/router.go b/router/router.go
index 68627f93..045c86ef 100644
--- a/router/router.go
+++ b/router/router.go
@@ -6,13 +6,14 @@ import (
 	"database/sql"
 	"encoding/json"
 	"fmt"
-	"github.com/prebid/prebid-server/pbsmetrics"
 	"io/ioutil"
 	"net/http"
 	"path/filepath"
 	"strings"
 	"time"
 
+	"github.com/prebid/prebid-server/pbsmetrics"
+
 	"github.com/prebid/prebid-server/adapters"
 	"github.com/prebid/prebid-server/adapters/adform"
 	"github.com/prebid/prebid-server/adapters/appnexus"
diff --git a/static/bidder-info/mobilefuse.yaml b/static/bidder-info/mobilefuse.yaml
new file mode 100644
index 00000000..178e407d
--- /dev/null
+++ b/static/bidder-info/mobilefuse.yaml
@@ -0,0 +1,7 @@
+maintainer:
+  email: prebid@mobilefuse.com
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
diff --git a/static/bidder-params/mobilefuse.json b/static/bidder-params/mobilefuse.json
new file mode 100644
index 00000000..15f17148
--- /dev/null
+++ b/static/bidder-params/mobilefuse.json
@@ -0,0 +1,24 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "MobileFuse Adapter Params",
+    "description": "A schema which validates params accepted by the MobileFuse adapter",
+    "type": "object",
+    "properties": {
+        "placement_id": {
+            "type": "integer",
+            "description": "An ID which identifies this specific inventory placement"
+        },
+        "pub_id": {
+            "type": "integer",
+            "description": "An ID which identifies the publisher selling the inventory."
+        },
+        "tagid_src": {
+            "type": "string",
+            "description": "ext if passing publisher's ids, empty if passing MobileFuse IDs in placement_id field. Defaults to empty"
+        }
+    },
+    "required": [
+        "placement_id",
+        "pub_id"
+    ]
+}
\ No newline at end of file


Test patch:
diff --git a/adapters/advangelists/usersync_test.go b/adapters/advangelists/usersync_test.go
index b97652c1..2167d49f 100644
--- a/adapters/advangelists/usersync_test.go
+++ b/adapters/advangelists/usersync_test.go
@@ -26,6 +26,6 @@ func TestAdvangelistsSyncer(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, "https://nep.advangelists.com/xp/user-sync?acctid={aid}&&redirect=localhost/setuid?bidder=advangelists&gdpr=1&gdpr_consent=BOPVK28OVJoTBABABAENBs-AAAAhuAKAANAAoACwAGgAPAAxAB0AHgAQAAiABOADkA&uid=$UID", syncInfo.URL)
 	assert.Equal(t, "iframe", syncInfo.Type)
-	assert.EqualValues(t, 61, syncer.GDPRVendorID())
+	assert.EqualValues(t, 0, syncer.GDPRVendorID())
 	assert.Equal(t, false, syncInfo.SupportCORS)
 }
diff --git a/adapters/consumable/usersync_test.go b/adapters/consumable/usersync_test.go
index eb97edf2..017cb729 100644
--- a/adapters/consumable/usersync_test.go
+++ b/adapters/consumable/usersync_test.go
@@ -30,6 +30,6 @@ func TestConsumableSyncer(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, "//e.serverbid.com/udb/9969/match?gdpr=A&euconsent=B&us_privacy=C&redir=http%3A%2F%2Flocalhost%3A8000%2Fsetuid%3Fbidder%3Dconsumable%26gdpr%3DA%26gdpr_consent%3DB%26uid%3D", u.URL)
 	assert.Equal(t, "redirect", u.Type)
-	assert.Equal(t, uint16(65535), syncer.GDPRVendorID())
+	assert.Equal(t, uint16(591), syncer.GDPRVendorID())
 	assert.Equal(t, false, u.SupportCORS)
 }
diff --git a/adapters/eplanning/eplanningtest/exemplary/simple-banner-2.json b/adapters/eplanning/eplanningtest/exemplary/simple-banner-2.json
index f4c8fe0c..e602877f 100644
--- a/adapters/eplanning/eplanningtest/exemplary/simple-banner-2.json
+++ b/adapters/eplanning/eplanningtest/exemplary/simple-banner-2.json
@@ -28,7 +28,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=300x250:300x250",
+        "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?e=300x250%3A300x250&ncb=1&r=pbs&ur=FILE",
         "body": {}
       },
       "mockResponse": {
diff --git a/adapters/eplanning/eplanningtest/exemplary/simple-banner.json b/adapters/eplanning/eplanningtest/exemplary/simple-banner.json
index 61b7878a..0403e59a 100644
--- a/adapters/eplanning/eplanningtest/exemplary/simple-banner.json
+++ b/adapters/eplanning/eplanningtest/exemplary/simple-banner.json
@@ -31,7 +31,7 @@
   "httpCalls": [
     {
       "expectedRequest": {
-        "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadun_itco_de:600x300&uid=2154987&ip=123.123.123.123",
+        "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?e=testadun_itco_de%3A600x300&ip=123.123.123.123&ncb=1&r=pbs&uid=2154987&ur=FILE",
         "body": {}
       },
       "mockResponse": {
diff --git a/adapters/eplanning/eplanningtest/exemplary/two-banners.json b/adapters/eplanning/eplanningtest/exemplary/two-banners.json
index fccc1a30..8c4ca021 100644
--- a/adapters/eplanning/eplanningtest/exemplary/two-banners.json
+++ b/adapters/eplanning/eplanningtest/exemplary/two-banners.json
@@ -39,7 +39,7 @@
     "httpCalls": [
       {
         "expectedRequest": {
-          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadunitcode:600x300+300x250:300x250&ip=123.123.123.123",
+          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?e=testadunitcode%3A600x300%2B300x250%3A300x250&ip=123.123.123.123&ncb=1&r=pbs&ur=FILE",
           "body": {}
         },
         "mockResponse": {
diff --git a/adapters/eplanning/eplanningtest/supplemental/app-domain-and-url-correctly-parsed.json b/adapters/eplanning/eplanningtest/supplemental/app-domain-and-url-correctly-parsed.json
new file mode 100644
index 00000000..e6e25566
--- /dev/null
+++ b/adapters/eplanning/eplanningtest/supplemental/app-domain-and-url-correctly-parsed.json
@@ -0,0 +1,90 @@
+{
+    "mockBidRequest": {
+      "id": "test-request-id",
+      "imp": [
+        {
+          "id": "test-imp-id",
+          "banner": {
+            "w": 600,
+            "h": 300
+          },
+          "ext": {
+            "bidder": {
+              "ci": "12345",
+              "adunit_code": "test_adunitcode"
+            }
+          }
+        }
+      ],
+      "app": {
+        "id": "[a-f0-9]{16}",
+        "name": "MobileExchange",
+        "domain": "sitio.net",
+        "cat":  ["IAB12"],
+        "publisher": {
+          "id": "[a-f0-9]{16}",
+          "name": "mobile - cliente sitio con exchange activo y ad magic"
+        },
+        "bundle": "mx.com.xeu"
+      },
+      "device": {
+        "ua": "test-user-agent",
+        "ip": "123.123.123.123",
+        "ifa": "3B8E2335-Z049",
+        "language": "en",
+        "dnt": 1
+      }
+    },
+  
+    "httpCalls": [
+      {
+        "expectedRequest": {
+          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/mx.com.xeu/ROS?app=1&appid=%5Ba-f0-9%5D%7B16%7D&appn=MobileExchange&e=testadunitcode%3A600x300&ifa=3B8E2335-Z049&ip=123.123.123.123&ncb=1&r=pbs",
+          "body": {}
+        },
+        "mockResponse": {
+          "status": 200,
+          "body": {
+            "sI": { "k": "12345" },
+            "sec": "ROS",
+            "sp": [
+              {
+                "k": "testadunitcode",
+                "a": [{
+                  "i": "123456789abcdef",
+                  "pr": "0.5",
+                  "adm": "<div>test</div>",
+                  "crid": "abcdef123456789",
+                  "id": "adid12345",
+                  "w": 600,
+                  "h": 300
+                }]
+              }
+            ]
+          }
+        }
+      }
+    ],
+  
+    "expectedBidResponses": [
+      {
+        "currency": "USD",
+        "bids": [
+          {
+            "bid": {
+              "id": "123456789abcdef",
+              "impid": "test-imp-id",
+              "price": 0.5,
+              "adm": "<div>test</div>",
+              "adid": "adid12345",
+              "crid": "abcdef123456789",
+              "w": 600,
+              "h": 300
+            },
+            "type": "banner"
+          }
+        ]
+      }
+    ]
+  }
+  
diff --git a/adapters/eplanning/eplanningtest/supplemental/banner-no-size-sends-1x1.json b/adapters/eplanning/eplanningtest/supplemental/banner-no-size-sends-1x1.json
index afa7b953..f1bc29e1 100644
--- a/adapters/eplanning/eplanningtest/supplemental/banner-no-size-sends-1x1.json
+++ b/adapters/eplanning/eplanningtest/supplemental/banner-no-size-sends-1x1.json
@@ -19,7 +19,7 @@
     "httpCalls": [
       {
         "expectedRequest": {
-          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadunitcodenosize:1x1",
+          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?e=testadunitcodenosize%3A1x1&ncb=1&r=pbs&ur=FILE",
           "body": {}
         },
         "mockResponse": {
diff --git a/adapters/eplanning/eplanningtest/supplemental/invalid-response-no-bids.json b/adapters/eplanning/eplanningtest/supplemental/invalid-response-no-bids.json
index 3bf45a16..978989e2 100644
--- a/adapters/eplanning/eplanningtest/supplemental/invalid-response-no-bids.json
+++ b/adapters/eplanning/eplanningtest/supplemental/invalid-response-no-bids.json
@@ -21,7 +21,7 @@
     "httpCalls": [
       {
         "expectedRequest": {
-          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadunitcode:600x300",
+          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?e=testadunitcode%3A600x300&ncb=1&r=pbs&ur=FILE",
           "body": {}
         },
         "mockResponse": {
diff --git a/adapters/eplanning/eplanningtest/supplemental/invalid-response-unmarshall-error.json b/adapters/eplanning/eplanningtest/supplemental/invalid-response-unmarshall-error.json
index e8d88f17..7198f4ee 100644
--- a/adapters/eplanning/eplanningtest/supplemental/invalid-response-unmarshall-error.json
+++ b/adapters/eplanning/eplanningtest/supplemental/invalid-response-unmarshall-error.json
@@ -21,7 +21,7 @@
     "httpCalls": [
       {
         "expectedRequest": {
-          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadunitcode:600x300",
+          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?e=testadunitcode%3A600x300&ncb=1&r=pbs&ur=FILE",
           "body": {}
         },
         "mockResponse": {
diff --git a/adapters/eplanning/eplanningtest/supplemental/server-bad-request.json b/adapters/eplanning/eplanningtest/supplemental/server-bad-request.json
index 421f47ef..938ede62 100644
--- a/adapters/eplanning/eplanningtest/supplemental/server-bad-request.json
+++ b/adapters/eplanning/eplanningtest/supplemental/server-bad-request.json
@@ -21,7 +21,7 @@
     "httpCalls": [
       {
         "expectedRequest": {
-          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadunitcode:600x300",
+          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?e=testadunitcode%3A600x300&ncb=1&r=pbs&ur=FILE",
           "body": {}
         },
         "mockResponse": {
diff --git a/adapters/eplanning/eplanningtest/supplemental/server-error-code.json b/adapters/eplanning/eplanningtest/supplemental/server-error-code.json
index ceec970b..eaa2a677 100644
--- a/adapters/eplanning/eplanningtest/supplemental/server-error-code.json
+++ b/adapters/eplanning/eplanningtest/supplemental/server-error-code.json
@@ -21,7 +21,7 @@
     "httpCalls": [
       {
         "expectedRequest": {
-          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadunitcode:600x300",
+          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?e=testadunitcode%3A600x300&ncb=1&r=pbs&ur=FILE",
           "body": {}
         },
         "mockResponse": {
diff --git a/adapters/eplanning/eplanningtest/supplemental/server-no-content.json b/adapters/eplanning/eplanningtest/supplemental/server-no-content.json
index a2e444a9..d1feb865 100644
--- a/adapters/eplanning/eplanningtest/supplemental/server-no-content.json
+++ b/adapters/eplanning/eplanningtest/supplemental/server-no-content.json
@@ -21,7 +21,7 @@
     "httpCalls": [
       {
         "expectedRequest": {
-          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadunitcode:600x300",
+          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/FILE/ROS?e=testadunitcode%3A600x300&ncb=1&r=pbs&ur=FILE",
           "body": {}
         },
         "mockResponse": {
diff --git a/adapters/eplanning/eplanningtest/supplemental/site-domain-and-url-correctly-parsed.json b/adapters/eplanning/eplanningtest/supplemental/site-domain-and-url-correctly-parsed.json
index d889f481..2f43b9aa 100644
--- a/adapters/eplanning/eplanningtest/supplemental/site-domain-and-url-correctly-parsed.json
+++ b/adapters/eplanning/eplanningtest/supplemental/site-domain-and-url-correctly-parsed.json
@@ -25,7 +25,7 @@
     "httpCalls": [
       {
         "expectedRequest": {
-          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/www.publisher.com/ROS?r=pbs&ncb=1&ur=http%3A%2F%2Fwww.publisher.com%2Fawesome%2Fsite%3Fwith%3Dsome%26parameters%3Dhere&e=testadunitcode:600x300",
+          "uri": "https://ads.us.e-planning.net/hb/1/12345/1/www.publisher.com/ROS?e=testadunitcode%3A600x300&ncb=1&r=pbs&ur=http%3A%2F%2Fwww.publisher.com%2Fawesome%2Fsite%3Fwith%3Dsome%26parameters%3Dhere",
           "body": {}
         },
         "mockResponse": {
diff --git a/adapters/mobilefuse/mobilefuse_test.go b/adapters/mobilefuse/mobilefuse_test.go
new file mode 100644
index 00000000..15021a06
--- /dev/null
+++ b/adapters/mobilefuse/mobilefuse_test.go
@@ -0,0 +1,10 @@
+package mobilefuse
+
+import (
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"testing"
+)
+
+func TestJsonSamples(t *testing.T) {
+	adapterstest.RunJSONBidderTest(t, "mobilefusetest", NewMobileFuseBidder("http://mfx-us-east.mobilefuse.com/openrtb?pub_id={{.PublisherID}}"))
+}
diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/multi-format.json b/adapters/mobilefuse/mobilefusetest/exemplary/multi-format.json
new file mode 100644
index 00000000..49fb8819
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/exemplary/multi-format.json
@@ -0,0 +1,67 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 320,
+                            "h": 50
+                        }
+                    ]
+                },
+                "video": {
+                    "mimes": [
+                        "video/mp4"
+                    ],
+                    "protocols": [
+                        2,
+                        5
+                    ],
+                    "w": 320,
+                    "h": 480
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 123456,
+                        "pub_id": 1234
+                    }
+                }
+            }
+        ]
+    },
+
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://mfx-us-east.mobilefuse.com/openrtb?pub_id=1234",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 320,
+                                        "h": 50
+                                    }
+                                ]
+                            },
+                            "tagid": "123456"
+                        }
+                    ]
+                }
+            },
+
+            "mockResponse": {
+                "status": 204,
+                "body": ""
+            }
+        }
+    ],
+
+    "expectedBidResponses": []
+}
diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json
new file mode 100644
index 00000000..61ac1a3e
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json
@@ -0,0 +1,110 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 320,
+                            "h": 50
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 123456,
+                        "pub_id": 1234
+                    }
+                }
+            },
+            {
+                "id": "2",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 50
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 234567,
+                        "pub_id": 1234
+                    }
+                }
+            }
+        ]
+    },
+
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://mfx-us-east.mobilefuse.com/openrtb?pub_id=1234",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 320,
+                                        "h": 50
+                                    }
+                                ]
+                            },
+                            "tagid": "123456"
+                        }
+                    ]
+                }
+            },
+
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "mobilefuse",
+                            "bid": [
+                                {
+                                    "id": "test-bid-id",
+                                    "impid": "1",
+                                    "price": 1.50,
+                                    "adm": "some-test-ad",
+                                    "crid": "test-crid",
+                                    "h": 50,
+                                    "w": 320
+                                }
+                            ]
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test-bid-id",
+                        "impid": "1",
+                        "price": 1.50,
+                        "adm": "some-test-ad",
+                        "crid": "test-crid",
+                        "w": 320,
+                        "h": 50
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/no-bid.json b/adapters/mobilefuse/mobilefusetest/exemplary/no-bid.json
new file mode 100644
index 00000000..cec47a0b
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/exemplary/no-bid.json
@@ -0,0 +1,55 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 999999,
+                        "pub_id": 1111
+                    }
+                }
+            }
+        ]
+    },
+
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://mfx-us-east.mobilefuse.com/openrtb?pub_id=1111",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ]
+                            },
+                            "tagid": "999999"
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 204,
+                "body": {}
+            }
+        }
+    ],
+
+    "expectedBidResponses": []
+}
diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/optional-params.json b/adapters/mobilefuse/mobilefusetest/exemplary/optional-params.json
new file mode 100644
index 00000000..2f71da8f
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/exemplary/optional-params.json
@@ -0,0 +1,56 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 999999,
+                        "pub_id": 1111,
+                        "tagid_src": "ext"
+                    }
+                }
+            }
+        ]
+    },
+
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://mfx-us-east.mobilefuse.com/openrtb?pub_id=1111&tagid_src=ext",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ]
+                            },
+                            "tagid": "999999"
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 204,
+                "body": {}
+            }
+        }
+    ],
+
+    "expectedBidResponses": []
+}
diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json b/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json
new file mode 100644
index 00000000..7db7776d
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json
@@ -0,0 +1,93 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 320,
+                            "h": 50
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 123456,
+                        "pub_id": 1234
+                    }
+                }
+            }
+        ]
+    },
+
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://mfx-us-east.mobilefuse.com/openrtb?pub_id=1234",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 320,
+                                        "h": 50
+                                    }
+                                ]
+                            },
+                            "tagid": "123456"
+                        }
+                    ]
+                }
+            },
+
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "mobilefuse",
+                            "bid": [
+                                {
+                                    "id": "test-bid-id",
+                                    "impid": "1",
+                                    "price": 1.50,
+                                    "adm": "some-test-ad",
+                                    "crid": "test-crid",
+                                    "h": 50,
+                                    "w": 320
+                                }
+                            ]
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test-bid-id",
+                        "impid": "1",
+                        "price": 1.50,
+                        "adm": "some-test-ad",
+                        "crid": "test-crid",
+                        "w": 320,
+                        "h": 50
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json b/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json
new file mode 100644
index 00000000..118c82e1
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json
@@ -0,0 +1,96 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "video": {
+                    "mimes": [
+                        "video/mp4"
+                    ],
+                    "protocols": [
+                        2,
+                        5
+                    ],
+                    "w": 320,
+                    "h": 480
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 200000,
+                        "pub_id": 2000
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://mfx-us-east.mobilefuse.com/openrtb?pub_id=2000",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "1",
+                            "video": {
+                                "mimes": [
+                                    "video/mp4"
+                                ],
+                                "protocols": [
+                                    2,
+                                    5
+                                ],
+                                "w": 320,
+                                "h": 480
+                            },
+                            "tagid": "200000"
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "cur": "USD",
+                    "seatbid": [
+                        {
+                            "seat": "mobilefuse",
+                            "bid": [
+                                {
+                                    "id": "test-bid-id",
+                                    "impid": "1",
+                                    "price": 2.50,
+                                    "adm": "some-test-ad",
+                                    "crid": "test-crid",
+                                    "w": 320,
+                                    "h": 480
+                                }
+                            ]
+                        }
+                    ]
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test-bid-id",
+                        "impid": "1",
+                        "price": 2.50,
+                        "adm": "some-test-ad",
+                        "crid": "test-crid",
+                        "w": 320,
+                        "h": 480
+                    },
+                    "type": "video"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/mobilefuse/mobilefusetest/params/race/banner.json b/adapters/mobilefuse/mobilefusetest/params/race/banner.json
new file mode 100644
index 00000000..8c8d3f2b
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/params/race/banner.json
@@ -0,0 +1,5 @@
+{
+    "placement_id": 123456,
+    "pub_id": 1234,
+    "tagid_src": "ext"
+}
diff --git a/adapters/mobilefuse/mobilefusetest/params/race/video.json b/adapters/mobilefuse/mobilefusetest/params/race/video.json
new file mode 100644
index 00000000..8c8d3f2b
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/params/race/video.json
@@ -0,0 +1,5 @@
+{
+    "placement_id": 123456,
+    "pub_id": 1234,
+    "tagid_src": "ext"
+}
diff --git a/adapters/mobilefuse/mobilefusetest/supplemental/bad-ext-bidder.json b/adapters/mobilefuse/mobilefusetest/supplemental/bad-ext-bidder.json
new file mode 100644
index 00000000..61cf115f
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/supplemental/bad-ext-bidder.json
@@ -0,0 +1,36 @@
+{
+    "expectedMakeRequestsErrors": [
+        {
+            "value": "json: cannot unmarshal string into Go value of type openrtb_ext.ExtImpMobileFuse",
+            "comparison": "literal"
+        }
+    ],
+
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": "aaa"
+                }
+            }
+        ]
+    },
+
+    "httpCalls": [],
+
+    "expectedBidResponses": []
+}
diff --git a/adapters/mobilefuse/mobilefusetest/supplemental/bad-ext.json b/adapters/mobilefuse/mobilefusetest/supplemental/bad-ext.json
new file mode 100644
index 00000000..f0c23aa2
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/supplemental/bad-ext.json
@@ -0,0 +1,32 @@
+{
+    "expectedMakeRequestsErrors": [
+        {
+            "value": "json: cannot unmarshal string into Go value of type adapters.ExtImpBidder",
+            "comparison": "literal"
+        }
+    ],
+
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": "aaa"
+            }
+        ]
+    },
+
+    "httpCalls": []
+}
diff --git a/adapters/mobilefuse/mobilefusetest/supplemental/bad-status-code.json b/adapters/mobilefuse/mobilefusetest/supplemental/bad-status-code.json
new file mode 100644
index 00000000..5ee94680
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/supplemental/bad-status-code.json
@@ -0,0 +1,62 @@
+{
+    "expectedMakeBidsErrors": [
+        {
+            "value": "Unexpected status code: 400.",
+            "comparison": "literal"
+        }
+    ],
+
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 999999,
+                        "pub_id": 1111
+                    }
+                }
+            }
+        ]
+    },
+
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://mfx-us-east.mobilefuse.com/openrtb?pub_id=1111",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ]
+                            },
+                            "tagid": "999999"
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 400,
+                "body": ""
+            }
+        }
+    ],
+
+    "expectedBidResponses": []
+}
diff --git a/adapters/mobilefuse/mobilefusetest/supplemental/no-imps.json b/adapters/mobilefuse/mobilefusetest/supplemental/no-imps.json
new file mode 100644
index 00000000..eab96d4d
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/supplemental/no-imps.json
@@ -0,0 +1,27 @@
+{
+    "expectedMakeRequestsErrors": [
+        {
+            "value": "No valid imps",
+            "comparison": "literal"
+        }
+    ],
+
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "ext": {
+                    "bidder": {
+                        "placement_id": 999999,
+                        "pub_id": 1111
+                    }
+                }
+            }
+        ]
+    },
+
+    "httpCalls": [],
+
+    "expectedBidResponses": []
+}
diff --git a/adapters/mobilefuse/mobilefusetest/supplemental/server-error-response.json b/adapters/mobilefuse/mobilefusetest/supplemental/server-error-response.json
new file mode 100644
index 00000000..25c4a0bd
--- /dev/null
+++ b/adapters/mobilefuse/mobilefusetest/supplemental/server-error-response.json
@@ -0,0 +1,62 @@
+{
+    "expectedMakeBidsErrors": [
+        {
+            "value": "Unexpected status code: 500.",
+            "comparison": "literal"
+        }
+    ],
+
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "1",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placement_id": 999999,
+                        "pub_id": 1111
+                    }
+                }
+            }
+        ]
+    },
+
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://mfx-us-east.mobilefuse.com/openrtb?pub_id=1111",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "1",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ]
+                            },
+                            "tagid": "999999"
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 500,
+                "body": ""
+            }
+        }
+    ],
+
+    "expectedBidResponses": []
+}
diff --git a/adapters/mobilefuse/params_test.go b/adapters/mobilefuse/params_test.go
new file mode 100644
index 00000000..dbfd8894
--- /dev/null
+++ b/adapters/mobilefuse/params_test.go
@@ -0,0 +1,54 @@
+package mobilefuse
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestValidParams(test *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+
+	if err != nil {
+		test.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		err := validator.Validate(openrtb_ext.BidderMobileFuse, json.RawMessage(validParam))
+
+		if err != nil {
+			test.Errorf("Schema rejected MobileFuse params: %s\nError: %v", validParam, err)
+		}
+	}
+}
+
+func TestInvalidParams(test *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+
+	if err != nil {
+		test.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		err := validator.Validate(openrtb_ext.BidderMobileFuse, json.RawMessage(invalidParam))
+
+		if err == nil {
+			test.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"placement_id":123,"pub_id":456}`,
+	`{"placement_id":123,"pub_id":456,"tagid_src":"ext"}`,
+	`{"placement_id":123, "pub_id":456, "tagid_src":""}`,
+}
+
+var invalidParams = []string{
+	`{"placement_id":123}`,
+	`{"pub_id":456}`,
+	`{"placement_id":"123","pub_id":"456"}`,
+	`{"placement_id":123, "placementId":123}`,
+	`{"tagid_src":"ext"}`,
+}
diff --git a/adapters/visx/visxtest/exemplary/simple-banner.json b/adapters/visx/visxtest/exemplary/simple-banner.json
index d4c4ea73..2840521c 100644
--- a/adapters/visx/visxtest/exemplary/simple-banner.json
+++ b/adapters/visx/visxtest/exemplary/simple-banner.json
@@ -77,6 +77,7 @@
                         "amp": 0
                     }
                 },
+                "cur": ["USD"],
                 "imp": [{
                     "id": "test-imp-id",
                     "banner": {
@@ -131,21 +132,21 @@
         "mockResponse": {
             "status": 200,
             "body": {
-                "id": "1519967420713_259406708_583019428",
+                "cur": ["USD"],
                 "seatbid": [
                     {
                         "bid": [
                             {
+                                "crid": "2_260",
                                 "price": 0.500000,
                                 "adm": "some-test-ad",
-                                "impid": "1",
+                                "impid": "test-imp-id",
                                 "auid": 46,
-                                "id": "1",
                                 "h": 250,
                                 "adomain": [
                                     "goodadvertiser.com"
                                 ],
-                                "crid": "11_222222",
+                                "dealid": "test_deal_id",
                                 "w": 300
                             }
                         ],
@@ -157,17 +158,19 @@
     }],
 
     "expectedBidResponses": [{
+        "currency": "USD",
         "bids": [{
             "bid": {
                 "price": 0.5,
                 "adm": "some-test-ad",
-                "impid": "1",
-                "id": "1",
+                "impid": "test-imp-id",
+                "id": "test-request-id",
                 "h": 250,
                 "adomain": [
                     "goodadvertiser.com"
                 ],
-                "crid": "11_222222",
+                "dealid": "test_deal_id",
+                "crid": "2_260",
                 "w": 300
             },
             "type": "banner"
diff --git a/adapters/visx/visxtest/exemplary/with_currency.json b/adapters/visx/visxtest/exemplary/with_currency.json
new file mode 100644
index 00000000..ce7c9283
--- /dev/null
+++ b/adapters/visx/visxtest/exemplary/with_currency.json
@@ -0,0 +1,94 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "site": {
+            "page": "https://good.site/url"
+        },
+        "cur": ["EUR"],
+        "imp": [{
+            "id": "test-imp-id",
+            "banner": {
+                "format": [{
+                    "w": 300,
+                    "h": 250
+                }]
+            },
+            "ext": {
+                "bidder": {
+                    "uid": 7
+                }
+            }
+        }]
+    },
+
+    "httpCalls": [{
+        "expectedRequest": {
+            "uri": "http://localhost/prebid",
+            "body": {
+                "id": "test-request-id",
+                "site": {
+                    "page": "https://good.site/url"
+                },
+                "cur": ["EUR"],
+                "imp": [{
+                    "id": "test-imp-id",
+                    "banner": {
+                        "format": [{
+                            "w": 300,
+                            "h": 250
+                        }]
+                    },
+                    "ext": {
+                        "bidder": {
+                            "uid": 7
+                        }
+                    }
+                }]
+            }
+        },
+        "mockResponse": {
+            "status": 200,
+            "body": {
+                "cur": ["EUR"],
+                "seatbid": [
+                    {
+                        "bid": [
+                            {
+                                "crid": "2_261",
+                                "price": 0.500000,
+                                "adm": "some-test-ad",
+                                "impid": "test-imp-id",
+                                "auid": 46,
+                                "h": 250,
+                                "adomain": [
+                                    "goodadvertiser.com"
+                                ],
+                                "w": 300
+                            }
+                        ],
+                        "seat": "51"
+                    }
+                ]
+            }
+        }
+    }],
+
+    "expectedBidResponses": [{
+        "currency": "EUR",
+        "bids": [{
+            "bid": {
+                "price": 0.5,
+                "adm": "some-test-ad",
+                "impid": "test-imp-id",
+                "id": "test-request-id",
+                "h": 250,
+                "adomain": [
+                    "goodadvertiser.com"
+                ],
+                "crid": "2_261",
+                "w": 300
+            },
+            "type": "banner"
+        }]
+    }]
+}
diff --git a/adapters/visx/visxtest/supplemental/bad_response.json b/adapters/visx/visxtest/supplemental/bad_response.json
index 4ad5c09c..09376f94 100644
--- a/adapters/visx/visxtest/supplemental/bad_response.json
+++ b/adapters/visx/visxtest/supplemental/bad_response.json
@@ -26,6 +26,7 @@
         "uri": "http://localhost/prebid",
         "body": {
           "id": "test-request-id",
+          "cur": ["USD"],
           "imp": [
             {
               "id": "test-imp-id",
@@ -54,7 +55,7 @@
 
   "expectedMakeBidsErrors": [
     {
-      "value": "json: cannot unmarshal string into Go value of type openrtb.BidResponse",
+      "value": "json: cannot unmarshal string into Go value of type visx.visxResponse",
       "comparison": "literal"
     }
   ]
diff --git a/adapters/visx/visxtest/supplemental/status_204.json b/adapters/visx/visxtest/supplemental/status_204.json
index 906d8553..7e0899d9 100644
--- a/adapters/visx/visxtest/supplemental/status_204.json
+++ b/adapters/visx/visxtest/supplemental/status_204.json
@@ -26,6 +26,7 @@
         "uri": "http://localhost/prebid",
         "body": {
           "id": "test-request-id",
+          "cur": ["USD"],
           "imp": [
             {
               "id": "test-imp-id",
diff --git a/adapters/visx/visxtest/supplemental/status_400.json b/adapters/visx/visxtest/supplemental/status_400.json
index dbf2a4d7..82903ca9 100644
--- a/adapters/visx/visxtest/supplemental/status_400.json
+++ b/adapters/visx/visxtest/supplemental/status_400.json
@@ -26,6 +26,7 @@
         "uri": "http://localhost/prebid",
         "body": {
           "id": "test-request-id",
+          "cur": ["USD"],
           "imp": [
             {
               "id": "test-imp-id",
diff --git a/adapters/visx/visxtest/supplemental/status_418.json b/adapters/visx/visxtest/supplemental/status_418.json
index 7619cd6a..86ecf8b0 100644
--- a/adapters/visx/visxtest/supplemental/status_418.json
+++ b/adapters/visx/visxtest/supplemental/status_418.json
@@ -26,6 +26,7 @@
         "uri": "http://localhost/prebid",
         "body": {
           "id": "test-request-id",
+          "cur": ["USD"],
           "imp": [
             {
               "id": "test-imp-id",
diff --git a/endpoints/auction_test.go b/endpoints/auction_test.go
index df91f8ca..3035a6d4 100644
--- a/endpoints/auction_test.go
+++ b/endpoints/auction_test.go
@@ -421,6 +421,10 @@ func (m *auctionMockPermissions) PersonalInfoAllowed(ctx context.Context, bidder
 	return m.allowPI, nil
 }
 
+func (m *auctionMockPermissions) AMPException() bool {
+	return false
+}
+
 func TestBidSizeValidate(t *testing.T) {
 	bids := make(pbs.PBSBidSlice, 0)
 	// bid1 will be rejected due to undefined size when adunit has multiple sizes
diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go
index 011cecf3..bb766aa9 100644
--- a/endpoints/cookie_sync_test.go
+++ b/endpoints/cookie_sync_test.go
@@ -257,3 +257,7 @@ func (g *gdprPerms) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.Bi
 func (g *gdprPerms) PersonalInfoAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, consent string) (bool, error) {
 	return true, nil
 }
+
+func (g *gdprPerms) AMPException() bool {
+	return false
+}
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index 98dfa66d..fdd6b3a4 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -602,7 +602,7 @@ func TestStoredRequests(t *testing.T) {
 	// NewMetrics() will create a new go_metrics MetricsEngine, bypassing the need for a crafted configuration set to support it.
 	// As a side effect this gives us some coverage of the go_metrics piece of the metrics engine.
 	theMetrics := pbsmetrics.NewMetrics(metrics.NewRegistry(), openrtb_ext.BidderList(), config.DisabledMetrics{})
-	edep := &endpointDeps{&nobidExchange{}, newParamsValidator(t), &mockStoredReqFetcher{}, empty_fetcher.EmptyFetcher{}, empty_fetcher.EmptyFetcher{}, &config.Configuration{MaxRequestSize: maxSize}, theMetrics, analyticsConf.NewPBSAnalytics(&config.Analytics{}), map[string]string{}, false, []byte{}, openrtb_ext.BidderMap, nil}
+	edep := &endpointDeps{&nobidExchange{}, newParamsValidator(t), &mockStoredReqFetcher{}, empty_fetcher.EmptyFetcher{}, empty_fetcher.EmptyFetcher{}, &config.Configuration{MaxRequestSize: maxSize}, theMetrics, analyticsConf.NewPBSAnalytics(&config.Analytics{}), map[string]string{}, false, []byte{}, openrtb_ext.BidderMap, nil, nil}
 
 	for i, requestData := range testStoredRequests {
 		newRequest, errList := edep.processStoredRequests(context.Background(), json.RawMessage(requestData))
@@ -639,6 +639,7 @@ func TestOversizedRequest(t *testing.T) {
 		[]byte{},
 		openrtb_ext.BidderMap,
 		nil,
+		nil,
 	}
 
 	req := httptest.NewRequest("POST", "/openrtb2/auction", strings.NewReader(reqBody))
@@ -672,6 +673,7 @@ func TestRequestSizeEdgeCase(t *testing.T) {
 		[]byte{},
 		openrtb_ext.BidderMap,
 		nil,
+		nil,
 	}
 
 	req := httptest.NewRequest("POST", "/openrtb2/auction", strings.NewReader(reqBody))
@@ -810,6 +812,7 @@ func TestDisabledBidder(t *testing.T) {
 		[]byte{},
 		openrtb_ext.BidderMap,
 		nil,
+		nil,
 	}
 
 	req := httptest.NewRequest("POST", "/openrtb2/auction", strings.NewReader(reqBody))
@@ -844,6 +847,7 @@ func TestValidateImpExtDisabledBidder(t *testing.T) {
 		[]byte{},
 		openrtb_ext.BidderMap,
 		nil,
+		nil,
 	}
 	errs := deps.validateImpExt(imp, nil, 0)
 	assert.JSONEq(t, `{"appnexus":{"placement_id":555}}`, string(imp.Ext))
@@ -883,6 +887,7 @@ func TestCurrencyTrunc(t *testing.T) {
 		[]byte{},
 		openrtb_ext.BidderMap,
 		nil,
+		nil,
 	}
 
 	ui := uint64(1)
@@ -925,6 +930,7 @@ func TestCCPAInvalidValueWarning(t *testing.T) {
 		[]byte{},
 		openrtb_ext.BidderMap,
 		nil,
+		nil,
 	}
 
 	ui := uint64(1)
diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go
index 38c9dc3f..5ba34068 100644
--- a/endpoints/openrtb2/video_auction_test.go
+++ b/endpoints/openrtb2/video_auction_test.go
@@ -7,6 +7,7 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
+	"regexp"
 	"strings"
 	"testing"
 
@@ -989,10 +990,15 @@ func TestHandleErrorDebugLog(t *testing.T) {
 	err1 := errors.New("Error for testing handleError 1")
 	err2 := errors.New("Error for testing handleError 2")
 	debugLog := exchange.DebugLog{
-		EnableDebug: true,
-		CacheType:   prebid_cache_client.TypeXML,
-		Data:        "test debug data",
-		TTL:         int64(3600),
+		Enabled:   true,
+		CacheType: prebid_cache_client.TypeXML,
+		Data: exchange.DebugData{
+			Request:  "test request string",
+			Headers:  "test headers string",
+			Response: "test response string",
+		},
+		TTL:    int64(3600),
+		Regexp: regexp.MustCompile(`[<>]`),
 	}
 	handleError(&labels, recorder, []error{err1, err2}, &vo, &debugLog)
 
@@ -1047,6 +1053,7 @@ func mockDepsWithMetrics(t *testing.T, ex *mockExchangeVideo) (*endpointDeps, *p
 		[]byte{},
 		openrtb_ext.BidderMap,
 		nil,
+		nil,
 	}
 
 	return edep, theMetrics, mockModule
@@ -1087,6 +1094,7 @@ func mockDeps(t *testing.T, ex *mockExchangeVideo) *endpointDeps {
 		[]byte{},
 		openrtb_ext.BidderMap,
 		ex.cache,
+		regexp.MustCompile(`[<>]`),
 	}
 
 	return edep
@@ -1121,7 +1129,7 @@ type mockExchangeVideo struct {
 
 func (m *mockExchangeVideo) HoldAuction(ctx context.Context, bidRequest *openrtb.BidRequest, ids exchange.IdFetcher, labels pbsmetrics.Labels, categoriesFetcher *stored_requests.CategoryFetcher, debugLog *exchange.DebugLog) (*openrtb.BidResponse, error) {
 	m.lastRequest = bidRequest
-	if debugLog != nil && debugLog.EnableDebug {
+	if debugLog != nil && debugLog.Enabled {
 		m.cache.called = true
 	}
 	ext := []byte(`{"prebid":{"targeting":{"hb_bidder":"appnexus","hb_pb":"20.00","hb_pb_cat_dur":"20.00_395_30s","hb_size":"1x1", "hb_uuid":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"},"type":"video"},"bidder":{"appnexus":{"brand_id":1,"auction_id":7840037870526938650,"bidder_id":2,"bid_ad_type":1,"creative_info":{"video":{"duration":30,"mimes":["video\/mp4"]}}}}}`)
diff --git a/endpoints/setuid_test.go b/endpoints/setuid_test.go
index 555f6173..8499ac1c 100644
--- a/endpoints/setuid_test.go
+++ b/endpoints/setuid_test.go
@@ -441,6 +441,10 @@ func (g *mockPermsSetUID) PersonalInfoAllowed(ctx context.Context, bidder openrt
 	return g.allowPI, nil
 }
 
+func (g *mockPermsSetUID) AMPException() bool {
+	return false
+}
+
 func newFakeSyncer(familyName string) usersync.Usersyncer {
 	return fakeSyncer{
 		familyName: familyName,
diff --git a/exchange/auction_test.go b/exchange/auction_test.go
index d23ff03e..e23c45cb 100644
--- a/exchange/auction_test.go
+++ b/exchange/auction_test.go
@@ -3,8 +3,10 @@ package exchange
 import (
 	"context"
 	"encoding/json"
+	"encoding/xml"
 	"fmt"
 	"io/ioutil"
+	"regexp"
 	"strconv"
 	"strings"
 	"testing"
@@ -40,6 +42,61 @@ func TestMakeVASTNurl(t *testing.T) {
 	assert.Equal(t, expect, vast)
 }
 
+func TestBuildCacheString(t *testing.T) {
+	testCases := []struct {
+		description      string
+		debugLog         DebugLog
+		expectedDebugLog DebugLog
+	}{
+		{
+			description: "DebugLog strings should have tags and be formatted",
+			debugLog: DebugLog{
+				Data: DebugData{
+					Request:  "test request string",
+					Headers:  "test headers string",
+					Response: "test response string",
+				},
+				Regexp: regexp.MustCompile(`[<>]`),
+			},
+			expectedDebugLog: DebugLog{
+				Data: DebugData{
+					Request:  "<Request>test request string</Request>",
+					Headers:  "<Headers>test headers string</Headers>",
+					Response: "<Response>test response string</Response>",
+				},
+				Regexp: regexp.MustCompile(`[<>]`),
+			},
+		},
+		{
+			description: "DebugLog strings should have no < or > characters",
+			debugLog: DebugLog{
+				Data: DebugData{
+					Request:  "<test>test request string</test>",
+					Headers:  "test <headers string",
+					Response: "test <response> string",
+				},
+				Regexp: regexp.MustCompile(`[<>]`),
+			},
+			expectedDebugLog: DebugLog{
+				Data: DebugData{
+					Request:  "<Request>testtest request string/test</Request>",
+					Headers:  "<Headers>test headers string</Headers>",
+					Response: "<Response>test response string</Response>",
+				},
+				Regexp: regexp.MustCompile(`[<>]`),
+			},
+		},
+	}
+
+	for _, test := range testCases {
+		test.expectedDebugLog.CacheString = fmt.Sprintf("%s<Log>%s%s%s</Log>", xml.Header, test.expectedDebugLog.Data.Request, test.expectedDebugLog.Data.Headers, test.expectedDebugLog.Data.Response)
+
+		test.debugLog.BuildCacheString()
+
+		assert.Equal(t, test.expectedDebugLog, test.debugLog, test.description)
+	}
+}
+
 // TestCacheJSON executes tests for all the *.json files in cachetest.
 // customcachekey.json test here verifies custom cache key not used for non-vast video
 func TestCacheJSON(t *testing.T) {
diff --git a/exchange/cachetest/debuglog_disabled.json b/exchange/cachetest/debuglog_disabled.json
index 675488c0..88d6332c 100644
--- a/exchange/cachetest/debuglog_disabled.json
+++ b/exchange/cachetest/debuglog_disabled.json
@@ -1,9 +1,13 @@
 {
     "debugLog": {
-        "EnableDebug": false,
+        "Enabled": false,
         "CacheType": "xml",
         "TTL": 3600,
-        "Data": "test debug data"
+        "Data": {
+            "Request": "test request string",
+            "Headers": "test headers string",
+            "Response": "test response string"
+        }
     },
     "bidRequest": {
         "imp": [{
diff --git a/exchange/cachetest/debuglog_enabled.json b/exchange/cachetest/debuglog_enabled.json
index d4486558..670b694f 100644
--- a/exchange/cachetest/debuglog_enabled.json
+++ b/exchange/cachetest/debuglog_enabled.json
@@ -1,9 +1,13 @@
 {    
     "debugLog": {
-        "EnableDebug": true,
+        "Enabled": true,
         "CacheType": "xml",
         "TTL": 3600,
-        "Data": "test debug data"
+        "Data": {
+            "Request": "test request string",
+            "Headers": "test headers string",
+            "Response": "test response string"
+        }
     },
     "bidRequest": {
         "imp": [{
@@ -42,7 +46,7 @@
         }, {
             "Type": "xml",
             "TTLSeconds": 3600,
-            "Data": "test debug data"
+            "Data": "\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cLog\u003e\u003cRequest\u003etest request string\u003c/Request\u003e\u003cHeaders\u003etest headers string\u003c/Headers\u003e\u003cResponse\u003etest response string\u003c/Response\u003e\u003c/Log\u003e"
         }
     ],
     "defaultTTLs": {
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 3c1c2f3b..e9b2127e 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -740,6 +740,7 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) {
 	debugLog := &DebugLog{}
 	if spec.DebugLog != nil {
 		*debugLog = *spec.DebugLog
+		debugLog.Regexp = regexp.MustCompile(`[<>]`)
 	}
 	bid, err := ex.HoldAuction(context.Background(), &spec.IncomingRequest.OrtbRequest, mockIdFetcher(spec.IncomingRequest.Usersyncs), pbsmetrics.Labels{}, &categoriesFetcher, debugLog)
 	responseTimes := extractResponseTimes(t, filename, bid)
@@ -761,13 +762,13 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) {
 		}
 	}
 	if spec.DebugLog != nil {
-		if spec.DebugLog.EnableDebug {
-			if len(debugLog.Data) <= len(spec.DebugLog.Data) {
-				t.Errorf("%s: DebugLog was not modified when it should have been", filename)
+		if spec.DebugLog.Enabled {
+			if len(debugLog.Data.Response) == 0 {
+				t.Errorf("%s: DebugLog response was not modified when it should have been", filename)
 			}
 		} else {
-			if !strings.EqualFold(spec.DebugLog.Data, debugLog.Data) {
-				t.Errorf("%s: DebugLog was modified when it shouldn't have been", filename)
+			if len(debugLog.Data.Response) != 0 {
+				t.Errorf("%s: DebugLog response was modified when it shouldn't have been", filename)
 			}
 		}
 	}
diff --git a/exchange/exchangetest/debuglog_disabled.json b/exchange/exchangetest/debuglog_disabled.json
index 0c24c121..3dd04f66 100644
--- a/exchange/exchangetest/debuglog_disabled.json
+++ b/exchange/exchangetest/debuglog_disabled.json
@@ -1,161 +1,230 @@
 {
-    "debugLog": {
-        "EnableDebug": false,
-        "CacheType": "xml",
-        "TTL": 3600,
-        "Data": "test debug data"
-    },
-    "incomingRequest": {
-      "ortbRequest": {
-        "id": "some-request-id",
-        "site": {
-          "page": "test.somepage.com"
-        },
-        "imp": [
-          {
-            "id": "my-imp-id",
-            "video": {
-              "mimes": ["video/mp4"]
-            },
-            "ext": {
-              "appnexus": {
-                "placementId": 1
-              }
-            }
+  "debugLog": {
+    "Enabled": false,
+    "CacheType": "xml",
+    "TTL": 3600,
+    "Data": {
+      "Request": "test request string",
+      "Headers": "test headers string",
+      "Response": ""
+    }
+  },
+  "incomingRequest": {
+    "ortbRequest": {
+      "id": "some-request-id",
+      "site": {
+        "page": "test.somepage.com"
+      },
+      "imp": [
+        {
+          "id": "my-imp-id",
+          "video": {
+            "mimes": [
+              "video/mp4"
+            ]
           },
-          {
-            "id": "imp-id-2",
-            "video": {
-              "mimes": ["video/mp4"]
-            },
-            "ext": {
-              "appnexus": {
-                "placementId": 1
-              }
+          "ext": {
+            "appnexus": {
+              "placementId": 1
             }
           }
-        ],
-        "ext": {
-          "prebid": {
-            "targeting": {
-              "includebrandcategory": {
-                "primaryadserver": 1,
-                "publisher":"",
-                "withcategory": true
-              }
+        },
+        {
+          "id": "imp-id-2",
+          "video": {
+            "mimes": [
+              "video/mp4"
+            ]
+          },
+          "ext": {
+            "appnexus": {
+              "placementId": 1
             }
           }
         }
-      },
-      "usersyncs": {
-        "appnexus": "123"
-      }
-    },
-    "outgoingRequests": {
-      "appnexus": {
-        "mockResponse": {
-          "pbsSeatBid": {
-            "pbsBids": [
-              {
-                "ortbBid": {
-                  "id": "apn-bid",
-                  "impid": "my-imp-id",
-                  "price": 0.3,
-                  "w": 200,
-                  "h": 250,
-                  "crid": "creative-1",
-                  "cat": ["IAB1-1"]
-                },
-                "bidType": "video",
-                "bidVideo": {
-                  "duration": 30,
-                  "PrimaryCategory": ""
-                }
-              },
-              {
-                "ortbBid": {
-                  "id": "apn-other-bid",
-                  "impid": "imp-id-2",
-                  "price": 0.6,
-                  "w": 300,
-                  "h": 500,
-                  "crid": "creative-3",
-                  "cat": ["IAB1-2"]
-                },
-                "bidType": "video"
-              }
-            ]
+      ],
+      "test": 1,
+      "ext": {
+        "prebid": {
+          "targeting": {
+            "includebrandcategory": {
+              "primaryadserver": 1,
+              "publisher": "",
+              "withcategory": true
+            }
           }
         }
       }
     },
-    "response": {
-      "bids": {
-        "id": "some-request-id",
-        "seatbid": [
-          {
-            "seat": "appnexus",
-            "bid": [
-              {
+    "usersyncs": {
+      "appnexus": "123"
+    }
+  },
+  "outgoingRequests": {
+    "appnexus": {
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
                 "id": "apn-bid",
                 "impid": "my-imp-id",
                 "price": 0.3,
                 "w": 200,
                 "h": 250,
                 "crid": "creative-1",
-                "cat": ["IAB1-1"],
-                "ext": {
-                  "prebid": {
-                    "type": "video",
-                    "targeting": {
-                       "hb_bidder": "appnexus",
-                       "hb_bidder_appnexus": "appnexus",
-                       "hb_cache_host": "www.pbcserver.com",
-                       "hb_cache_host_appnex": "www.pbcserver.com",
-                       "hb_cache_path": "/pbcache/endpoint",
-                       "hb_cache_path_appnex": "/pbcache/endpoint",
-                       "hb_pb": "0.20",
-                       "hb_pb_appnexus": "0.20",
-                       "hb_pb_cat_dur": "0.20_VideoGames_0s",
-                       "hb_pb_cat_dur_appnex": "0.20_VideoGames_0s",
-                       "hb_size": "200x250",
-                       "hb_size_appnexus": "200x250"
-                     }
-                  }
-                }
+                "cat": [
+                  "IAB1-1"
+                ]
               },
-              {
-                "cat": ["IAB1-2"],
-                "crid": "creative-3",
-                "ext": {
-                  "prebid": {
-                    "targeting": {
-                        "hb_bidder": "appnexus",
-                        "hb_bidder_appnexus": "appnexus",
-                        "hb_cache_host": "www.pbcserver.com",
-                        "hb_cache_host_appnex": "www.pbcserver.com",
-                        "hb_cache_path": "/pbcache/endpoint",
-                        "hb_cache_path_appnex": "/pbcache/endpoint",
-                        "hb_pb": "0.50",
-                        "hb_pb_appnexus": "0.50",
-                        "hb_pb_cat_dur": "0.50_HomeDecor_0s",
-                        "hb_pb_cat_dur_appnex": "0.50_HomeDecor_0s",
-                        "hb_size": "300x500",
-                        "hb_size_appnexus": "300x500"
-                      },
-                    "type": "video"
-                  }
-                },
-                "h": 500,
+              "bidType": "video",
+              "bidVideo": {
+                "duration": 30,
+                "PrimaryCategory": ""
+              }
+            },
+            {
+              "ortbBid": {
                 "id": "apn-other-bid",
                 "impid": "imp-id-2",
                 "price": 0.6,
-                "w": 300
+                "w": 300,
+                "h": 500,
+                "crid": "creative-3",
+                "cat": [
+                  "IAB1-2"
+                ]
+              },
+              "bidType": "video"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "response": {
+    "bids": {
+      "id": "some-request-id",
+      "seatbid": [
+        {
+          "seat": "appnexus",
+          "bid": [
+            {
+              "id": "apn-bid",
+              "impid": "my-imp-id",
+              "price": 0.3,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-1",
+              "cat": [
+                "IAB1-1"
+              ],
+              "ext": {
+                "prebid": {
+                  "type": "video",
+                  "targeting": {
+                    "hb_bidder": "appnexus",
+                    "hb_bidder_appnexus": "appnexus",
+                    "hb_cache_host": "www.pbcserver.com",
+                    "hb_cache_host_appnex": "www.pbcserver.com",
+                    "hb_cache_path": "/pbcache/endpoint",
+                    "hb_cache_path_appnex": "/pbcache/endpoint",
+                    "hb_pb": "0.20",
+                    "hb_pb_appnexus": "0.20",
+                    "hb_pb_cat_dur": "0.20_VideoGames_0s",
+                    "hb_pb_cat_dur_appnex": "0.20_VideoGames_0s",
+                    "hb_size": "200x250",
+                    "hb_size_appnexus": "200x250"
+                  }
+                }
               }
-            ]
+            },
+            {
+              "cat": [
+                "IAB1-2"
+              ],
+              "crid": "creative-3",
+              "ext": {
+                "prebid": {
+                  "targeting": {
+                    "hb_bidder": "appnexus",
+                    "hb_bidder_appnexus": "appnexus",
+                    "hb_cache_host": "www.pbcserver.com",
+                    "hb_cache_host_appnex": "www.pbcserver.com",
+                    "hb_cache_path": "/pbcache/endpoint",
+                    "hb_cache_path_appnex": "/pbcache/endpoint",
+                    "hb_pb": "0.50",
+                    "hb_pb_appnexus": "0.50",
+                    "hb_pb_cat_dur": "0.50_HomeDecor_0s",
+                    "hb_pb_cat_dur_appnex": "0.50_HomeDecor_0s",
+                    "hb_size": "300x500",
+                    "hb_size_appnexus": "300x500"
+                  },
+                  "type": "video"
+                }
+              },
+              "h": 500,
+              "id": "apn-other-bid",
+              "impid": "imp-id-2",
+              "price": 0.6,
+              "w": 300
+            }
+          ]
+        }
+      ]
+    },
+    "ext": {
+      "debug": {
+        "httpcalls": {
+          "appnexus": null
+        },
+        "resolvedrequest": {
+          "id": "some-request-id",
+          "imp": [
+            {
+              "id": "my-imp-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "appnexus": {
+                  "placementId": 1
+                }
+              }
+            },
+            {
+              "id": "imp-id-2",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "appnexus": {
+                  "placementId": 1
+                }
+              }
+            }
+          ],
+          "site": {
+            "page": "test.somepage.com"
+          },
+          "test": 1,
+          "ext": {
+            "prebid": {
+              "targeting": {
+                "includebrandcategory": {
+                  "primaryadserver": 1,
+                  "publisher": "",
+                  "withcategory": true
+                }
+              }
+            }
           }
-        ]
+        }
       }
     }
   }
-  
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/exchange/exchangetest/debuglog_enabled.json b/exchange/exchangetest/debuglog_enabled.json
index 281bf3a1..a70013b4 100644
--- a/exchange/exchangetest/debuglog_enabled.json
+++ b/exchange/exchangetest/debuglog_enabled.json
@@ -1,161 +1,230 @@
 {
-    "debugLog": {
-        "EnableDebug": true,
-        "CacheType": "xml",
-        "TTL": 3600,
-        "Data": "test debug data"
-    },
-    "incomingRequest": {
-      "ortbRequest": {
-        "id": "some-request-id",
-        "site": {
-          "page": "test.somepage.com"
-        },
-        "imp": [
-          {
-            "id": "my-imp-id",
-            "video": {
-              "mimes": ["video/mp4"]
-            },
-            "ext": {
-              "appnexus": {
-                "placementId": 1
-              }
-            }
+  "debugLog": {
+    "Enabled": true,
+    "CacheType": "xml",
+    "TTL": 3600,
+    "Data": {
+      "Request": "test request string",
+      "Headers": "test headers string",
+      "Response": ""
+    }
+  },
+  "incomingRequest": {
+    "ortbRequest": {
+      "id": "some-request-id",
+      "site": {
+        "page": "test.somepage.com"
+      },
+      "imp": [
+        {
+          "id": "my-imp-id",
+          "video": {
+            "mimes": [
+              "video/mp4"
+            ]
           },
-          {
-            "id": "imp-id-2",
-            "video": {
-              "mimes": ["video/mp4"]
-            },
-            "ext": {
-              "appnexus": {
-                "placementId": 1
-              }
+          "ext": {
+            "appnexus": {
+              "placementId": 1
             }
           }
-        ],
-        "ext": {
-          "prebid": {
-            "targeting": {
-              "includebrandcategory": {
-                "primaryadserver": 1,
-                "publisher":"",
-                "withcategory": true
-              }
+        },
+        {
+          "id": "imp-id-2",
+          "video": {
+            "mimes": [
+              "video/mp4"
+            ]
+          },
+          "ext": {
+            "appnexus": {
+              "placementId": 1
             }
           }
         }
-      },
-      "usersyncs": {
-        "appnexus": "123"
-      }
-    },
-    "outgoingRequests": {
-      "appnexus": {
-        "mockResponse": {
-          "pbsSeatBid": {
-            "pbsBids": [
-              {
-                "ortbBid": {
-                  "id": "apn-bid",
-                  "impid": "my-imp-id",
-                  "price": 0.3,
-                  "w": 200,
-                  "h": 250,
-                  "crid": "creative-1",
-                  "cat": ["IAB1-1"]
-                },
-                "bidType": "video",
-                "bidVideo": {
-                  "duration": 30,
-                  "PrimaryCategory": ""
-                }
-              },
-              {
-                "ortbBid": {
-                  "id": "apn-other-bid",
-                  "impid": "imp-id-2",
-                  "price": 0.6,
-                  "w": 300,
-                  "h": 500,
-                  "crid": "creative-3",
-                  "cat": ["IAB1-2"]
-                },
-                "bidType": "video"
-              }
-            ]
+      ],
+      "test": 1,
+      "ext": {
+        "prebid": {
+          "targeting": {
+            "includebrandcategory": {
+              "primaryadserver": 1,
+              "publisher": "",
+              "withcategory": true
+            }
           }
         }
       }
     },
-    "response": {
-      "bids": {
-        "id": "some-request-id",
-        "seatbid": [
-          {
-            "seat": "appnexus",
-            "bid": [
-              {
+    "usersyncs": {
+      "appnexus": "123"
+    }
+  },
+  "outgoingRequests": {
+    "appnexus": {
+      "mockResponse": {
+        "pbsSeatBid": {
+          "pbsBids": [
+            {
+              "ortbBid": {
                 "id": "apn-bid",
                 "impid": "my-imp-id",
                 "price": 0.3,
                 "w": 200,
                 "h": 250,
                 "crid": "creative-1",
-                "cat": ["IAB1-1"],
-                "ext": {
-                  "prebid": {
-                    "type": "video",
-                    "targeting": {
-                       "hb_bidder": "appnexus",
-                       "hb_bidder_appnexus": "appnexus",
-                       "hb_cache_host": "www.pbcserver.com",
-                       "hb_cache_host_appnex": "www.pbcserver.com",
-                       "hb_cache_path": "/pbcache/endpoint",
-                       "hb_cache_path_appnex": "/pbcache/endpoint",
-                       "hb_pb": "0.20",
-                       "hb_pb_appnexus": "0.20",
-                       "hb_pb_cat_dur": "0.20_VideoGames_0s",
-                       "hb_pb_cat_dur_appnex": "0.20_VideoGames_0s",
-                       "hb_size": "200x250",
-                       "hb_size_appnexus": "200x250"
-                     }
-                  }
-                }
+                "cat": [
+                  "IAB1-1"
+                ]
               },
-              {
-                "cat": ["IAB1-2"],
-                "crid": "creative-3",
-                "ext": {
-                  "prebid": {
-                    "targeting": {
-                        "hb_bidder": "appnexus",
-                        "hb_bidder_appnexus": "appnexus",
-                        "hb_cache_host": "www.pbcserver.com",
-                        "hb_cache_host_appnex": "www.pbcserver.com",
-                        "hb_cache_path": "/pbcache/endpoint",
-                        "hb_cache_path_appnex": "/pbcache/endpoint",
-                        "hb_pb": "0.50",
-                        "hb_pb_appnexus": "0.50",
-                        "hb_pb_cat_dur": "0.50_HomeDecor_0s",
-                        "hb_pb_cat_dur_appnex": "0.50_HomeDecor_0s",
-                        "hb_size": "300x500",
-                        "hb_size_appnexus": "300x500"
-                      },
-                    "type": "video"
-                  }
-                },
-                "h": 500,
+              "bidType": "video",
+              "bidVideo": {
+                "duration": 30,
+                "PrimaryCategory": ""
+              }
+            },
+            {
+              "ortbBid": {
                 "id": "apn-other-bid",
                 "impid": "imp-id-2",
                 "price": 0.6,
-                "w": 300
+                "w": 300,
+                "h": 500,
+                "crid": "creative-3",
+                "cat": [
+                  "IAB1-2"
+                ]
+              },
+              "bidType": "video"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "response": {
+    "bids": {
+      "id": "some-request-id",
+      "seatbid": [
+        {
+          "seat": "appnexus",
+          "bid": [
+            {
+              "id": "apn-bid",
+              "impid": "my-imp-id",
+              "price": 0.3,
+              "w": 200,
+              "h": 250,
+              "crid": "creative-1",
+              "cat": [
+                "IAB1-1"
+              ],
+              "ext": {
+                "prebid": {
+                  "type": "video",
+                  "targeting": {
+                    "hb_bidder": "appnexus",
+                    "hb_bidder_appnexus": "appnexus",
+                    "hb_cache_host": "www.pbcserver.com",
+                    "hb_cache_host_appnex": "www.pbcserver.com",
+                    "hb_cache_path": "/pbcache/endpoint",
+                    "hb_cache_path_appnex": "/pbcache/endpoint",
+                    "hb_pb": "0.20",
+                    "hb_pb_appnexus": "0.20",
+                    "hb_pb_cat_dur": "0.20_VideoGames_0s",
+                    "hb_pb_cat_dur_appnex": "0.20_VideoGames_0s",
+                    "hb_size": "200x250",
+                    "hb_size_appnexus": "200x250"
+                  }
+                }
               }
-            ]
+            },
+            {
+              "cat": [
+                "IAB1-2"
+              ],
+              "crid": "creative-3",
+              "ext": {
+                "prebid": {
+                  "targeting": {
+                    "hb_bidder": "appnexus",
+                    "hb_bidder_appnexus": "appnexus",
+                    "hb_cache_host": "www.pbcserver.com",
+                    "hb_cache_host_appnex": "www.pbcserver.com",
+                    "hb_cache_path": "/pbcache/endpoint",
+                    "hb_cache_path_appnex": "/pbcache/endpoint",
+                    "hb_pb": "0.50",
+                    "hb_pb_appnexus": "0.50",
+                    "hb_pb_cat_dur": "0.50_HomeDecor_0s",
+                    "hb_pb_cat_dur_appnex": "0.50_HomeDecor_0s",
+                    "hb_size": "300x500",
+                    "hb_size_appnexus": "300x500"
+                  },
+                  "type": "video"
+                }
+              },
+              "h": 500,
+              "id": "apn-other-bid",
+              "impid": "imp-id-2",
+              "price": 0.6,
+              "w": 300
+            }
+          ]
+        }
+      ]
+    },
+    "ext": {
+      "debug": {
+        "httpcalls": {
+          "appnexus": null
+        },
+        "resolvedrequest": {
+          "id": "some-request-id",
+          "imp": [
+            {
+              "id": "my-imp-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "appnexus": {
+                  "placementId": 1
+                }
+              }
+            },
+            {
+              "id": "imp-id-2",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "appnexus": {
+                  "placementId": 1
+                }
+              }
+            }
+          ],
+          "site": {
+            "page": "test.somepage.com"
+          },
+          "test": 1,
+          "ext": {
+            "prebid": {
+              "targeting": {
+                "includebrandcategory": {
+                  "primaryadserver": 1,
+                  "publisher": "",
+                  "withcategory": true
+                }
+              }
+            }
           }
-        ]
+        }
       }
     }
   }
-  
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index edbe04a0..53d6b85c 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -31,6 +31,10 @@ func (p *permissionsMock) PersonalInfoAllowed(ctx context.Context, bidder openrt
 	return false, nil
 }
 
+func (p *permissionsMock) AMPException() bool {
+	return false
+}
+
 func assertReq(t *testing.T, reqByBidders map[openrtb_ext.BidderName]*openrtb.BidRequest,
 	applyCOPPA bool, consentedVendors map[string]bool) {
 	// assert individual bidder requests
diff --git a/privacy/enforcement_test.go b/privacy/enforcement_test.go
index c7433f8b..25e08b5e 100644
--- a/privacy/enforcement_test.go
+++ b/privacy/enforcement_test.go
@@ -51,12 +51,13 @@ func TestAny(t *testing.T) {
 
 func TestApply(t *testing.T) {
 	testCases := []struct {
-		description             string
-		enforcement             Enforcement
-		expectedDeviceIPv6      ScrubStrategyIPV6
-		expectedDeviceGeo       ScrubStrategyGeo
-		expectedUserDemographic ScrubStrategyDemographic
-		expectedUserGeo         ScrubStrategyGeo
+		description        string
+		enforcement        Enforcement
+		ampGDPRException   bool
+		expectedDeviceIPv6 ScrubStrategyIPV6
+		expectedDeviceGeo  ScrubStrategyGeo
+		expectedUser       ScrubStrategyUser
+		expectedUserGeo    ScrubStrategyGeo
 	}{
 		{
 			description: "All Enforced",
@@ -65,10 +66,11 @@ func TestApply(t *testing.T) {
 				COPPA: true,
 				GDPR:  true,
 			},
-			expectedDeviceIPv6:      ScrubStrategyIPV6Lowest32,
-			expectedDeviceGeo:       ScrubStrategyGeoFull,
-			expectedUserDemographic: ScrubStrategyDemographicAgeAndGender,
-			expectedUserGeo:         ScrubStrategyGeoFull,
+			ampGDPRException:   false,
+			expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
+			expectedDeviceGeo:  ScrubStrategyGeoFull,
+			expectedUser:       ScrubStrategyUserIDAndDemographic,
+			expectedUserGeo:    ScrubStrategyGeoFull,
 		},
 		{
 			description: "CCPA Only",
@@ -77,10 +79,11 @@ func TestApply(t *testing.T) {
 				COPPA: false,
 				GDPR:  false,
 			},
-			expectedDeviceIPv6:      ScrubStrategyIPV6Lowest16,
-			expectedDeviceGeo:       ScrubStrategyGeoReducedPrecision,
-			expectedUserDemographic: ScrubStrategyDemographicNone,
-			expectedUserGeo:         ScrubStrategyGeoReducedPrecision,
+			ampGDPRException:   false,
+			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
+			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
+			expectedUser:       ScrubStrategyUserID,
+			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
 		},
 		{
 			description: "COPPA Only",
@@ -89,10 +92,11 @@ func TestApply(t *testing.T) {
 				COPPA: true,
 				GDPR:  false,
 			},
-			expectedDeviceIPv6:      ScrubStrategyIPV6Lowest32,
-			expectedDeviceGeo:       ScrubStrategyGeoFull,
-			expectedUserDemographic: ScrubStrategyDemographicAgeAndGender,
-			expectedUserGeo:         ScrubStrategyGeoFull,
+			ampGDPRException:   false,
+			expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
+			expectedDeviceGeo:  ScrubStrategyGeoFull,
+			expectedUser:       ScrubStrategyUserIDAndDemographic,
+			expectedUserGeo:    ScrubStrategyGeoFull,
 		},
 		{
 			description: "GDPR Only",
@@ -101,10 +105,50 @@ func TestApply(t *testing.T) {
 				COPPA: false,
 				GDPR:  true,
 			},
-			expectedDeviceIPv6:      ScrubStrategyIPV6Lowest16,
-			expectedDeviceGeo:       ScrubStrategyGeoReducedPrecision,
-			expectedUserDemographic: ScrubStrategyDemographicNone,
-			expectedUserGeo:         ScrubStrategyGeoReducedPrecision,
+			ampGDPRException:   false,
+			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
+			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
+			expectedUser:       ScrubStrategyUserID,
+			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
+		},
+		{
+			description: "GDPR Only, ampGDPRException",
+			enforcement: Enforcement{
+				CCPA:  false,
+				COPPA: false,
+				GDPR:  true,
+			},
+			ampGDPRException:   true,
+			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
+			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
+			expectedUser:       ScrubStrategyUserNone,
+			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
+		},
+		{
+			description: "CCPA Only, ampGDPRException",
+			enforcement: Enforcement{
+				CCPA:  true,
+				COPPA: false,
+				GDPR:  false,
+			},
+			ampGDPRException:   true,
+			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
+			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
+			expectedUser:       ScrubStrategyUserID,
+			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
+		},
+		{
+			description: "COPPA and GDPR, ampGDPRException",
+			enforcement: Enforcement{
+				CCPA:  false,
+				COPPA: true,
+				GDPR:  true,
+			},
+			ampGDPRException:   true,
+			expectedDeviceIPv6: ScrubStrategyIPV6Lowest32,
+			expectedDeviceGeo:  ScrubStrategyGeoFull,
+			expectedUser:       ScrubStrategyUserIDAndDemographic,
+			expectedUserGeo:    ScrubStrategyGeoFull,
 		},
 	}
 
@@ -118,9 +162,9 @@ func TestApply(t *testing.T) {
 
 		m := &mockScrubber{}
 		m.On("ScrubDevice", req.Device, test.expectedDeviceIPv6, test.expectedDeviceGeo).Return(replacedDevice).Once()
-		m.On("ScrubUser", req.User, test.expectedUserDemographic, test.expectedUserGeo).Return(replacedUser).Once()
+		m.On("ScrubUser", req.User, test.expectedUser, test.expectedUserGeo).Return(replacedUser).Once()
 
-		test.enforcement.apply(req, m)
+		test.enforcement.apply(req, test.ampGDPRException, m)
 
 		m.AssertExpectations(t)
 		assert.Same(t, replacedDevice, req.Device, "Device")
@@ -138,7 +182,7 @@ func TestApplyNoneApplicable(t *testing.T) {
 		COPPA: false,
 		GDPR:  false,
 	}
-	enforcement.apply(req, m)
+	enforcement.apply(req, false, m)
 
 	m.AssertNotCalled(t, "ScrubDevice")
 	m.AssertNotCalled(t, "ScrubUser")
@@ -148,7 +192,7 @@ func TestApplyNil(t *testing.T) {
 	m := &mockScrubber{}
 
 	enforcement := Enforcement{}
-	enforcement.apply(nil, m)
+	enforcement.apply(nil, false, m)
 
 	m.AssertNotCalled(t, "ScrubDevice")
 	m.AssertNotCalled(t, "ScrubUser")
@@ -163,7 +207,7 @@ func (m *mockScrubber) ScrubDevice(device *openrtb.Device, ipv6 ScrubStrategyIPV
 	return args.Get(0).(*openrtb.Device)
 }
 
-func (m *mockScrubber) ScrubUser(user *openrtb.User, demographic ScrubStrategyDemographic, geo ScrubStrategyGeo) *openrtb.User {
-	args := m.Called(user, demographic, geo)
+func (m *mockScrubber) ScrubUser(user *openrtb.User, strategy ScrubStrategyUser, geo ScrubStrategyGeo) *openrtb.User {
+	args := m.Called(user, strategy, geo)
 	return args.Get(0).(*openrtb.User)
 }
diff --git a/privacy/scrubber_test.go b/privacy/scrubber_test.go
index 2d5ee667..a6c4bde3 100644
--- a/privacy/scrubber_test.go
+++ b/privacy/scrubber_test.go
@@ -252,7 +252,7 @@ func TestScrubUser(t *testing.T) {
 
 	testCases := []struct {
 		expected    *openrtb.User
-		demographic ScrubStrategyDemographic
+		user        ScrubStrategyUser
 		geo         ScrubStrategyGeo
 		description string
 	}{
@@ -265,8 +265,8 @@ func TestScrubUser(t *testing.T) {
 				Gender:   "",
 				Geo:      &openrtb.Geo{},
 			},
-			demographic: ScrubStrategyDemographicAgeAndGender,
-			geo:         ScrubStrategyGeoFull,
+			user: ScrubStrategyUserIDAndDemographic,
+			geo:  ScrubStrategyGeoFull,
 		},
 		{
 			description: "Demographic Age And Gender & Geo Reduced",
@@ -283,11 +283,11 @@ func TestScrubUser(t *testing.T) {
 					ZIP:   "some zip",
 				},
 			},
-			demographic: ScrubStrategyDemographicAgeAndGender,
-			geo:         ScrubStrategyGeoReducedPrecision,
+			user: ScrubStrategyUserIDAndDemographic,
+			geo:  ScrubStrategyGeoReducedPrecision,
 		},
 		{
-			description: "Demographic Age And Gender & Geo None",
+			description: "Demographic Full & Geo None",
 			expected: &openrtb.User{
 				ID:       "",
 				BuyerUID: "",
@@ -301,11 +301,11 @@ func TestScrubUser(t *testing.T) {
 					ZIP:   "some zip",
 				},
 			},
-			demographic: ScrubStrategyDemographicAgeAndGender,
-			geo:         ScrubStrategyGeoNone,
+			user: ScrubStrategyUserIDAndDemographic,
+			geo:  ScrubStrategyGeoNone,
 		},
 		{
-			description: "Demographic None & Geo Full",
+			description: "Demographic Buyer ID & Geo Full",
 			expected: &openrtb.User{
 				ID:       "",
 				BuyerUID: "",
@@ -313,11 +313,11 @@ func TestScrubUser(t *testing.T) {
 				Gender:   "anyGender",
 				Geo:      &openrtb.Geo{},
 			},
-			demographic: ScrubStrategyDemographicNone,
-			geo:         ScrubStrategyGeoFull,
+			user: ScrubStrategyUserID,
+			geo:  ScrubStrategyGeoFull,
 		},
 		{
-			description: "Demographic None & Geo Reduced",
+			description: "Demographic Buyer ID & Geo Reduced",
 			expected: &openrtb.User{
 				ID:       "",
 				BuyerUID: "",
@@ -331,11 +331,29 @@ func TestScrubUser(t *testing.T) {
 					ZIP:   "some zip",
 				},
 			},
-			demographic: ScrubStrategyDemographicNone,
-			geo:         ScrubStrategyGeoReducedPrecision,
+			user: ScrubStrategyUserID,
+			geo:  ScrubStrategyGeoReducedPrecision,
 		},
 		{
 			description: "Demographic None & Geo None",
+			expected: &openrtb.User{
+				ID:       "anyID",
+				BuyerUID: "anyBuyerUID",
+				Yob:      42,
+				Gender:   "anyGender",
+				Geo: &openrtb.Geo{
+					Lat:   123.456,
+					Lon:   678.89,
+					Metro: "some metro",
+					City:  "some city",
+					ZIP:   "some zip",
+				},
+			},
+			user: ScrubStrategyUserNone,
+			geo:  ScrubStrategyGeoNone,
+		},
+		{
+			description: "Demographic BuyerIDOnly & Geo None",
 			expected: &openrtb.User{
 				ID:       "",
 				BuyerUID: "",
@@ -349,19 +367,19 @@ func TestScrubUser(t *testing.T) {
 					ZIP:   "some zip",
 				},
 			},
-			demographic: ScrubStrategyDemographicNone,
-			geo:         ScrubStrategyGeoNone,
+			user: ScrubStrategyUserID,
+			geo:  ScrubStrategyGeoNone,
 		},
 	}
 
 	for _, test := range testCases {
-		result := NewScrubber().ScrubUser(user, test.demographic, test.geo)
+		result := NewScrubber().ScrubUser(user, test.user, test.geo)
 		assert.Equal(t, test.expected, result, test.description)
 	}
 }
 
 func TestScrubUserNil(t *testing.T) {
-	result := NewScrubber().ScrubUser(nil, ScrubStrategyDemographicNone, ScrubStrategyGeoNone)
+	result := NewScrubber().ScrubUser(nil, ScrubStrategyUserNone, ScrubStrategyGeoNone)
 	assert.Nil(t, result)
 }
 
diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go
index 49ce85d0..f448da50 100755
--- a/usersync/usersyncers/syncer_test.go
+++ b/usersync/usersyncers/syncer_test.go
@@ -80,12 +80,13 @@ func TestNewSyncerMap(t *testing.T) {
 		openrtb_ext.BidderAdgeneration: true,
 		openrtb_ext.BidderAdoppler:     true,
 		openrtb_ext.BidderApplogy:      true,
-		openrtb_ext.BidderTappx:        true,
+		openrtb_ext.BidderKidoz:        true,
 		openrtb_ext.BidderKubient:      true,
+		openrtb_ext.BidderMobileFuse:   true,
+		openrtb_ext.BidderOrbidder:     true,
 		openrtb_ext.BidderPubnative:    true,
-		openrtb_ext.BidderKidoz:        true,
+		openrtb_ext.BidderTappx:        true,
 		openrtb_ext.BidderYeahmobi:     true,
-		openrtb_ext.BidderOrbidder:     true,
 	}
 
 	for bidder, config := range cfg.Adapters {