diff --git a/README.md b/README.md
index 90c8ae16..11d687b7 100644
--- a/README.md
+++ b/README.md
@@ -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
```
+`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-`.
## Integrating Prebid
diff --git a/lib/addons/gpt.test.js b/lib/addons/gpt.test.js
index 35c7f09b..8e8f5365 100644
--- a/lib/addons/gpt.test.js
+++ b/lib/addons/gpt.test.js
@@ -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();
diff --git a/lib/addons/gpt.ts b/lib/addons/gpt.ts
index ba450e20..72988acb 100644
--- a/lib/addons/gpt.ts
+++ b/lib/addons/gpt.ts
@@ -1,6 +1,7 @@
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";
@@ -8,6 +9,7 @@ declare module "../sdk" {
export interface OptableSDK {
installGPTEventListeners: () => void;
installGPTSecureSignals: (...signals: SecureSignal[]) => void;
+ installGPTSecureSignalsFromEids: (options?: SecureSignalsFromEidsOptions) => void;
}
}
@@ -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
*/
@@ -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
@@ -140,3 +155,5 @@ export async function setContextualTargetingInGAM(
}
});
}
+
+export type { SecureSignalsFromEidsOptions };