Skip to content

Commit

Permalink
Add custom conversion ID patterns for Verifiable Advertiser Conversions
Browse files Browse the repository at this point in the history
To increase adoption of Verifiable Advertiser Conversions we provide a mechanism to extract a conversion ID from an advertiser's conversion site w/o the need to modify its DOM. To this end a regex pattern can be configured via the conversions resource to extract the ID from either the URL or the DOM. The default pattern has been made configurable via griffin.
  • Loading branch information
Moritz Haller committed Apr 26, 2021
1 parent 1a0d5c4 commit 978142a
Show file tree
Hide file tree
Showing 16 changed files with 641 additions and 37 deletions.
2 changes: 2 additions & 0 deletions components/brave_ads/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ source_set("brave_ads_unit_tests") {
"//brave/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/features/anti_targeting/anti_targeting_features_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/features/bandits/epsilon_greedy_bandit_features_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/features/conversions/conversions_features_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/features/purchase_intent/purchase_intent_features_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/features/text_classification/text_classification_features_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/features/user_activity/user_activity_features_unittest.cc",
Expand Down Expand Up @@ -128,6 +129,7 @@ source_set("brave_ads_unit_tests") {
"//brave/vendor/bat-native-ads/src/bat/ads/internal/resources/behavioral/bandits/epsilon_greedy_bandit_resource_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/resources/behavioral/purchase_intent/purchase_intent_resource_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/resources/contextual/text_classification/text_classification_resource_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/resources/conversions/conversions_resource_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/resources/frequency_capping/anti_targeting_resource_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/security/conversions/conversions_util_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/security/crypto_util_unittest.cc",
Expand Down
6 changes: 6 additions & 0 deletions vendor/bat-native-ads/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,8 @@ source_set("ads") {
"src/bat/ads/internal/features/anti_targeting/anti_targeting_features.h",
"src/bat/ads/internal/features/bandits/epsilon_greedy_bandit_features.cc",
"src/bat/ads/internal/features/bandits/epsilon_greedy_bandit_features.h",
"src/bat/ads/internal/features/conversions/conversions_features.cc",
"src/bat/ads/internal/features/conversions/conversions_features.h",
"src/bat/ads/internal/features/features.cc",
"src/bat/ads/internal/features/features.h",
"src/bat/ads/internal/features/features_util.cc",
Expand Down Expand Up @@ -552,6 +554,10 @@ source_set("ads") {
"src/bat/ads/internal/resources/behavioral/purchase_intent/purchase_intent_resource.h",
"src/bat/ads/internal/resources/contextual/text_classification/text_classification_resource.cc",
"src/bat/ads/internal/resources/contextual/text_classification/text_classification_resource.h",
"src/bat/ads/internal/resources/conversions/conversion_id_pattern_info.cc",
"src/bat/ads/internal/resources/conversions/conversion_id_pattern_info.h",
"src/bat/ads/internal/resources/conversions/conversions_resource.cc",
"src/bat/ads/internal/resources/conversions/conversions_resource.h",
"src/bat/ads/internal/resources/country_components.h",
"src/bat/ads/internal/resources/frequency_capping/anti_targeting_info.cc",
"src/bat/ads/internal/resources/frequency_capping/anti_targeting_info.h",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"locale": "us",
"version": 1,
"timestamp": "2021-04-26 09:00:00",
"conversion_id_patterns": {
"https://brave.com/foobar": {
"id_pattern": "<div.*id=\"conversion-id\".*>(.*)<\/div>",
"search_in": "html"
},
"https://brave.com/foobar?conversion_id=*": {
"id_pattern": "conversion_id\\=(.*)",
"search_in": "url"
}
}
}
8 changes: 7 additions & 1 deletion vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "bat/ads/internal/resources/behavioral/bandits/epsilon_greedy_bandit_resource.h"
#include "bat/ads/internal/resources/behavioral/purchase_intent/purchase_intent_resource.h"
#include "bat/ads/internal/resources/contextual/text_classification/text_classification_resource.h"
#include "bat/ads/internal/resources/conversions/conversions_resource.h"
#include "bat/ads/internal/resources/country_components.h"
#include "bat/ads/internal/resources/frequency_capping/anti_targeting_resource.h"
#include "bat/ads/internal/resources/language_components.h"
Expand Down Expand Up @@ -126,6 +127,7 @@ void AdsImpl::ChangeLocale(const std::string& locale) {
text_classification_resource_->Load();
purchase_intent_resource_->Load();
anti_targeting_resource_->Load();
conversions_resource_->Load();
}

void AdsImpl::OnAdsSubdivisionTargetingCodeHasChanged() {
Expand All @@ -150,7 +152,8 @@ void AdsImpl::OnHtmlLoaded(const int32_t tab_id,

const std::string original_url = redirect_chain.front();
ad_transfer_->MaybeTransferAd(tab_id, original_url);
conversions_->MaybeConvert(redirect_chain, html);
conversions_->MaybeConvert(redirect_chain, html,
conversions_resource_->get());
}

void AdsImpl::OnTextLoaded(const int32_t tab_id,
Expand Down Expand Up @@ -274,6 +277,7 @@ void AdsImpl::OnResourceComponentUpdated(const std::string& id) {
} else if (kComponentCountryIds.find(id) != kComponentCountryIds.end()) {
purchase_intent_resource_->Load();
anti_targeting_resource_->Load();
conversions_resource_->Load();
} else {
BLOG(0, "Unknown resource for " << id);
}
Expand Down Expand Up @@ -424,6 +428,8 @@ void AdsImpl::set(privacy::TokenGeneratorInterface* token_generator) {

anti_targeting_resource_ = std::make_unique<resource::AntiTargeting>();

conversions_resource_ = std::make_unique<resource::Conversions>();

ad_targeting_ = std::make_unique<AdTargeting>();
subdivision_targeting_ =
std::make_unique<ad_targeting::geographic::SubdivisionTargeting>();
Expand Down
2 changes: 2 additions & 0 deletions vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class SubdivisionTargeting;

namespace resource {
class AntiTargeting;
class Conversions;
class EpsilonGreedyBandit;
class PurchaseIntent;
class TextClassification;
Expand Down Expand Up @@ -202,6 +203,7 @@ class AdsImpl : public Ads,
std::unique_ptr<ad_targeting::processor::PurchaseIntent>
purchase_intent_processor_;
std::unique_ptr<resource::AntiTargeting> anti_targeting_resource_;
std::unique_ptr<resource::Conversions> conversions_resource_;
std::unique_ptr<ad_targeting::geographic::SubdivisionTargeting>
subdivision_targeting_;
std::unique_ptr<AdTargeting> ad_targeting_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "bat/ads/internal/database/tables/ad_events_database_table.h"
#include "bat/ads/internal/database/tables/conversion_queue_database_table.h"
#include "bat/ads/internal/database/tables/conversions_database_table.h"
#include "bat/ads/internal/features/conversions/conversions_features.h"
#include "bat/ads/internal/logging.h"
#include "bat/ads/internal/time_formatting_util.h"
#include "bat/ads/internal/url_util.h"
Expand All @@ -34,8 +35,8 @@ namespace {
const int64_t kConvertAfterSeconds =
base::Time::kHoursPerDay * base::Time::kSecondsPerHour;
const int64_t kDebugConvertAfterSeconds = 10 * base::Time::kSecondsPerMinute;

const int64_t kExpiredConvertAfterSeconds = 1 * base::Time::kSecondsPerMinute;
const char kSearchInUrl[] = "url";

bool HasObservationWindowForAdEventExpired(const int observation_window,
const AdEventInfo& ad_event) {
Expand Down Expand Up @@ -83,14 +84,41 @@ bool DoesConfirmationTypeMatchConversionType(
}
}

std::string ExtractVerifiableConversionIdFromHtml(const std::string& html) {
re2::StringPiece text_string_piece(html);
RE2 r("<meta.*name=\"ad-conversion-id\".*content=\"(.*)\".*>");
std::string ExtractConversionIdFromText(
const std::string& html,
const std::vector<std::string>& redirect_chain,
const std::string& conversion_url_pattern,
const ConversionIdPatternMap& conversion_id_patterns) {
std::string conversion_id;
std::string conversion_id_pattern =
features::GetGetDefaultConversionIdPattern();
std::string text = html;

const auto iter = conversion_id_patterns.find(conversion_url_pattern);
if (iter != conversion_id_patterns.end()) {
const ConversionIdPatternInfo conversion_id_pattern_info = iter->second;
if (conversion_id_pattern_info.search_in == kSearchInUrl) {
const auto url_iter = std::find_if(
redirect_chain.begin(), redirect_chain.end(),
[=](const std::string& url) {
return DoesUrlMatchPattern(url, conversion_url_pattern);
});

if (url_iter == redirect_chain.end()) {
return conversion_id;
}

text = *url_iter;
}

conversion_id_pattern = conversion_id_pattern_info.id_pattern;
}

std::string verifiable_conversion_id;
RE2::FindAndConsume(&text_string_piece, r, &verifiable_conversion_id);
re2::StringPiece text_string_piece(text);
RE2 r(conversion_id_pattern);
RE2::FindAndConsume(&text_string_piece, r, &conversion_id);

return verifiable_conversion_id;
return conversion_id;
}

std::set<std::string> GetConvertedCreativeSets(const AdEventList& ad_events) {
Expand Down Expand Up @@ -155,8 +183,10 @@ void Conversions::RemoveObserver(ConversionsObserver* observer) {
observers_.RemoveObserver(observer);
}

void Conversions::MaybeConvert(const std::vector<std::string>& redirect_chain,
const std::string& html) {
void Conversions::MaybeConvert(
const std::vector<std::string>& redirect_chain,
const std::string& html,
const ConversionIdPatternMap& conversion_id_patterns) {
if (!ShouldAllow()) {
BLOG(1, "Conversions are not allowed");
return;
Expand All @@ -168,7 +198,7 @@ void Conversions::MaybeConvert(const std::vector<std::string>& redirect_chain,
return;
}

CheckRedirectChain(redirect_chain, html);
CheckRedirectChain(redirect_chain, html, conversion_id_patterns);
}

void Conversions::StartTimerIfReady() {
Expand Down Expand Up @@ -202,7 +232,8 @@ bool Conversions::ShouldAllow() const {

void Conversions::CheckRedirectChain(
const std::vector<std::string>& redirect_chain,
const std::string& html) {
const std::string& html,
const ConversionIdPatternMap& conversion_id_patterns) {
BLOG(1, "Checking URL for conversions");

database::table::AdEvents ad_events_database_table;
Expand Down Expand Up @@ -254,8 +285,9 @@ void Conversions::CheckRedirectChain(
creative_set_ids.insert(ad_event.creative_set_id);

VerifiableConversionInfo verifiable_conversion;
verifiable_conversion.id =
ExtractVerifiableConversionIdFromHtml(html);
verifiable_conversion.id = ExtractConversionIdFromText(
html, redirect_chain, conversion.url_pattern,
conversion_id_patterns);
verifiable_conversion.public_key = conversion.advertiser_public_key;

Convert(ad_event, verifiable_conversion);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "bat/ads/internal/conversions/conversion_queue_item_info.h"
#include "bat/ads/internal/conversions/conversions_observer.h"
#include "bat/ads/internal/conversions/verifiable_conversion_info.h"
#include "bat/ads/internal/resources/conversions/conversion_id_pattern_info.h"
#include "bat/ads/internal/security/conversions/verifiable_conversion_envelope_info.h"
#include "bat/ads/internal/timer.h"

Expand All @@ -34,7 +35,8 @@ class Conversions {
bool ShouldAllow() const;

void MaybeConvert(const std::vector<std::string>& redirect_chain,
const std::string& html);
const std::string& html,
const ConversionIdPatternMap& conversion_id_patterns);

void StartTimerIfReady();

Expand All @@ -44,7 +46,8 @@ class Conversions {
Timer timer_;

void CheckRedirectChain(const std::vector<std::string>& redirect_chain,
const std::string& html);
const std::string& html,
const ConversionIdPatternMap& conversion_id_patterns);

void Convert(const AdEventInfo& ad_event,
const VerifiableConversionInfo& verifiable_conversion);
Expand Down
Loading

0 comments on commit 978142a

Please sign in to comment.