Example: contextual segments API

Shows how to call ctxSegments() to classify a page URL and inspect the classifications the DCN returns for it: taxonomy categories (e.g. against the IAB Content Taxonomy), free-form keywords, and/or a brand-safety assessment (against the Brand Safety Floor + Suitability Framework), depending on which classifiers the DCN has enabled.

// Classify the URL of the current page (defaults to window.location.href):
optable.instance.ctxSegments();

// Or classify an explicit URL:
optable.instance.ctxSegments("https://optable.co/");

The response is a ContextualSegmentsResponse:

{
  classifications: {
    categories: [{ id, name, score, taxonomy }],
    keywords: [{ keyword, prominence }],
    brandSafety: { assessed, categories: [{ name, riskLevel }] },
  },
}

The classifications object groups results by classification method, and the DCN includes only the methods it has enabled. Three methods exist today:

categories: taxonomy category ids scored for the page
FieldDescription
idCategory id within its taxonomy (e.g. an IAB category id).
nameHuman-readable category name.
scoreRelevance score from 0 to 1.
taxonomy Id of the taxonomy the category belongs to (e.g. iab_ct_3_1).
keywords: free-form terms extracted from the page
FieldDescription
keywordThe extracted keyword text.
prominence Per-page ordinal rank (1 = most prominent), not a score, so prominences are not comparable across pages.
brandSafety: brand-safety assessment of the page

The categories and the risk tiers follow the Brand Safety Floor + Suitability Framework, which is where the category list and the term floor come from.

Note: only the page's text is assessed. Embedded media, such as images, video and audio, is not, so a page can come back with nothing flagged and still carry unsafe media. Treat the result as a signal about what the page says, not about everything a visitor sees.

FieldDescription
assessed Whether an assessment backs categories. It decides what an empty categories means, so read it first: see the table below.
categories[].name Human-readable brand-safety category name.
categories[].riskLevel Tier the category was flagged at: low, medium, high or floor, in increasing severity, so floor is the framework's brand-safety floor rather than a baseline. not_assessed means the pass did not cover the category, and is not a severity.

Read assessed before categories. An empty categories list means two opposite things depending on it:

assessedcategoriesMeaning
trueemptyAn assessment ran and flagged nothing.
true non-empty An assessment ran: each entry is a category it flagged, at its riskLevel, or a not_assessed category the pass did not cover. Assessed categories with no finding are omitted.
false always empty Nothing is known about this page. The DCN never classified it, the read failed, or this DCN does not run the brand-safety classifier at all.

Two helpers read this off the cached response, so you do not have to walk it yourself. ctxBrandSafety() returns the group above, and ctxMaxRiskLevel() returns the most severe tier flagged, or null when nothing is flagged, which is convenient for a single gate:

if (optable.instance.ctxMaxRiskLevel() === "floor") {
  // Do not monetize this page.
}

null comes back in two different situations: an assessment ran and flagged nothing, and nothing is known about the page at all. A gate that must tell those apart reads ctxBrandSafety().assessed as well. Note also that a page assessed clean is not a clearance: the taxonomy enumerates risks, so the classifier can report that a page matches one but never that it is free of them.

Alternatively, configure the SDK with initContextual set to a callback. The SDK will automatically call ctxSegments() for the URL of the current page on initialization, and invoke the callback with the response as soon as it's available — no second call required:

optable.instance = new optable.SDK({
  host: "ca.edge.optable.co",
  site: "web-sdk-demo",
  node: "optable",
  cookies: false,
  initContextual: function (response) {
    // Use the response, or read it later via optable.instance.ctxTargetingKeyValues().
    console.log("contextual segments:", response);
  },
});

Note: the URL requested must have been classified by the DCN. For the demo DCN used by this page, the URL https://optable.co/ should have been classified, so you can try that. A URL the DCN holds no classification for comes back with empty categories and keywords arrays, and brandSafety.assessed set to false.

Result
Raw response
Click the button to call ctxSegments().
GAM targeting key-values

Derived from the cached ctxSegments() response via optable.instance.ctxTargetingKeyValues(), this object can be passed straight to Google Ad Manager via googletag.pubads().setTargeting(key, values):

var loadGAM = function (tdata = {}) {
  window.googletag = window.googletag || { cmd: [] };
  googletag.cmd.push(function () {
    for (const [key, values] of Object.entries(tdata)) {
      googletag.pubads().setTargeting(key, values);
    }
    googletag.pubads().refresh();
  });
};

