Skip to content
Open
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -918,32 +918,32 @@ The Optable Web SDK provides a method `installGPTSecureSignals` to pass user-def

Please refer to the list of approved Secure Signal [providers](https://support.google.com/admanager/answer/14750072). Please refer to the provider's integration documentation for the exact provider name and value to pass as a signal.

To build the signals from cached EIDs instead of by hand, `secureSignalsFromEids(eids, filter?)` builds one `{ provider, id }` pair per EID source — GPT keys secure signals by provider, so the first EID that passes the filter and carries a non-empty uid wins its source — optionally filtered by `sources`, `inserters` or `matchers` (an empty or missing list means no constraint on that field).
To build the signals from EIDs instead of by hand, `installGPTSecureSignalsFromEids({ filter?, eids? })` installs one signal per EID source — GPT keys secure signals by provider, so the first EID that passes the filter and carries a non-empty uid wins its source. `filter` narrows by `sources`, `inserters` or `matchers` (an empty or missing list means no constraint on that field).

The signals come from the last cached targeting response, so a first visit installs none until `targeting()` has resolved once.
`eids` defaults to the last cached targeting response, so a first visit installs none until `targeting()` has resolved once. Pass it explicitly to install from somewhere else.

With the npm package:

```javascript
import { secureSignalsFromEids } from "@optable/web-sdk/lib/dist/core/secure-signals";
import "@optable/web-sdk/lib/dist/addons/gpt";

const eids = sdk.targetingFromCache()?.ortb2?.user?.eids ?? [];
sdk.installGPTSecureSignals(...secureSignalsFromEids(eids, { sources: ["uidapi.com"] }));
sdk.installGPTSecureSignalsFromEids({ filter: { sources: ["uidapi.com"] } });
```

With the SDK loaded from a script tag, the helper is available under `optable.utils`:
With the SDK loaded from a script tag:

```html
<script async src="https://cdn.optable.co/web-sdk/latest/sdk.js"></script>
<script>
window.optable = window.optable || { cmd: [] };
optable.cmd.push(function () {
const eids = optable.instance.targetingFromCache()?.ortb2?.user?.eids ?? [];
optable.instance.installGPTSecureSignals(...optable.utils.secureSignalsFromEids(eids, { sources: ["uidapi.com"] }));
optable.instance.installGPTSecureSignalsFromEids({ filter: { sources: ["uidapi.com"] } });
});
</script>
```

`secureSignalsFromEids(eids, filter?)` is also exported from `@optable/web-sdk/lib/dist/core/secure-signals`, and available as `optable.utils.secureSignalsFromEids` on script-tag pages, for callers that want the `{ provider, id }` pairs without installing them.

You can verify the signal was correctly passed to GAM by searching for its value cached in `localStorage` under the key `_GESPSK-<provider_name>`.

## Integrating Prebid
Expand Down
40 changes: 40 additions & 0 deletions lib/addons/gpt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,46 @@ describe("OptableSDK - installGPTSecureSignals", () => {
expect(window.googletag.secureSignalProviders).toHaveLength(0);
});

test("installs from the cached targeting response, applying the filter", () => {
jest.spyOn(SDK, "targetingFromCache").mockReturnValue({
ortb2: {
user: {
eids: [
{ source: "uidapi.com", uids: [{ id: "uid2-a" }] },
{ source: "id5-sync.com", uids: [{ id: "id5-a" }] },
],
},
},
});

SDK.installGPTSecureSignalsFromEids({ filter: { sources: ["uidapi.com"] } });
window.googletag.cmd.forEach((cmd) => cmd());

expect(window.googletag.secureSignalProviders).toEqual([
{ id: "uidapi.com", collectorFunction: expect.any(Function) },
]);
});

test("prefers explicitly passed eids over the cache", () => {
jest.spyOn(SDK, "targetingFromCache").mockReturnValue({
ortb2: { user: { eids: [{ source: "cached.com", uids: [{ id: "cached" }] }] } },
});

SDK.installGPTSecureSignalsFromEids({ eids: [{ source: "given.com", uids: [{ id: "given" }] }] });
window.googletag.cmd.forEach((cmd) => cmd());

expect(window.googletag.secureSignalProviders.map((p) => p.id)).toEqual(["given.com"]);
});

test("installs nothing when the targeting cache is empty", () => {
jest.spyOn(SDK, "targetingFromCache").mockReturnValue(null);

SDK.installGPTSecureSignalsFromEids();

expect(window.googletag.cmd).toHaveLength(0);
expect(window.googletag.secureSignalProviders).toHaveLength(0);
});

test("handles an empty signals array gracefully", () => {
SDK.installGPTSecureSignals();

Expand Down
19 changes: 18 additions & 1 deletion lib/addons/gpt.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import type { ContextualTargetingKeyValuesOptions } from "../edge/contextual_segments";
import type { WitnessProperties } from "../edge/witness";
import type { SecureSignal } from "../core/secure-signals";
import { secureSignalsFromEids } from "../core/secure-signals";
import type { SecureSignal, SecureSignalEid, SecureSignalsFilter } from "../core/secure-signals";
import { debugLog } from "../core/log";
import OptableSDK from "../sdk";

declare module "../sdk" {
export interface OptableSDK {
installGPTEventListeners: () => void;
installGPTSecureSignals: (...signals: SecureSignal[]) => void;
installGPTSecureSignalsFromEids: (options?: SecureSignalsFromEidsOptions) => void;
}
}

Expand Down Expand Up @@ -84,6 +86,12 @@ OptableSDK.prototype.installGPTEventListeners = function (eventSpec?: GptEventSp
});
};

type SecureSignalsFromEidsOptions = {
filter?: SecureSignalsFilter;
// Defaults to the EIDs in the last cached targeting response.
eids?: SecureSignalEid[];
};

/*
* Pass user-defined signals to GAM Secure Signals
*/
Expand All @@ -103,6 +111,13 @@ OptableSDK.prototype.installGPTSecureSignals = function (...signals: SecureSigna
}
};

// Installs secure signals built from EIDs, defaulting to the cached targeting
// response. A first visit installs none until targeting() has resolved once.
OptableSDK.prototype.installGPTSecureSignalsFromEids = function (options: SecureSignalsFromEidsOptions = {}) {
const eids = options.eids ?? this.targetingFromCache()?.ortb2?.user?.eids ?? [];
this.installGPTSecureSignals(...secureSignalsFromEids(eids, options.filter ?? {}));
};

// Fetches the page's contextual segments and pushes the resulting key-values
// to GAM via googletag.pubads().setTargeting. taxonomyKeys and options are
// forwarded to ctxTargetingKeyValues(); url to ctxSegments(), for SPAs
Expand Down Expand Up @@ -140,3 +155,5 @@ export async function setContextualTargetingInGAM(
}
});
}

export type { SecureSignalsFromEidsOptions };