From 312e7b6df6f88afa66a3741dda4ad7940d2a051b Mon Sep 17 00:00:00 2001 From: Josh Radcliff Date: Wed, 24 Jun 2026 15:43:46 -0400 Subject: [PATCH 1/2] feat(sample): use CompositeData with IP for audiences Also fixes the version specifier in samples/composer.json to get the latest version of googleads/data-manager with major version `0`. Change-Id: I160e558ebe82b4c93442ae8987160866ba006cea --- samples/audiences/ingest_audience_members.php | 69 +++++++++++++++++-- samples/composer.json | 2 +- samples/sampledata/audience_members_1.json | 15 ++++ 3 files changed, 81 insertions(+), 5 deletions(-) diff --git a/samples/audiences/ingest_audience_members.php b/samples/audiences/ingest_audience_members.php index 3604630..863dd4e 100644 --- a/samples/audiences/ingest_audience_members.php +++ b/samples/audiences/ingest_audience_members.php @@ -21,11 +21,13 @@ use Google\Ads\DataManager\V1\AudienceMember; use Google\Ads\DataManager\V1\Client\IngestionServiceClient; +use Google\Ads\DataManager\V1\CompositeData; use Google\Ads\DataManager\V1\Consent; use Google\Ads\DataManager\V1\ConsentStatus; use Google\Ads\DataManager\V1\Destination; use Google\Ads\DataManager\V1\Encoding as DataManagerEncoding; use Google\Ads\DataManager\V1\IngestAudienceMembersRequest; +use Google\Ads\DataManager\V1\IpData; use Google\Ads\DataManager\V1\ProductAccount; use Google\Ads\DataManager\V1\ProductAccount\AccountType; use Google\Ads\DataManager\V1\TermsOfService; @@ -35,6 +37,7 @@ use Google\Ads\DataManagerUtil\Encoding; use Google\Ads\DataManagerUtil\Formatter; use Google\ApiCore\ApiException; +use Google\Protobuf\Timestamp; /** * Reads the JSON member data file. @@ -120,11 +123,69 @@ function main( } } - if (!empty($identifiers)) { - $userData = new UserData()->setUserIdentifiers($identifiers); + // Adds IP address information for each valid entry for the member. + $ipDatas = []; + $ipInfos = $memberRow['ipInfos'] ?? []; + foreach ($ipInfos as $ipInfo) { + if ($operatingAccountType !== AccountType::GOOGLE_ADS) { + error_log(sprintf( + 'Skipping IP address information for operating account type %s. ' + . 'Sending IP address is only supported for operating account type GOOGLE_ADS.', + AccountType::name($operatingAccountType) + )); + } + + // Trims leading and trailing whitespace from the IP address. + $ipAddress = trim($ipInfo['ipAddress'] ?? ''); + if (empty($ipAddress)) { + // Skips the IP information from the input file since it is missing IP address, which is + // required. + error_log('Skipping IP address information with no IP address'); + continue; + } + + // Creates an IpData message and sets its IP address. + $ipData = (new IpData())->setIpAddress($ipAddress); + + // Adds observe start time to the IpData if present and in the expected timestamp format. + $startTimeStr = trim($ipInfo['observeStartTime'] ?? ''); + if (!empty($startTimeStr)) { + try { + $startTime = new Timestamp(); + $startTime->fromDateTime(new \DateTime($startTimeStr)); + $ipData->setObserveStartTime($startTime); + } catch (\Exception $e) { + error_log(sprintf("Ignoring observe start time '%s' since it can't be parsed", $startTimeStr)); + } + } + + // Adds observe end time to the IpData if present and in the expected timestamp format. + $endTimeStr = trim($ipInfo['observeEndTime'] ?? ''); + if (!empty($endTimeStr)) { + try { + $endTime = new Timestamp(); + $endTime->fromDateTime(new \DateTime($endTimeStr)); + $ipData->setObserveEndTime($endTime); + } catch (\Exception $e) { + error_log(sprintf("Ignoring observe end time '%s' since it can't be parsed", $endTimeStr)); + } + } + + $ipDatas[] = $ipData; + } + + if (!empty($identifiers) || !empty($ipDatas)) { + $compositeData = new CompositeData(); + if (!empty($identifiers)) { + $userData = (new UserData())->setUserIdentifiers($identifiers); + $compositeData->setUserData($userData); + } + if (!empty($ipDatas)) { + $compositeData->setIpData($ipDatas); + } - // Adds an AudienceMember with the formatted and hashed identifiers. - $audienceMember = (new AudienceMember())->setUserData($userData); + // Adds an AudienceMember with the CompositeData. + $audienceMember = (new AudienceMember())->setCompositeData($compositeData); $audienceMembers[] = $audienceMember; } } diff --git a/samples/composer.json b/samples/composer.json index 71a1fd7..66c7207 100644 --- a/samples/composer.json +++ b/samples/composer.json @@ -13,7 +13,7 @@ ], "require": { "php": ">=8.1", - "googleads/data-manager": "^0.1.0", + "googleads/data-manager": "^0", "googleads/data-manager-util": "@dev" }, "require-dev": { diff --git a/samples/sampledata/audience_members_1.json b/samples/sampledata/audience_members_1.json index f40064d..128e0f9 100644 --- a/samples/sampledata/audience_members_1.json +++ b/samples/sampledata/audience_members_1.json @@ -3,6 +3,14 @@ "emails": [ "dana@example.com", "DanaM@example.com" + ], + "ipInfos": [ + { + "ipAddress": "192.0.2.211" + }, + { + "ipAddress": "198.51.100.14" + } ] }, { @@ -21,6 +29,13 @@ "emails": [ "quinn@CYMBALGROUP.com", "baklavainthebalkans@gmail.com" + ], + "ipInfos": [ + { + "ipAddress": "203.0.113.98", + "observeStartTime": "2026-06-10T20:17:52.0-04:00", + "observeEndTime": "2026-06-17T04:02:04.123-04:00" + } ] }, { From 7bf29945eeb88b7d37d46b859e4a4f1a44e7bf7f Mon Sep 17 00:00:00 2001 From: Josh Radcliff Date: Thu, 25 Jun 2026 16:10:57 -0400 Subject: [PATCH 2/2] add missing "continue" Change-Id: I9d5bb7dc13abcc239a814205b840b5b8df72fc81 --- samples/audiences/ingest_audience_members.php | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/audiences/ingest_audience_members.php b/samples/audiences/ingest_audience_members.php index 863dd4e..8d31c63 100644 --- a/samples/audiences/ingest_audience_members.php +++ b/samples/audiences/ingest_audience_members.php @@ -133,6 +133,7 @@ function main( . 'Sending IP address is only supported for operating account type GOOGLE_ADS.', AccountType::name($operatingAccountType) )); + continue; } // Trims leading and trailing whitespace from the IP address.