OpenRTB
If you run your own exchange, SSP, or mediation stack, you can call Ezoic as a server-to-server OpenRTB connection. You send a standard OpenRTB 2.5/2.6 bid request and get a standard bid response back, with at most one bid per impression. No Ezoic JavaScript is needed on your pages.
Complete the onboarding steps first. There is no API key: eligibility is checked per registered domain or app bundle, and unregistered inventory gets no bids.
Endpoint
POST https://g.ezoic.net/ezoic/prebid/adapter/ortb
Content-Type: application/json
- Unknown OpenRTB fields are accepted and passed to demand where relevant.
- Responses are never cacheable (
Cache-Control: no-store). - Methods other than POST return 405.
Request
The minimum is an id, at least one imp, and site or app identity.
| Field | Required | Notes |
|---|---|---|
id |
yes | Echoed back in the response. A missing id or empty imp returns 400. |
imp[].id |
yes | Echoed back as bid.impid. |
site.page |
yes (web) | Full page URL. If missing, site.domain is used as https://<domain>/. |
app.bundle |
yes (app) | The bundle must be registered with Ezoic. |
tmax |
recommended | Milliseconds. Requests with less than about 250 ms left after network time get a no-bid. Send 800–1000. 1000 is assumed if omitted. |
device |
recommended | ua, ip/ipv6, os, devicetype and geo.country drive form factor and geo targeting. Desktop, phone, tablet and CTV are supported. |
imp[].banner |
one of banner / video / native | Sizes from format[] (preferred) or w/h. Imps with no banner sizes, video, or native are ignored. |
imp[].video |
one of | Standard OpenRTB video object. Adding a sibling banner on the same imp keeps display demand as a fallback, which we recommend. |
imp[].native |
one of | Standard OpenRTB native request. |
imp[].tagid |
optional | Used as the ad unit name in reporting. Defaults to imp.id. |
imp[].ext.bidder.placementId |
optional | Your own name or ID for the slot (string). Recorded for reporting; doesn't change bidding. |
imp[].bidfloor, bidfloorcur |
optional | Enforced across Ezoic's demand. Currency defaults to USD. |
imp[].instl |
optional | 1 marks interstitial inventory. |
imp[].rwdd |
optional | 1 marks rewarded inventory (imp.ext.prebid.is_rewarded_inventory also works). |
Privacy
Standard OpenRTB fields are honored and passed to all demand:
user.consent(oruser.ext.consent): TCF v2 consent stringregs.gdpr(orregs.ext.gdpr): GDPR appliesregs.gppandregs.gpp_sid: GPPregs.ext.us_privacy: US Privacy
First-party data and supply chain
site / app content objects, user.eids, source.schain, and the badv / bcat / bapp block lists are passed to demand. Block lists are honored.
User matching
Ezoic matches users through an iframe sync (https://g.ezoic.net/ezoic/prebid/adapter/usersync-frame), which we strongly recommend for web inventory. On Prebid Server, see User sync. For custom stacks, set it up with your Ezoic contact. Requests without a matched user are still bid on, at lower expected prices.
Example request
{
"id": "auction-8f2c1a",
"tmax": 1000,
"site": {
"page": "https://www.example.com/articles/how-to-grow-tomatoes",
"domain": "example.com"
},
"device": {
"ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1",
"ip": "203.0.113.42",
"os": "iOS",
"devicetype": 1,
"geo": { "country": "USA" }
},
"regs": {
"gdpr": 0,
"ext": { "us_privacy": "1---" }
},
"source": {
"schain": {
"ver": "1.0",
"complete": 1,
"nodes": [
{ "asi": "examplepub-exchange.com", "sid": "pub-4711", "hp": 1 }
]
}
},
"badv": ["competitor.example"],
"imp": [
{
"id": "1",
"tagid": "sidebar-top",
"banner": { "format": [{ "w": 300, "h": 250 }, { "w": 336, "h": 280 }] },
"bidfloor": 0.25,
"bidfloorcur": "USD"
},
{
"id": "2",
"tagid": "page-interstitial",
"instl": 1,
"banner": { "format": [{ "w": 320, "h": 480 }, { "w": 300, "h": 600 }] },
"bidfloor": 0.5,
"bidfloorcur": "USD"
}
]
}
device.geo.country uses ISO-3166 alpha-3 codes (USA), as OpenRTB specifies.
To test, save the request as request.json and run:
curl -s -w "\nHTTP %{http_code}\n" \
-X POST "https://g.ezoic.net/ezoic/prebid/adapter/ortb" \
-H "Content-Type: application/json" \
--data-binary @request.json
Before your domain is approved this returns HTTP 204, which confirms the request parsed and reached Ezoic. 400 {"error":"invalid_json"} means the body is malformed.
Response
200 with a bid:
{
"id": "<your auction id>",
"cur": "USD",
"seatbid": [{
"seat": "ezoic",
"bid": [{
"id": "...",
"impid": "<imp.id>",
"price": 1.27,
"mtype": 1,
"adm": "<self-contained HTML>",
"crid": "...",
"w": 300,
"h": 250
}]
}]
}
mtype: 1 = banner, 2 = video, 4 = native.- Banner and native:
admis self-contained markup that includes Ezoic's impression tracking. Render it in a standard iframe. No win notice is needed from your side; Ezoic counts the impression when the markup renders. - Video:
nurlcarries an Ezoic VAST URL. Fetch it as the VAST document for your player when the bid wins. Impression tracking is inside the VAST. - At most one bid per impression.
204: no bid. Causes include no demand, unapproved inventory, invalid traffic, an unsupported form factor, a privacy-restricted request, or too little tmax.
400: unparseable JSON, or a missing id or imp.
Counting and payment
priceis a net CPM: you're paidprice / 1000per rendered, valid impression.- Ezoic counts impressions with its own tracking: at render for banner and native, and from VAST impression events for video. As with any server-side partner, expect small differences from your ad server's counts; Ezoic's count is the payment basis.
- Reporting and payment schedule are set up with your Ezoic contact during onboarding.
Go-live checklist
- Domains / app bundles registered and approved by Ezoic
- A test request returns 204, not 400
-
tmaxof 800 ms or more end to end - Consent strings populated where they apply
- Video imps carry a sibling
bannerwhere display fallback is acceptable - Start with low traffic and agree the ramp window with your Ezoic contact