Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 28 additions & 25 deletions extra/modules/live-intent-omni-channel-identity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,48 @@

This module enriches bid requests with user EIDs.

The user EIDs to be enriched are configured per partner as part of the LiveIntent HIRO onboarding process. As part of this onboarding process, partners will also be provided with the `identity-resolution-endpoint` URL as well as with the `auth-token`.
The user EIDs to be enriched are configured per partner as part of the LiveIntent HIRO onboarding process. As part of
this onboarding process, partners will also be provided with the `identity-resolution-endpoint` URL as well as with the
`auth-token`.

`treatment-rate` is a value between 0.0 and 1.0 (including 0.0 and 1.0) and defines the percentage of requests for which identity enrichment should be performed. This value can be freely picked. We recommend a value between 0.9 and 0.95
`treatment-rate` is a value between 0.0 and 1.0 (including 0.0 and 1.0) and defines the percentage of requests for which
identity enrichment should be performed. This value can be freely picked. We recommend a value between 0.9 and 0.95

## Configuration

To start using the LiveIntent Omni Channel Identity module you have to enable it and add configuration:

```yaml
hooks:
liveintent-omni-channel-identity:
enabled: true
host-execution-plan: >
{
"endpoints": {
"/openrtb2/auction": {
"stages": {
"processed-auction-request": {
"groups": [
{
"timeout": 100,
"hook-sequence": [
liveintent-omni-channel-identity:
enabled: true
host-execution-plan: >
{
"endpoints": {
"/openrtb2/auction": {
"stages": {
"processed-auction-request": {
"groups": [
{
"module-code": "liveintent-omni-channel-identity",
"hook-impl-code": "liveintent-omni-channel-identity-enrichment-hook"
"timeout": 100,
"hook-sequence": [
{
"module-code": "liveintent-omni-channel-identity",
"hook-impl-code": "liveintent-omni-channel-identity-enrichment-hook"
}
]
}
]
}
]
}
}
}
}
}
}
modules:
liveintent-omni-channel-identity:
request-timeout-ms: 2000
identity-resolution-endpoint: "https://liveintent.com/idx"
auth-token: "secret-token"
treatment-rate: 0.9
modules:
liveintent-omni-channel-identity:
request-timeout-ms: 2000
identity-resolution-endpoint: "https://u.liveintent.com/idx"
auth-token: "secret-token"
treatment-rate: 0.9
```

Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.prebid.server.vertx.httpclient.HttpClient;
import org.prebid.server.vertx.httpclient.model.HttpClientResponse;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
Expand All @@ -58,6 +59,8 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements

private static final String CODE = "liveintent-omni-channel-identity-enrichment-hook";

private static final String INSERTER = "s2s.liveintent.com";

private final LiveIntentOmniChannelProperties config;
private final JacksonMapper mapper;
private final HttpClient httpClient;
Expand Down Expand Up @@ -161,7 +164,11 @@ private MultiMap headers() {
}

private IdResResponse processResponse(HttpClientResponse response) {
return mapper.decodeValue(response.getBody(), IdResResponse.class);
final IdResResponse res = mapper.decodeValue(response.getBody(), IdResResponse.class);
final List<Eid> eids = res.getEids().stream()
.map(eid -> eid.toBuilder().inserter(INSERTER).build())
.toList();
return IdResResponse.of(eids);
}

private static Future<InvocationResult<AuctionRequestPayload>> noAction() {
Expand Down Expand Up @@ -208,14 +215,6 @@ private BidRequest updateAllowedBidders(BidRequest bidRequest, List<Eid> resolve
final ExtRequestPrebid extPrebid = ext != null ? ext.getPrebid() : null;
final ExtRequestPrebidData extPrebidData = extPrebid != null ? extPrebid.getData() : null;

final List<ExtRequestPrebidDataEidPermissions> existingPerms = extPrebidData != null
? extPrebidData.getEidPermissions()
: null;

if (CollectionUtils.isEmpty(existingPerms)) {
return bidRequest;
}

final ExtRequestPrebid updatedExtPrebid = Optional.ofNullable(extPrebid)
.map(ExtRequestPrebid::toBuilder)
.orElseGet(ExtRequestPrebid::builder)
Expand All @@ -237,7 +236,11 @@ private ExtRequestPrebidData updatePrebidData(ExtRequestPrebidData extPrebidData
.map(Eid::getSource)
.collect(Collectors.toSet());

final List<ExtRequestPrebidDataEidPermissions> updatedPermissions = extPrebidData.getEidPermissions().stream()
final List<ExtRequestPrebidDataEidPermissions> eidPermissions = extPrebidData != null
? ListUtils.emptyIfNull(extPrebidData.getEidPermissions())
: Collections.emptyList();

final List<ExtRequestPrebidDataEidPermissions> updatedPermissions = eidPermissions.stream()
.map(permission -> restrictEidPermission(permission, resolvedSources))
.filter(Objects::nonNull)
.toList();
Expand All @@ -252,16 +255,24 @@ private ExtRequestPrebidDataEidPermissions restrictEidPermission(ExtRequestPrebi
return permission;
}

final List<String> permittedBidders = ListUtils.emptyIfNull(permission.getBidders());

if (CollectionUtils.isEmpty(permittedBidders) || permittedBidders.contains("*")) {
return ExtRequestPrebidDataEidPermissions.builder()
.source(permission.getSource())
.bidders(targetBidders.stream().toList())
.build();
}

final List<String> finalBidders = ListUtils.emptyIfNull(permission.getBidders()).stream()
.filter(targetBidders::contains)
.toList();

return CollectionUtils.isEmpty(finalBidders)
? null
: ExtRequestPrebidDataEidPermissions
.builder()
.bidders(finalBidders)
: ExtRequestPrebidDataEidPermissions.builder()
.source(permission.getSource())
.bidders(finalBidders)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ public void callShouldEnrichUserEidsWithRequestedEids() {
final Eid expectedEid = Eid.builder()
.source("liveintent.com")
.uids(singletonList(Uid.builder().id("id2").atype(3).build()))
.matcher("liveintent.com")
.build();

final String responseBody = MAPPER.encodeToString(IdResResponse.of(List.of(expectedEid)));
Expand All @@ -273,7 +274,7 @@ public void callShouldEnrichUserEidsWithRequestedEids() {
.extracting(AuctionRequestPayload::bidRequest)
.extracting(BidRequest::getUser)
.extracting(User::getEids)
.isEqualTo(List.of(givenEid, expectedEid));
.isEqualTo(List.of(givenEid, expectedEid.toBuilder().inserter("s2s.liveintent.com").build()));

verify(httpClient).post(
eq("https://test.com/idres"),
Expand All @@ -290,6 +291,7 @@ public void callShouldCreateUserAndUseRequestedEidsWhenUserIsAbsent() {
final Eid expectedEid = Eid.builder()
.source("liveintent.com")
.uids(singletonList(Uid.builder().id("id2").atype(3).build()))
.matcher("liveintent.com")
.build();

final String responseBody = MAPPER.encodeToString(IdResResponse.of(List.of(expectedEid)));
Expand All @@ -315,7 +317,7 @@ public void callShouldCreateUserAndUseRequestedEidsWhenUserIsAbsent() {
.extracting(AuctionRequestPayload::bidRequest)
.extracting(BidRequest::getUser)
.extracting(User::getEids)
.isEqualTo(List.of(expectedEid));
.isEqualTo(List.of(expectedEid.toBuilder().inserter("s2s.liveintent.com").build()));

verify(httpClient).post(
eq("https://test.com/idres"),
Expand Down