Targeting
How targeting works and the accepted values for each attribute.
Every deal is either targeted, carrying one or more targeting groups, or
Run of Network, which matches all eligible supply with
no targeting rules at all. Exactly one of targeting and runOfNetwork must
be present on a submission.
For targeted deals, within the targeting model:
- Groups OR together: a request matches if any group matches.
- Rules within a group AND together.
- Values within a rule OR together.
Each rule either includes or excludes its values via match (include is the
default; use exclude to negate).
A deal request carries at most 25 targeting groups and at most 100
rules in total across all groups. There is no limit on the number of values
in a rule, but the whole request body is capped at 1 MB (1,048,576 bytes), and
a larger one returns 413. Exceeding either targeting limit returns a 400
naming the limit:
{ "message": "body/targeting at most 25 targeting groups per deal request" }
Only enumerated attributes andpublisher.idare checked on submissionA value that is not on its attribute's list is rejected with a
400naming
the values in question, on a dry run too. Every attribute whose
valueFormatisenumeratedis checked this way exceptadUnit.size, and
the list forcontent.categorization.v1is the IAB's own Content Taxonomy
1.0 (seecontent.categorization.v1below). A 2-letter country code such
asUSis converted to its 3-letter code rather than rejected (see
device.geo.countrybelow). A publisher id that is not a
positive whole number up to2147483647is rejected the same way (see
publisher.idbelow).Other free-text attributes and ad sizes accept any value: one that doesn't
match the formats below is accepted and then simply never matches
traffic, with no error at any point. Send the exact formats shown here.
Read the vocabulary liveRather than relying on this page staying current, you can read the accepted
values live (see
Discovering attributes and values).
GET /targeting-attributeslists every attribute and whether it has an
enumerable set of values, andGET /targeting-attributes/{attribute}/values
returns the values themselves. The endpoints are the source of truth; the
tables below are a snapshot for reading. A value Sovrn adds, such as a new
audience segment, can take up to about 30 minutes to appear there.
Run of Network
To create a deal with no targeting rules, send runOfNetwork: true instead
of targeting:
{
"name": "Acme CTV Run of Network Q1",
"adFormat": "video",
"environments": ["ctv"],
"runOfNetwork": true,
"pricing": { "model": "auction", "floor": 12.0, "currency": "USD" },
"commercial": { "takeRate": 0.15 },
"schedule": { "startDate": "2030-01-01" },
"buyers": [{ "partner": "thetradedesk", "seatIds": ["your-seat-id"] }]
}A Run of Network deal matches all eligible supply within its ad format and
its environments: adFormat and environments still scope the deal; only
the targeting rules are absent.
runOfNetworkandtargetingare mutually exclusive; sending both (or
neither) returns a400.- The only accepted value is
true; to make a deal targeted, send
targetinginstead.
In a single-deal response (GET /deal-requests/{id} and the 200 from a
PATCH), the deal carries a runOfNetwork boolean, and targeting is null
for a Run of Network deal.
Switching modes after creation works through PATCH: sending
{ "runOfNetwork": true } converts a targeted deal to Run of Network
(its targeting rules are removed), and sending a targeting array converts a
Run of Network deal back to targeted. This is also the only way to remove
targeting from a deal: targeting itself cannot be cleared or set to an
empty array.
Discovering attributes and values
Two read-only endpoints expose the live vocabulary, so you don't have to track
changes to this page.
GET /targeting-attributes lists every attribute a rule may use, with a
valueFormat telling you whether its values can be enumerated:
{
"data": [
{
"attribute": "device.deviceType",
"description": "OpenRTB device-type code as an integer, not a label. 3 is Connected TV.",
"valueFormat": "enumerated",
"valuesPath": "/sovrnos/v1/targeting-attributes/device.deviceType/values"
},
{
"attribute": "site.domain",
"description": "Registrable site domain, as free text — no scheme or path. For example \"espn.com\".",
"valueFormat": "freeText",
"valuesPath": null
}
]
}valuesPath is a path on https://api.sovrn.com that already includes
/sovrnos/v1. Request it on that host as it is; appending it to the base URL
would repeat /sovrnos/v1.
GET /targeting-attributes/{attribute}/values returns the accepted values for
an enumerated attribute, each with a label. Every value comes back as a
string, such as "3", and total is always the number of entries in data.
An excerpt, cut to one value:
{
"attribute": "device.deviceType",
"total": 1,
"data": [{ "value": "3", "label": "Connected TV" }]
}A freeText attribute has no list to return, so asking for its values responds
400 rather than an empty array. Check valueFormat first, or follow
valuesPath, which is null exactly when there's nothing to enumerate.
Attribute reference
device.geo.country
Country as an ISO 3166-1 alpha-3 code (three uppercase letters). Read the
current list from GET /targeting-attributes/device.geo.country/values.
Examples: USA, GBR, CAN, DEU, JPN, AUS.
A 2-letter ISO 3166-1 alpha-2 code, such as US, is converted to its
3-letter code before the deal is created, so the deal is stored with USA
and reads back as USA. A value is accepted when it, or the 3-letter code
of a 2-letter one, is in that list. Anything else is rejected at submission,
on a dry run too, with a 400 naming the values as you sent them. Without
this check, a code the list lacks would pass a dry run and then fail the real
create with a 502 that doesn't name it:
{
"message": "body/targeting/0/rules/0/values country code(s) not available for targeting: \"ZZZ\", \"usa\". Send a code from GET /targeting-attributes/device.geo.country/values, or its 2-letter ISO 3166-1 form."
}Codes are matched exactly, with no case folding, so usa and us are
rejected. Only the rejected values are named, each quoted as you sent it, so
a rule mixing valid and invalid codes tells you exactly which to fix.
device.geo.region
A US state as its two-letter postal code, such as CA, CO or KS.
Read the current list from
GET /targeting-attributes/device.geo.region/values. A code that is not on
that list is rejected at submission, on a dry run too, with a 400 naming
it.
The region is looked up from the device's IP address and carries no country,
so put it in the same group as a device.geo.country rule for USA. Rules
within a group AND together, so the pair matches those states in the United
States only:
{
"name": "California and Colorado",
"rules": [
{ "attribute": "device.geo.country", "values": ["USA"] },
{ "attribute": "device.geo.region", "values": ["CA", "CO"] }
]
}device.language
The device's language as a lowercase two-letter ISO 639-1 code, such as
en or es. Today the list holds de, en, es, fr and ja; read the
current list from GET /targeting-attributes/device.language/values.
The code is matched exactly against the device.language the bid request
carries, so send it in lowercase as listed; a code that is not on the list is
rejected at submission, on a dry run too, with a 400 naming it. Example:
["en", "es"].
device.deviceType
OpenRTB device-type code (integer), not a label. Value discovery lists
each code as a string, such as "3":
| Code | Device |
|---|---|
| 1 | Mobile / Tablet (general) |
| 2 | Personal Computer |
| 3 | Connected TV |
| 4 | Phone |
| 5 | Tablet |
| 6 | Connected Device |
| 7 | Set-Top Box |
| 8 | Out-of-Home (OOH) device |
Example: [3] targets Connected TV (listed by value discovery as "3").
Its values are validated, as country codes are. A code that is not in
GET /targeting-attributes/device.deviceType/values is rejected at
submission, on a dry run too, with a 400 naming the codes as you sent them,
instead of passing a dry run and then failing the real create with a 502:
{
"message": "body/targeting/0/rules/0/values device.deviceType value(s) not available for targeting: 99. Send a value from GET /targeting-attributes/device.deviceType/values."
}Codes may be sent as integers or strings: 3 and "3" behave identically.
Only the rejected codes are named, each quoted as you sent it (99 for an
integer, "99" for a string), so a rule mixing valid and invalid codes tells
you exactly which to fix.
adUnit.size
A Sovrn size token (not a raw WxH string). Tokens are namespaced by medium
(wd web display, wv web video, mwd mobile web display, mb mobile in-app
banner, mv mobile video, ctv connected TV), as pixel tokens of the form
{medium}.px.{width}x{height}, plus category and aspect-ratio tokens. Send the
token exactly, e.g. wd.px.300x250.
This list grows as Sovrn adds sizes. For the current set, call
GET /targeting-attributes/adUnit.size/values. If you need a size
that doesn't appear there, ask your Sovrn representative.
audience.segmentids
Sovrn-assigned audience segment IDs (integers). Read the current list from
GET /targeting-attributes/audience.segmentids/values, which returns each id,
as a string, with its human-readable label. A new segment can take up to about
30 minutes to appear in that list and to be accepted in a rule.
Its values are validated, as country codes are. An id Sovrn doesn't
recognize is rejected at submission, on a dry run too, with a 400 naming
the offending ids, instead of passing a dry run and then failing the real
create with a 502:
{
"message": "body/targeting/0/rules/0/values unknown audience segment id(s): 999999999999. Segment availability is account-specific — ask your Sovrn representative for the ids provisioned to you."
}Ids may be sent as integers or strings: 366 and "366" behave identically.
Only the unrecognized ids are named, so a rule mixing valid and invalid ids
tells you exactly which to fix.
content.categorization.v3
An IAB content category from the v3 taxonomy, as its code. Read the codes
and their labels from
GET /targeting-attributes/content.categorization.v3/values. A code that is
not on that list is rejected at submission, on a dry run too, with a 400
naming it.
Codes are matched exactly: a category does not include its subcategories. To
cover a whole branch, list the category and every subcategory under it, so a
rule with "match": "exclude" meant to keep a deal off all gaming content
lists the gaming category and each of its subcategories.
The rule takes v3 codes only. Codes from the IAB's separate v1 taxonomy, such
as IAB9, are not v3 codes: target them with content.categorization.v1.
content.categorization.v1
An IAB content category from the v1 taxonomy, IAB Content Taxonomy 1.0, as
its code: IAB and a category number from 1 to 26, such as IAB9 (Hobbies &
Interests), or for a subcategory the category's code, a hyphen and the
subcategory's number, such as IAB9-30 (Video & Computer Games). Read the 392
codes and their labels from
GET /targeting-attributes/content.categorization.v1/values. A code that is
not on that list is rejected at submission, on a dry run too, with a 400
naming it:
{
"message": "body/targeting/0/rules/0/values content.categorization.v1 value(s) not available for targeting: \"IAB27\", \"IAB9-99\", \"iab9\". Send a value from GET /targeting-attributes/content.categorization.v1/values."
}Codes are matched exactly, with no case folding, so iab9 is rejected. A
category does not include its subcategories: IAB9 matches content
categorized as IAB9, not content categorized only as IAB9-30. To cover a
whole branch, list the category and each subcategory under it: for Hobbies &
Interests, IAB9 and IAB9-1 through IAB9-31.
v1 and v3 are separate taxonomies with codes of their own, so a v3 code is not
a v1 code and each goes in a rule on its own attribute. A bid request's
categories come from one of the two, and a request that does not say which is
read as v1.
geo.zip
Postal / ZIP code, as free text. Example: ["10001", "90210"].
site.domain
Registrable site domain, as free text (no scheme or path). Example:
["espn.com", "weather.com"].
app.bundleId
App-store bundle identifier, as free text: an iOS numeric store ID or an Android
package name. Example: ["284035177", "com.example.app"].
content.genre
Content genre, as free text. Example: ["comedy", "drama"]. There is no list
to look up, so GET /targeting-attributes/content.genre/values answers 400.
A bid request can carry several genres in its content.genre, separated by
commas. The rule matches when any one of those items equals one of its
values, ignoring case and the spaces around each item: comedy matches a
request whose genre is Drama, Comedy.
publisher.id
A Sovrn publisher id: a positive whole number, sent as an integer or as a
string of digits, so 12345 and "12345" match the same publisher. The
largest publisher id is 2147483647. Ask your Sovrn representative for the
publisher ids you want to target.
Any other value, such as "abc", 12.5, -3, "0123", " 123" or
2147483648, is rejected at submission, on a dry run too, with a 400
naming each value as you sent it. Without this check, a value that is not a
number at all would fail the create with a 502 that doesn't name it, and
the others would be stored and then never match:
{
"message": "body/targeting/0/rules/0/values publisher id(s) not valid: \"abc\", 12.5, -3. A publisher id is a positive whole number, such as 12345 or \"12345\"."
}Updated about 14 hours ago