ctxTargetingKeyValues() reads the response cached on the SDK instance, so the instance should be initialized with the initContextual: true option. That way the contextual segments are fetched during initialization, and the cache is likely to be populated by the time loadGAM() runs:

loadGAM(optable.instance.ctxTargetingKeyValues());

By default the returned map has one key per taxonomy the DCN classified into (keyed by the raw taxonomy value), the page's keywords under ctx_kw, and its brand-safety tier under ctx_bs_max. For example, ctxTargetingKeyValues() might return:

{
  "iab_ct_3_1": ["53", "91", "58", "115", "90", "52"],
  "ctx_kw": ["advertising", "programmatic", "ad tech"],
  "ctx_bs_max": ["no_flags"]
}

If you want loadGAM() to run as soon as the contextual segments arrive — without making a second ctxSegments() call — pass a callback to initContextual. The SDK fires the contextual request automatically during initialization and invokes the callback with the response, populating the cache before ctxTargetingKeyValues() reads from it:

optable.instance = new optable.SDK({
  host: "ca.edge.optable.co",
  site: "web-sdk-demo",
  node: "optable",
  cookies: false,
  initContextual: function (response) {
    loadGAM(optable.instance.ctxTargetingKeyValues());
  },
});

If you are not using initContextual at all, fetch the segments explicitly and pass the result to loadGAM() once ctxSegments() resolves (falling back to an untargeted load on error):

optable.cmd.push(function () {
  optable.instance
    .ctxSegments()
    .then(loadGAM)
    .catch((err) => {
      loadGAM();
    });
});

By default each taxonomy is emitted under its own value as the GAM key. Pass a map to ctxTargetingKeyValues() to rename keys and allow-list which taxonomies are emitted — only taxonomies present in the map are included:

// Emit only the "iab_ct_3_1" taxonomy, under the GAM key "ctx_iab":
loadGAM(optable.instance.ctxTargetingKeyValues({ iab_ct_3_1: "ctx_iab" }));

Keyword classifications are also emitted, by default under the GAM key ctx_kw. The values are the page's keywords ordered by prominence (most prominent first), capped to the top 10, and sanitized to GAM's value rules (lowercased, reserved characters stripped, truncated to 40 characters). Pass keywordKey to rename the key or maxKeywords to change the cap, or set keywordKey to an empty string to opt out of keyword key-values entirely:

// Rename the keyword key and emit only the top 5 keywords:
loadGAM(optable.instance.ctxTargetingKeyValues({ iab_ct_3_1: "ctx_iab" }, { keywordKey: "kw", maxKeywords: 5 }));

// Opt out of keyword key-values:
loadGAM(optable.instance.ctxTargetingKeyValues(undefined, { keywordKey: "" }));

Brand safety is emitted by default under ctx_bs_max, carrying the page's most severe flagged tier. It is the same text-only assessment described above, so a line item keyed on it is gating on the page's words and not on its embedded media. Use brandSafetyKey to rename it, or pass an empty brandSafetyKey to opt out, exactly as keywordKey works:

// Rename the brand-safety key:
loadGAM(optable.instance.ctxTargetingKeyValues(undefined, { brandSafetyKey: "bs" }));

// Opt out of the brand-safety key-value:
loadGAM(optable.instance.ctxTargetingKeyValues(undefined, { brandSafetyKey: "" }));

A value is emitted for every state rather than the key being dropped when nothing is flagged:

StateValue
A tier was flagged The most severe one: low, medium, high or floor
Assessed, nothing flaggedno_flags
Nothing is known about the pagenot_assessed

The two sentinels exist so a line item can tell them apart. If the key were simply absent when nothing was flagged, "we never looked" and "we looked and flagged nothing" would look identical in GAM, and you could not exclude unassessed inventory without also excluding clean inventory. no_flags is deliberately not named safe: a pass with no finding is not a clearance.

not_assessed is spelled the same as the riskLevel a category carries when the assessment did not cover it. That is deliberate: one word for one idea, "nothing is known here", at two scopes. The scopes cannot be confused, because ctx_bs_max only ever carries a page-level answer.

One difference from keywordKey is worth knowing before you ship: keywords are dropped when the DCN produced none, whereas ctx_bs_max is always present unless you disable it. A DCN that does not run the brand-safety classifier therefore adds ctx_bs_max=not_assessed to every ad request. If you do not use brand safety at all, pass an empty brandSafetyKey to keep it out.

—